Skip to content
27 changes: 26 additions & 1 deletion apiserver/plane/app/views/issue/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,9 +944,33 @@ class IssueDetailEndpoint(BaseAPIView):
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST])
def get(self, request, slug, project_id):
filters = issue_filters(request.query_params, "GET")

# check for the project member role, if the role is 5 then check for the guest_view_all_features
# if it is true then show all the issues else show only the issues created by the user
project_member_subquery = ProjectMember.objects.filter(
project_id=OuterRef("project_id"),
member=self.request.user,
is_active=True,
).filter(
Q(role__gt=ROLE.GUEST.value)
| Q(
role=ROLE.GUEST.value, project__guest_view_all_features=True
)
)

# Main issue query
issue = (
Issue.issue_objects.filter(workspace__slug=slug, project_id=project_id)
.select_related("workspace", "project", "state", "parent")
.filter(
Q(Exists(project_member_subquery))
| Q(
project__project_projectmember__member=self.request.user,
project__project_projectmember__is_active=True,
project__project_projectmember__role=ROLE.GUEST.value,
project__guest_view_all_features=False,
created_by=self.request.user,
)
)
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(
cycle_id=Subquery(
Expand Down Expand Up @@ -1014,6 +1038,7 @@ def get(self, request, slug, project_id):
.values("count")
)
)

issue = issue.filter(**filters)
order_by_param = request.GET.get("order_by", "-created_at")
# Issue queryset
Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/layout/gantt.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface IGanttBlock {
sort_order: number | undefined;
start_date: string | undefined;
target_date: string | undefined;
project_id: string | undefined;
}

export interface IBlockUpdateData {
Expand All @@ -25,6 +26,7 @@ export interface IBlockUpdateDependencyData {
id: string;
start_date?: string;
target_date?: string;
project_id?: string;
}

export type TGanttViews = "week" | "month" | "quarter";
Expand Down
3 changes: 2 additions & 1 deletion packages/utils/src/work-item/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export const getIssueBlocksStructure = (block: TIssue): IGanttBlock => ({
sort_order: block?.sort_order,
start_date: block?.start_date ?? undefined,
target_date: block?.target_date ?? undefined,
project_id: block?.project_id ?? undefined,
});

export const formatTextList = (TextArray: string[]): string => {
Expand Down Expand Up @@ -260,7 +261,7 @@ export const getComputedDisplayFilters = (
displayFilters: IIssueDisplayFilterOptions = {},
defaultValues?: IIssueDisplayFilterOptions
): IIssueDisplayFilterOptions => {
const filters = displayFilters || defaultValues;
const filters = !isEmpty(displayFilters) ? displayFilters : defaultValues;

return {
calendar: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import { useCallback, useState } from "react";
import { useCallback, useMemo, useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Layers } from "lucide-react";
// plane constants
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
import { EIssueFilterType, EIssueLayoutTypes, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// types
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
Expand All @@ -19,6 +19,7 @@ import { CreateUpdateWorkspaceViewModal } from "@/components/workspace";
// helpers
// hooks
import { useLabel, useMember, useIssues, useGlobalView } from "@/hooks/store";
import { GlobalViewLayoutSelection } from "@/plane-web/components/views/helper";

export const GlobalIssuesHeader = observer(() => {
// states
Expand All @@ -38,6 +39,7 @@ export const GlobalIssuesHeader = observer(() => {

const issueFilters = globalViewId ? filters[globalViewId.toString()] : undefined;

const activeLayout = issueFilters?.displayFilters?.layout;
const viewDetails = getViewDetailsById(globalViewId.toString());

const handleFiltersUpdate = useCallback(
Expand Down Expand Up @@ -95,8 +97,27 @@ export const GlobalIssuesHeader = observer(() => {
[workspaceSlug, updateFilters, globalViewId]
);

const handleLayoutChange = useCallback(
(layout: EIssueLayoutTypes) => {
if (!workspaceSlug || !globalViewId) return;
updateFilters(
workspaceSlug.toString(),
undefined,
EIssueFilterType.DISPLAY_FILTERS,
{ layout: layout },
globalViewId.toString()
);
},
[workspaceSlug, updateFilters, globalViewId]
);

const isLocked = viewDetails?.is_locked;

const currentLayoutFilters = useMemo(() => {
const layout = activeLayout ?? EIssueLayoutTypes.SPREADSHEET;
return ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues[layout];
}, [activeLayout]);

return (
<>
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
Expand All @@ -113,13 +134,18 @@ export const GlobalIssuesHeader = observer(() => {
<Header.RightItem>
{!isLocked ? (
<>
<GlobalViewLayoutSelection
onChange={handleLayoutChange}
selectedLayout={activeLayout ?? EIssueLayoutTypes.SPREADSHEET}
workspaceSlug={workspaceSlug.toString()}
/>
<FiltersDropdown
title={t("common.filters")}
placement="bottom-end"
isFiltersApplied={isIssueFilterActive(issueFilters)}
>
<FilterSelection
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues.spreadsheet}
layoutDisplayFiltersOptions={currentLayoutFilters}
filters={issueFilters?.filters ?? {}}
handleFiltersUpdate={handleFiltersUpdate}
displayFilters={issueFilters?.displayFilters ?? {}}
Expand All @@ -130,7 +156,7 @@ export const GlobalIssuesHeader = observer(() => {
</FiltersDropdown>
<FiltersDropdown title={t("common.display")} placement="bottom-end">
<DisplayFiltersSelection
layoutDisplayFiltersOptions={ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues.spreadsheet}
layoutDisplayFiltersOptions={currentLayoutFilters}
displayFilters={issueFilters?.displayFilters ?? {}}
handleDisplayFiltersUpdate={handleDisplayFilters}
displayProperties={issueFilters?.displayProperties ?? {}}
Expand Down
12 changes: 12 additions & 0 deletions web/ce/components/views/helper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EIssueLayoutTypes } from "@plane/constants";
import { TWorkspaceLayoutProps } from "@/components/views/helper";

export type TLayoutSelectionProps = {
onChange: (layout: EIssueLayoutTypes) => void;
selectedLayout: EIssueLayoutTypes;
workspaceSlug: string;
};

export const GlobalViewLayoutSelection = (props: TLayoutSelectionProps) => <></>;

export const WorkspaceAdditionalLayouts = (props: TWorkspaceLayoutProps) => <></>;
1 change: 1 addition & 0 deletions web/ce/store/issue/workspace/issue.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "@/store/issue/workspace/issue.store";
2 changes: 2 additions & 0 deletions web/ce/store/timeline/base-timeline.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type BlockData = {
sort_order: number | null;
start_date?: string | undefined | null;
target_date?: string | undefined | null;
project_id?: string | undefined | null;
};

export interface IBaseTimelineStore {
Expand Down Expand Up @@ -194,6 +195,7 @@ export class BaseTimeLineStore implements IBaseTimelineStore {
sort_order: blockData?.sort_order ?? undefined,
start_date: blockData?.start_date ?? undefined,
target_date: blockData?.target_date ?? undefined,
project_id: blockData?.project_id ?? undefined,
};
if (this.currentViewData && (this.currentViewData?.data?.startDate || this.currentViewData?.data?.dayWidth)) {
block.position = getItemPositionWidth(this.currentViewData, block);
Expand Down
3 changes: 3 additions & 0 deletions web/core/components/gantt-chart/blocks/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Props = {
enableBlockLeftResize: boolean;
enableBlockRightResize: boolean;
enableBlockMove: boolean;
enableDependency: boolean;
ganttContainerRef: RefObject<HTMLDivElement>;
updateBlockDates?: (updates: IBlockUpdateDependencyData[]) => Promise<void>;
};
Expand All @@ -33,6 +34,7 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
enableBlockRightResize,
enableBlockMove,
ganttContainerRef,
enableDependency,
updateBlockDates,
} = props;
// store hooks
Expand Down Expand Up @@ -90,6 +92,7 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove && !!isBlockComplete}
enableDependency={enableDependency}
isMoving={isMoving}
ganttContainerRef={ganttContainerRef}
/>
Expand Down
3 changes: 3 additions & 0 deletions web/core/components/gantt-chart/blocks/blocks-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type GanttChartBlocksProps = {
ganttContainerRef: React.RefObject<HTMLDivElement>;
showAllBlocks: boolean;
updateBlockDates?: (updates: IBlockUpdateDependencyData[]) => Promise<void>;
enableDependency: boolean | ((blockId: string) => boolean);
};

export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
Expand All @@ -24,6 +25,7 @@ export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
ganttContainerRef,
showAllBlocks,
updateBlockDates,
enableDependency,
} = props;

return (
Expand All @@ -41,6 +43,7 @@ export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
typeof enableBlockRightResize === "function" ? enableBlockRightResize(blockId) : enableBlockRightResize
}
enableBlockMove={typeof enableBlockMove === "function" ? enableBlockMove(blockId) : enableBlockMove}
enableDependency={typeof enableDependency === "function" ? enableDependency(blockId) : enableDependency}
ganttContainerRef={ganttContainerRef}
updateBlockDates={updateBlockDates}
/>
Expand Down
3 changes: 3 additions & 0 deletions web/core/components/gantt-chart/chart/main-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Props = {
enableReorder: boolean | ((blockId: string) => boolean);
enableSelection: boolean | ((blockId: string) => boolean);
enableAddBlock: boolean | ((blockId: string) => boolean);
enableDependency: boolean | ((blockId: string) => boolean);
itemsContainerWidth: number;
showAllBlocks: boolean;
sidebarToRender: (props: any) => React.ReactNode;
Expand All @@ -67,6 +68,7 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
enableReorder,
enableAddBlock,
enableSelection,
enableDependency,
itemsContainerWidth,
showAllBlocks,
sidebarToRender,
Expand Down Expand Up @@ -215,6 +217,7 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
ganttContainerRef={ganttContainerRef}
enableDependency={enableDependency}
showAllBlocks={showAllBlocks}
updateBlockDates={updateBlockDates}
/>
Expand Down
3 changes: 3 additions & 0 deletions web/core/components/gantt-chart/chart/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type ChartViewRootProps = {
enableReorder: boolean | ((blockId: string) => boolean);
enableAddBlock: boolean | ((blockId: string) => boolean);
enableSelection: boolean | ((blockId: string) => boolean);
enableDependency: boolean | ((blockId: string) => boolean);
bottomSpacing: boolean;
showAllBlocks: boolean;
loadMoreBlocks?: () => void;
Expand Down Expand Up @@ -70,6 +71,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => {
enableReorder,
enableAddBlock,
enableSelection,
enableDependency,
bottomSpacing,
showAllBlocks,
quickAdd,
Expand Down Expand Up @@ -204,6 +206,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => {
enableReorder={enableReorder}
enableSelection={enableSelection}
enableAddBlock={enableAddBlock}
enableDependency={enableDependency}
itemsContainerWidth={itemsContainerWidth}
showAllBlocks={showAllBlocks}
sidebarToRender={sidebarToRender}
Expand Down
10 changes: 8 additions & 2 deletions web/core/components/gantt-chart/helpers/draggable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Props = {
enableBlockLeftResize: boolean;
enableBlockRightResize: boolean;
enableBlockMove: boolean;
enableDependency: boolean | ((blockId: string) => boolean);
ganttContainerRef: RefObject<HTMLDivElement>;
};

Expand All @@ -29,14 +30,17 @@ export const ChartDraggable: React.FC<Props> = observer((props) => {
enableBlockLeftResize,
enableBlockRightResize,
enableBlockMove,
enableDependency,
isMoving,
ganttContainerRef,
} = props;

return (
<div className="group w-full z-[5] relative inline-flex h-full cursor-pointer items-center font-medium transition-all">
{/* left resize drag handle */}
<LeftDependencyDraggable block={block} ganttContainerRef={ganttContainerRef} />
{(typeof enableDependency === "function" ? enableDependency(block.id) : enableDependency) && (
<LeftDependencyDraggable block={block} ganttContainerRef={ganttContainerRef} />
)}
<LeftResizable
enableBlockLeftResize={enableBlockLeftResize}
handleBlockDrag={handleBlockDrag}
Expand All @@ -58,7 +62,9 @@ export const ChartDraggable: React.FC<Props> = observer((props) => {
isMoving={isMoving}
position={block.position}
/>
<RightDependencyDraggable block={block} ganttContainerRef={ganttContainerRef} />
{(typeof enableDependency === "function" ? enableDependency(block.id) : enableDependency) && (
<RightDependencyDraggable block={block} ganttContainerRef={ganttContainerRef} />
)}
</div>
);
});
3 changes: 3 additions & 0 deletions web/core/components/gantt-chart/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type GanttChartRootProps = {
enableReorder?: boolean | ((blockId: string) => boolean);
enableAddBlock?: boolean | ((blockId: string) => boolean);
enableSelection?: boolean | ((blockId: string) => boolean);
enableDependency?: boolean | ((blockId: string) => boolean);
bottomSpacing?: boolean;
showAllBlocks?: boolean;
showToday?: boolean;
Expand All @@ -47,6 +48,7 @@ export const GanttChartRoot: FC<GanttChartRootProps> = observer((props) => {
enableReorder = false,
enableAddBlock = false,
enableSelection = false,
enableDependency = false,
bottomSpacing = false,
showAllBlocks = false,
showToday = true,
Expand Down Expand Up @@ -79,6 +81,7 @@ export const GanttChartRoot: FC<GanttChartRootProps> = observer((props) => {
enableReorder={enableReorder}
enableAddBlock={enableAddBlock}
enableSelection={enableSelection}
enableDependency={enableDependency}
bottomSpacing={bottomSpacing}
showAllBlocks={showAllBlocks}
quickAdd={quickAdd}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
target_date?: string;
}[]
) =>
issues.updateIssueDates(workspaceSlug.toString(), projectId.toString(), updates).catch(() => {
issues.updateIssueDates(workspaceSlug.toString(), updates, projectId.toString()).catch(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: t("toast.error"),
message: "Error while updating work item dates, Please try again Later",
});
}),
[issues]
[issues, projectId, workspaceSlug]
);

const quickAdd =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
}
}, [isOpen, isMobile]);

if (!value) return null;

let projectLabels: IIssueLabel[] = defaultOptions as IIssueLabel[];
if (storeLabels && storeLabels.length > 0) projectLabels = storeLabels;

Expand Down
Loading