From a5fd6f0e8a487d6d7ce31187efa9fd0c06c2128f Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 13 Feb 2024 18:41:34 +0530 Subject: [PATCH] chore: store changes on the filters and display filters --- packages/types/src/view/filter.d.ts | 18 +- web/components/headers/project-issues.tsx | 13 +- .../display-filter-item-root.tsx | 72 ++++++ .../display-filters/display-filter-item.tsx | 27 +++ .../display-filter-selection.tsx | 38 +++ .../view/display-filters/dropdown.tsx | 30 +-- web/components/view/display-filters/root.tsx | 96 +++++++- web/components/view/filters/dropdown.tsx | 4 + web/components/view/filters/edit-dropdown.tsx | 16 +- web/components/view/filters/root.tsx | 21 +- web/components/view/index.ts | 3 + web/components/view/layout.tsx | 50 ++-- web/components/view/root.tsx | 46 ++-- .../view/views/create-edit-form.tsx | 6 +- web/components/view/views/edit-dropdown.tsx | 86 +++---- web/constants/issue.ts | 2 +- web/constants/view/filters.ts | 222 ++++++++++-------- web/hooks/store/views/use-view-filters.tsx | 83 ++++++- .../[projectId]/views/private/[viewId].tsx | 3 +- .../[projectId]/views/private/index.tsx | 37 +-- .../[projectId]/views/public/[viewId].tsx | 3 +- .../views/private/[viewId].tsx | 3 +- .../[workspaceSlug]/views/public/[viewId].tsx | 3 +- web/store/view/helpers/filters_helpers.ts | 33 ++- web/store/view/root.store.ts | 14 +- web/store/view/view-root.store.ts | 51 +++- web/store/view/view.store.ts | 35 ++- 27 files changed, 717 insertions(+), 298 deletions(-) create mode 100644 web/components/view/display-filters/display-filter-item-root.tsx create mode 100644 web/components/view/display-filters/display-filter-item.tsx create mode 100644 web/components/view/display-filters/display-filter-selection.tsx diff --git a/packages/types/src/view/filter.d.ts b/packages/types/src/view/filter.d.ts index c7da2cd65..2fd11b5d4 100644 --- a/packages/types/src/view/filter.d.ts +++ b/packages/types/src/view/filter.d.ts @@ -1,9 +1,17 @@ +declare enum EViewLayouts { + LIST = "list", + KANBAN = "kanban", + CALENDAR = "calendar", + SPREADSHEET = "spreadsheet", + GANTT = "gantt", +} + export type TViewLayouts = - | "list" - | "kanban" - | "calendar" - | "spreadsheet" - | "gantt"; + | EViewLayouts.LIST + | EViewLayouts.KANBAN + | EViewLayouts.CALENDAR + | EViewLayouts.SPREADSHEET + | EViewLayouts.GANTT; export type TViewDisplayFiltersGrouped = | "project" diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 5c44a84d6..593fa77b5 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -154,7 +154,9 @@ export const ProjectIssuesHeader: React.FC = observer(() => { } />} + link={ + } /> + } /> @@ -203,7 +205,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => { {currentProjectDetails?.inbox_view && inboxDetails && ( - + + ) + )} + + ); +}); diff --git a/web/components/view/display-filters/display-filter-item.tsx b/web/components/view/display-filters/display-filter-item.tsx new file mode 100644 index 000000000..f2523782c --- /dev/null +++ b/web/components/view/display-filters/display-filter-item.tsx @@ -0,0 +1,27 @@ +import { FC, Fragment } from "react"; +// hooks +import { useViewFilter } from "hooks/store"; +// types +import { TViewDisplayFilters } from "@plane/types"; + +type TViewDisplayFiltersItem = { + workspaceSlug: string; + projectId: string | undefined; + filterKey: keyof TViewDisplayFilters; + propertyId: string; +}; + +export const ViewDisplayFiltersItem: FC = (props) => { + const { workspaceSlug, projectId, filterKey, propertyId } = props; + // hooks + const viewFilterHelper = useViewFilter(workspaceSlug, projectId); + + const propertyDetail = viewFilterHelper?.displayPropertyDetails(filterKey, propertyId) || undefined; + + if (!propertyDetail) return <>; + return ( +
+ {propertyDetail?.label || propertyId} +
+ ); +}; diff --git a/web/components/view/display-filters/display-filter-selection.tsx b/web/components/view/display-filters/display-filter-selection.tsx new file mode 100644 index 000000000..9f31c1ae8 --- /dev/null +++ b/web/components/view/display-filters/display-filter-selection.tsx @@ -0,0 +1,38 @@ +import { FC } from "react"; +import { Check } from "lucide-react"; +import { observer } from "mobx-react-lite"; +// hooks +import { useViewDetail } from "hooks/store"; +// types +import { TViewDisplayFilters, TViewTypes } from "@plane/types"; + +type TViewDisplayFilterSelection = { + workspaceSlug: string; + projectId: string | undefined; + viewId: string; + viewType: TViewTypes; + filterKey: keyof TViewDisplayFilters; + propertyId: string; +}; + +export const ViewDisplayFilterSelection: FC = observer((props) => { + const { workspaceSlug, projectId, viewId, viewType, filterKey, propertyId } = props; + + const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); + + const propertyIds = viewDetailStore?.appliedFilters?.display_filters?.[filterKey] || undefined; + + const isSelected = propertyIds === propertyId || false; + + return ( +
+ {isSelected && } +
+ ); +}); diff --git a/web/components/view/display-filters/dropdown.tsx b/web/components/view/display-filters/dropdown.tsx index 1fca9fa59..3f32dc653 100644 --- a/web/components/view/display-filters/dropdown.tsx +++ b/web/components/view/display-filters/dropdown.tsx @@ -7,28 +7,34 @@ import { MonitorDot } from "lucide-react"; // hooks import useOutsideClickDetector from "hooks/use-outside-click-detector"; // components -import { ViewDisplayPropertiesRoot } from "../"; +import { ViewDisplayFiltersRoot } from "../"; // ui import { Tooltip } from "@plane/ui"; // types import { TViewTypes } from "@plane/types"; +// constants +import { EViewPageType } from "constants/view"; -type TViewDisplayFiltersDropdown = { +type NewType = { workspaceSlug: string; projectId: string | undefined; viewId: string; viewType: TViewTypes; + viewPageType: EViewPageType; children?: ReactNode; displayDropdownText?: boolean; dropdownPlacement?: Placement; }; +type TViewDisplayFiltersDropdown = NewType; + export const ViewDisplayFiltersDropdown: FC = observer((props) => { const { workspaceSlug, projectId, viewId, viewType, + viewPageType, children, displayDropdownText = true, dropdownPlacement = "bottom-start", @@ -110,18 +116,14 @@ export const ViewDisplayFiltersDropdown: FC = obser {...attributes.popper} className="my-1 w-72 p-2 space-y-2 rounded bg-custom-background-100 border-[0.5px] border-custom-border-300 shadow-custom-shadow-rg focus:outline-none" > -
-
-
Properties
- -
- -
Content
+
+
diff --git a/web/components/view/display-filters/root.tsx b/web/components/view/display-filters/root.tsx index 54e250273..39665bb63 100644 --- a/web/components/view/display-filters/root.tsx +++ b/web/components/view/display-filters/root.tsx @@ -1,17 +1,101 @@ -import { FC } from "react"; +import { FC, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { ChevronUp, ChevronDown } from "lucide-react"; +import filter from "lodash/filter"; +import concat from "lodash/concat"; +import uniq from "lodash/uniq"; +// hooks +import { useViewDetail } from "hooks/store"; +// components +import { ViewDisplayPropertiesRoot, ViewDisplayFiltersItemRoot } from "../"; +// types +import { TViewDisplayFilters, TViewTypes } from "@plane/types"; +// constants +import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view"; type TViewDisplayFiltersRoot = { workspaceSlug: string; projectId: string | undefined; viewId: string; + viewType: TViewTypes; + viewPageType: EViewPageType; }; -export const ViewDisplayFiltersRoot: FC = (props) => { - const { workspaceSlug, projectId, viewId } = props; +export const ViewDisplayFiltersRoot: FC = observer((props) => { + const { workspaceSlug, projectId, viewId, viewType, viewPageType } = props; + // hooks + const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); + // state + const [filterVisibility, setFilterVisibility] = useState<(Partial | "display_property")[]>( + [] + ); + const handleFilterVisibility = (key: keyof TViewDisplayFilters | "display_property") => { + setFilterVisibility((prevData = []) => { + if (prevData.includes(key)) return filter(prevData, (item) => item !== key); + return uniq(concat(prevData, [key])); + }); + }; + + const layout = viewDetailStore?.appliedFilters?.display_filters?.layout; + + const filtersProperties = layout + ? viewDefaultFilterParametersByViewTypeAndLayout(viewPageType, layout, "display_filters") + : []; return ( -
-
ViewDisplayFiltersRoot
+
+
+
+
Properties
+
handleFilterVisibility("display_property")} + > + {!filterVisibility.includes("display_property") ? : } +
+
+ {!filterVisibility.includes("display_property") && ( +
+ +
+ )} +
+ + {filtersProperties.map((filterKey) => ( +
+
+
+ {filterKey.replaceAll("_", " ")} +
+
handleFilterVisibility(filterKey)} + > + {!filterVisibility.includes(filterKey) ? : } +
+
+ {!filterVisibility.includes(filterKey) && ( + + )} +
+ ))} + + {/* extra options */} +
+
Show sub issues
+
Show Empty groups
+
); -}; +}); diff --git a/web/components/view/filters/dropdown.tsx b/web/components/view/filters/dropdown.tsx index d434ba438..677000bff 100644 --- a/web/components/view/filters/dropdown.tsx +++ b/web/components/view/filters/dropdown.tsx @@ -12,12 +12,14 @@ import { ViewFiltersRoot } from "../"; import { Tooltip } from "@plane/ui"; // types import { TViewTypes } from "@plane/types"; +import { EViewPageType } from "constants/view"; type TViewFiltersDropdown = { workspaceSlug: string; projectId: string | undefined; viewId: string; viewType: TViewTypes; + viewPageType: EViewPageType; children?: ReactNode; displayDropdownText?: boolean; dropdownPlacement?: Placement; @@ -29,6 +31,7 @@ export const ViewFiltersDropdown: FC = observer((props) => projectId, viewId, viewType, + viewPageType, children, displayDropdownText = true, dropdownPlacement = "bottom-start", @@ -130,6 +133,7 @@ export const ViewFiltersDropdown: FC = observer((props) => projectId={projectId} viewId={viewId} viewType={viewType} + viewPageType={viewPageType} dateCustomFilterToggle={dateCustomFilterToggle} setDateCustomFilterToggle={setDateCustomFilterToggle} /> diff --git a/web/components/view/filters/edit-dropdown.tsx b/web/components/view/filters/edit-dropdown.tsx index 703e2075c..5eb0b9ffc 100644 --- a/web/components/view/filters/edit-dropdown.tsx +++ b/web/components/view/filters/edit-dropdown.tsx @@ -50,14 +50,14 @@ export const ViewFiltersEditDropdown: FC = observer((p // dropdown options const dropdownOptions: TViewFilterEditDropdownOptions[] = useMemo( () => [ - // { - // icon: PhotoFilterIcon, - // key: "save_as_new", - // label: "Save as new view", - // onClick: () => { - // viewOperations.localViewCreateEdit(undefined, viewDetailStore?.filtersToUpdate); - // }, - // }, + { + icon: PhotoFilterIcon, + key: "save_as_new", + label: "Save as new view", + onClick: () => { + viewOperations.localViewCreateEdit(undefined, viewDetailStore?.filtersToUpdate); + }, + }, { icon: RotateCcw, key: "reset_changes", diff --git a/web/components/view/filters/root.tsx b/web/components/view/filters/root.tsx index 7f36ef86c..1a02da571 100644 --- a/web/components/view/filters/root.tsx +++ b/web/components/view/filters/root.tsx @@ -10,19 +10,28 @@ import { useViewDetail } from "hooks/store"; import { ViewFiltersItemRoot } from "../"; // types import { TViewFilters, TViewTypes } from "@plane/types"; -import { VIEW_DEFAULT_FILTER_PARAMETERS } from "constants/view"; +import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view"; type TViewFiltersRoot = { workspaceSlug: string; projectId: string | undefined; viewId: string; viewType: TViewTypes; + viewPageType: EViewPageType; dateCustomFilterToggle: string | undefined; setDateCustomFilterToggle: (value: string | undefined) => void; }; export const ViewFiltersRoot: FC = observer((props) => { - const { workspaceSlug, projectId, viewId, viewType, dateCustomFilterToggle, setDateCustomFilterToggle } = props; + const { + workspaceSlug, + projectId, + viewId, + viewType, + viewPageType, + dateCustomFilterToggle, + setDateCustomFilterToggle, + } = props; // hooks const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); // state @@ -34,9 +43,11 @@ export const ViewFiltersRoot: FC = observer((props) => { }); }; - const layout = viewDetailStore?.appliedFilters?.display_filters?.layout || "spreadsheet"; + const layout = viewDetailStore?.appliedFilters?.display_filters?.layout; - const filtersProperties = VIEW_DEFAULT_FILTER_PARAMETERS?.["all"]?.["spreadsheet"]?.filters || []; + const filtersProperties = layout + ? viewDefaultFilterParametersByViewTypeAndLayout(viewPageType, layout, "filters") + : []; if (!layout || filtersProperties.length <= 0) return <>; return ( @@ -45,7 +56,7 @@ export const ViewFiltersRoot: FC = observer((props) => {
- {filterKey.replace("_", " ")} + {filterKey.replaceAll("_", " ")}
= observer((props) => { - const { workspaceSlug, projectId, viewId, viewType } = props; + const { workspaceSlug, projectId, viewId, viewType, viewPageType } = props; // hooks const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); - if (!viewDetailStore) return <>; + const validLayouts = viewPageDefaultLayoutsByPageType(viewPageType); + + if (!viewDetailStore || validLayouts.length <= 1) return <>; return (
- {LAYOUTS_DATA.map((layout) => ( - - -
{ + if (!validLayouts.includes(layout.key)) return ; + return ( + + +
viewDetailStore.setDisplayFilters({ layout: layout.key })} - > - -
-
-
- ))} + onClick={() => viewDetailStore.setDisplayFilters({ layout: layout.key })} + > + +
+
+
+ ); + })}
); }); diff --git a/web/components/view/root.tsx b/web/components/view/root.tsx index 2a4631591..00aefe265 100644 --- a/web/components/view/root.tsx +++ b/web/components/view/root.tsx @@ -23,7 +23,7 @@ import { // ui import { Spinner } from "@plane/ui"; // constants -import { viewLocalPayload } from "constants/view"; +import { EViewPageType, viewLocalPayload } from "constants/view"; // types import { TViewOperations } from "./types"; import { TView, TViewTypes } from "@plane/types"; @@ -33,6 +33,7 @@ type TGlobalViewRoot = { projectId: string | undefined; viewId: string; viewType: TViewTypes; + viewPageType: EViewPageType; baseRoute: string; workspaceViewTabOptions: { key: TViewTypes; title: string; href: string }[]; }; @@ -43,7 +44,7 @@ type TViewOperationsToggle = { }; export const GlobalViewRoot: FC = observer((props) => { - const { workspaceSlug, projectId, viewId, viewType, baseRoute, workspaceViewTabOptions } = props; + const { workspaceSlug, projectId, viewId, viewType, viewPageType, baseRoute, workspaceViewTabOptions } = props; // hooks const viewStore = useView(workspaceSlug, projectId, viewType); const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); @@ -232,7 +233,13 @@ export const GlobalViewRoot: FC = observer((props) => {
- +
@@ -241,6 +248,7 @@ export const GlobalViewRoot: FC = observer((props) => { projectId={projectId} viewId={viewId} viewType={viewType} + viewPageType={viewPageType} displayDropdownText={false} />
@@ -251,24 +259,29 @@ export const GlobalViewRoot: FC = observer((props) => { projectId={projectId} viewId={viewId} viewType={viewType} + viewPageType={viewPageType} displayDropdownText={false} />
- +
+ +
- +
+ +
)} @@ -282,6 +295,7 @@ export const GlobalViewRoot: FC = observer((props) => { projectId={projectId} viewId={viewOperationsToggle.viewId} viewType={viewType} + viewPageType={viewPageType} viewOperations={viewOperations} /> )} diff --git a/web/components/view/views/create-edit-form.tsx b/web/components/view/views/create-edit-form.tsx index a44ce087e..2fbd62208 100644 --- a/web/components/view/views/create-edit-form.tsx +++ b/web/components/view/views/create-edit-form.tsx @@ -11,17 +11,20 @@ import { Input, Button } from "@plane/ui"; // types import { TViewTypes } from "@plane/types"; import { TViewOperations } from "../types"; +// constants +import { EViewPageType } from "constants/view"; type TViewCreateEditForm = { workspaceSlug: string; projectId: string | undefined; viewId: string; viewType: TViewTypes; + viewPageType: EViewPageType; viewOperations: TViewOperations; }; export const ViewCreateEditForm: FC = observer((props) => { - const { workspaceSlug, projectId, viewId, viewType, viewOperations } = props; + const { workspaceSlug, projectId, viewId, viewType, viewPageType, viewOperations } = props; // hooks const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType); const { getProjectById } = useProject(); @@ -126,6 +129,7 @@ export const ViewCreateEditForm: FC = observer((props) => { projectId={projectId} viewId={viewId} viewType={viewType} + viewPageType={viewPageType} dropdownPlacement="right" >
diff --git a/web/components/view/views/edit-dropdown.tsx b/web/components/view/views/edit-dropdown.tsx index 81be9f966..0ee24e920 100644 --- a/web/components/view/views/edit-dropdown.tsx +++ b/web/components/view/views/edit-dropdown.tsx @@ -49,49 +49,49 @@ export const ViewEditDropdown: FC = observer((props) => { onClick: () => viewOperations.localViewCreateEdit(viewId), children: undefined, }, - // { - // icon: Eye, - // key: "accessability", - // label: "Change Accessability", - // onClick: () => {}, - // children: [ - // { - // icon: Eye, - // key: "private", - // label: "Private", - // onClick: () => viewOperations.create({}), - // children: undefined, - // }, - // { - // icon: Globe2, - // key: "public", - // label: "Public", - // onClick: () => viewOperations.create({}), - // children: undefined, - // }, - // ], - // }, - // { - // icon: Copy, - // key: "duplicate", - // label: "Duplicate view", - // onClick: () => viewOperations.remove(viewId), - // children: undefined, - // }, - // { - // icon: Link2, - // key: "copy_link", - // label: "Copy view link", - // onClick: () => viewOperations.remove(viewId), - // children: undefined, - // }, - // { - // icon: Trash, - // key: "delete", - // label: "Delete view", - // onClick: () => viewOperations.remove(viewId), - // children: undefined, - // }, + { + icon: Eye, + key: "accessability", + label: "Change Accessability", + onClick: () => {}, + children: [ + { + icon: Eye, + key: "private", + label: "Private", + onClick: () => viewOperations.create({}), + children: undefined, + }, + { + icon: Globe2, + key: "public", + label: "Public", + onClick: () => viewOperations.create({}), + children: undefined, + }, + ], + }, + { + icon: Copy, + key: "duplicate", + label: "Duplicate view", + onClick: () => viewOperations.remove(viewId), + children: undefined, + }, + { + icon: Link2, + key: "copy_link", + label: "Copy view link", + onClick: () => viewOperations.remove(viewId), + children: undefined, + }, + { + icon: Trash, + key: "delete", + label: "Delete view", + onClick: () => viewOperations.remove(viewId), + children: undefined, + }, ], [viewOperations, viewId] ); diff --git a/web/constants/issue.ts b/web/constants/issue.ts index ccf609b1f..65778d44a 100644 --- a/web/constants/issue.ts +++ b/web/constants/issue.ts @@ -449,4 +449,4 @@ export const groupReactionEmojis = (reactions: any) => { } return _groupedEmojis; -}; \ No newline at end of file +}; diff --git a/web/constants/view/filters.ts b/web/constants/view/filters.ts index 53879f320..8f84ac386 100644 --- a/web/constants/view/filters.ts +++ b/web/constants/view/filters.ts @@ -1,40 +1,24 @@ // types -import { TStateGroups, TIssuePriorities, TViewFilters, TViewDisplayFilters, TViewLayouts } from "@plane/types"; +import { + TStateGroups, + TIssuePriorities, + TViewFilters, + TViewDisplayFilters, + TViewDisplayFiltersGrouped, + TViewDisplayFiltersOrderBy, + TViewDisplayFiltersType, +} from "@plane/types"; // filters constants -export const STATE_GROUP_PROPERTY: { - [key in TStateGroups]: { - label: string; - color: string; - }; -} = { - backlog: { - label: "Backlog", - color: "#d9d9d9", - }, - unstarted: { - label: "Unstarted", - color: "#3f76ff", - }, - started: { - label: "Started", - color: "#f59e0b", - }, - completed: { - label: "Completed", - color: "#16a34a", - }, - cancelled: { - label: "Canceled", - color: "#dc2626", - }, +export const STATE_GROUP_PROPERTY: Record = { + backlog: { label: "Backlog", color: "#d9d9d9" }, + unstarted: { label: "Unstarted", color: "#3f76ff" }, + started: { label: "Started", color: "#f59e0b" }, + completed: { label: "Completed", color: "#16a34a" }, + cancelled: { label: "Canceled", color: "#dc2626" }, }; -export const PRIORITIES_PROPERTY: { - [key in TIssuePriorities]: { - label: string; - }; -} = { +export const PRIORITIES_PROPERTY: Record = { urgent: { label: "Urgent" }, high: { label: "High" }, medium: { label: "Medium" }, @@ -42,11 +26,7 @@ export const PRIORITIES_PROPERTY: { none: { label: "None" }, }; -export const DATE_PROPERTY: { - [key in string]: { - label: string; - }; -} = { +export const DATE_PROPERTY: Record = { "1_weeks;after;fromnow": { label: "1 week from now" }, "2_weeks;after;fromnow": { label: "2 weeks from now" }, "1_months;after;fromnow": { label: "1 month from now" }, @@ -55,77 +35,98 @@ export const DATE_PROPERTY: { }; // display filter constants +export const GROUP_BY_PROPERTY: Partial> = { + state: { label: "states" }, + priority: { label: "Priority" }, + labels: { label: "labels" }, + assignees: { label: "Assignees" }, + created_by: { label: "Created By" }, + cycles: { label: "Cycles" }, + modules: { label: "Modules" }, + null: { label: "None" }, +}; -// layout, filter, display filter and display properties permissions for views -type TViewLayoutFilterProperties = { +export const ORDER_BY_PROPERTY: Partial>> = { + sort_order: { label: "Manual" }, + "-created_at": { label: "Last Created" }, + "-updated_at": { label: "Last Updated" }, + start_date: { label: "Start Date" }, + target_date: { label: "Due Date" }, + "-priority": { label: "Priority" }, +}; + +export const TYPE_PROPERTY: Record = { + null: { label: "All" }, + active: { label: "Active issues" }, + backlog: { label: "Backlog issues" }, +}; + +export const EXTRA_OPTIONS_PROPERTY: Record = { + sub_issue: { label: "Sub Issues" }, + show_empty_groups: { label: "Show Empty Groups" }, +}; + +export enum EViewPageType { + ALL = "all", + PROFILE = "profile", + PROJECT = "project", + ARCHIVED = "archived", + DRAFT = "draft", +} + +export enum EViewLayouts { + LIST = "list", + KANBAN = "kanban", + CALENDAR = "calendar", + SPREADSHEET = "spreadsheet", + GANTT = "gantt", +} + +export type TViewLayoutFilterProperties = { filters: Partial[]; - readonlyFilters?: Partial[]; display_filters: Partial[]; extra_options: ("sub_issue" | "show_empty_groups")[]; display_properties: boolean; + readonlyFilters?: Partial[]; }; -type TViewLayoutFilters = { - list: TViewLayoutFilterProperties; - kanban: TViewLayoutFilterProperties; - calendar: TViewLayoutFilterProperties; - spreadsheet: TViewLayoutFilterProperties; - gantt: TViewLayoutFilterProperties; +export type TViewLayoutFilters = { + layouts: Partial[]; + [EViewLayouts.LIST]: TViewLayoutFilterProperties; + [EViewLayouts.KANBAN]: TViewLayoutFilterProperties; + [EViewLayouts.CALENDAR]: TViewLayoutFilterProperties; + [EViewLayouts.SPREADSHEET]: TViewLayoutFilterProperties; + [EViewLayouts.GANTT]: TViewLayoutFilterProperties; }; -type TFilterPermissions = { - all: Omit & { - layouts: Omit[]; - }; - profile: Omit & { - layouts: Omit[]; - }; - project: TViewLayoutFilters & { - layouts: TViewLayouts[]; - }; - archived: Omit & { - layouts: Omit[]; - }; - draft: Omit & { - layouts: Omit[]; - }; +export type TFilterPermissions = { + [EViewPageType.ALL]: Partial; + [EViewPageType.PROFILE]: Partial; + [EViewPageType.PROJECT]: TViewLayoutFilters; + [EViewPageType.ARCHIVED]: Partial; + [EViewPageType.DRAFT]: Partial; }; const ALL_FILTER_PERMISSIONS: TFilterPermissions["all"] = { - layouts: ["spreadsheet"], - spreadsheet: { - // filters: ["project", "priority", "state_group", "assignees", "created_by", "labels", "start_date", "target_date"], - filters: [ - "project", - "module", - "cycle", - "priority", - "state", - "state_group", - "assignees", - "mentions", - "subscriber", - "created_by", - "labels", - "start_date", - "target_date", - ], - // display_filters: ["type"], - display_filters: ["group_by", "sub_group_by", "order_by", "type"], - extra_options: [], + layouts: [EViewLayouts.SPREADSHEET], + [EViewLayouts.SPREADSHEET]: { + filters: ["project", "priority", "state_group", "assignees", "created_by", "labels", "start_date", "target_date"], + display_filters: ["type"], + // extra_options: [], + extra_options: ["sub_issue", "show_empty_groups"], display_properties: true, }, }; const PROFILE_FILTER_PERMISSIONS: TFilterPermissions["profile"] = { - layouts: ["list", "kanban"], - list: { + layouts: [EViewLayouts.LIST, EViewLayouts.KANBAN], + [EViewLayouts.LIST]: { filters: ["priority", "state_group", "labels", "start_date", "target_date"], display_filters: ["group_by", "order_by", "type"], extra_options: [], display_properties: true, }, - kanban: { + [EViewLayouts.KANBAN]: { filters: ["priority", "state_group", "labels", "start_date", "target_date"], display_filters: ["group_by", "order_by", "type"], extra_options: [], @@ -134,8 +135,14 @@ const PROFILE_FILTER_PERMISSIONS: TFilterPermissions["profile"] = { }; const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { - layouts: ["list", "kanban", "spreadsheet", "calendar", "gantt"], - list: { + layouts: [ + EViewLayouts.LIST, + EViewLayouts.KANBAN, + EViewLayouts.CALENDAR, + EViewLayouts.SPREADSHEET, + EViewLayouts.GANTT, + ], + [EViewLayouts.LIST]: { filters: [ "priority", "state", @@ -152,7 +159,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { extra_options: ["sub_issue", "show_empty_groups"], display_properties: true, }, - kanban: { + [EViewLayouts.KANBAN]: { filters: [ "priority", "state", @@ -169,7 +176,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { extra_options: ["sub_issue", "show_empty_groups"], display_properties: true, }, - calendar: { + [EViewLayouts.CALENDAR]: { filters: [ "priority", "state", @@ -186,7 +193,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { extra_options: ["sub_issue"], display_properties: true, }, - spreadsheet: { + [EViewLayouts.SPREADSHEET]: { filters: [ "priority", "state", @@ -203,8 +210,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { extra_options: [], display_properties: true, }, - - gantt: { + [EViewLayouts.GANTT]: { filters: [ "priority", "state", @@ -224,8 +230,8 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = { }; const ARCHIVED_FILTER_PERMISSIONS: TFilterPermissions["archived"] = { - layouts: ["list"], - list: { + layouts: [EViewLayouts.LIST], + [EViewLayouts.LIST]: { filters: [ "priority", "state", @@ -245,8 +251,8 @@ const ARCHIVED_FILTER_PERMISSIONS: TFilterPermissions["archived"] = { }; const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = { - layouts: ["list", "kanban"], - list: { + layouts: [EViewLayouts.LIST, EViewLayouts.KANBAN], + [EViewLayouts.LIST]: { filters: [ "priority", "state", @@ -263,7 +269,7 @@ const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = { extra_options: ["sub_issue", "show_empty_groups"], display_properties: true, }, - kanban: { + [EViewLayouts.KANBAN]: { filters: [ "priority", "state", @@ -283,9 +289,19 @@ const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = { }; export const VIEW_DEFAULT_FILTER_PARAMETERS: TFilterPermissions = { - all: ALL_FILTER_PERMISSIONS, - profile: PROFILE_FILTER_PERMISSIONS, - project: PROJECT_FILTER_PERMISSIONS, - archived: ARCHIVED_FILTER_PERMISSIONS, - draft: DRAFT_FILTER_PERMISSIONS, + [EViewPageType.ALL]: ALL_FILTER_PERMISSIONS, + [EViewPageType.PROFILE]: PROFILE_FILTER_PERMISSIONS, + [EViewPageType.PROJECT]: PROJECT_FILTER_PERMISSIONS, + [EViewPageType.ARCHIVED]: ARCHIVED_FILTER_PERMISSIONS, + [EViewPageType.DRAFT]: DRAFT_FILTER_PERMISSIONS, }; + +export const viewPageDefaultLayoutsByPageType = (_viewPageType: EViewPageType) => + VIEW_DEFAULT_FILTER_PARAMETERS?.[_viewPageType]?.layouts || []; + +export const viewDefaultFilterParametersByViewTypeAndLayout = ( + _viewPageType: EViewPageType, + _layout: EViewLayouts, + property: K +): TViewLayoutFilterProperties[K] => + VIEW_DEFAULT_FILTER_PARAMETERS?.[_viewPageType]?.[_layout]?.[property] as TViewLayoutFilterProperties[K]; diff --git a/web/hooks/store/views/use-view-filters.tsx b/web/hooks/store/views/use-view-filters.tsx index 731267855..7ed774ba0 100644 --- a/web/hooks/store/views/use-view-filters.tsx +++ b/web/hooks/store/views/use-view-filters.tsx @@ -13,9 +13,24 @@ import { StateGroupIcon, } from "@plane/ui"; // types -import { TIssuePriorities, TStateGroups, TViewFilters } from "@plane/types"; +import { + TIssuePriorities, + TStateGroups, + TViewFilters, + TViewDisplayFilters, + TViewDisplayFiltersGrouped, + TViewDisplayFiltersOrderBy, + TViewDisplayFiltersType, +} from "@plane/types"; // constants -import { STATE_GROUP_PROPERTY, PRIORITIES_PROPERTY, DATE_PROPERTY } from "constants/view/filters"; +import { + STATE_GROUP_PROPERTY, + PRIORITIES_PROPERTY, + DATE_PROPERTY, + GROUP_BY_PROPERTY, + ORDER_BY_PROPERTY, + TYPE_PROPERTY, +} from "constants/view/filters"; // helpers import { renderEmoji } from "helpers/emoji.helper"; import { renderFormattedDate } from "helpers/date-time.helper"; @@ -30,6 +45,11 @@ type TFilterPropertyDefaultDetails = { label: string; }; +type TDisplayFilterPropertyDetails = { + icon: ReactNode; + label: string; +}; + export const useViewFilter = (workspaceSlug: string, projectId: string | undefined) => { const { projectMap, getProjectById } = useProject(); const { getProjectModuleIds, getModuleById } = useModule(); @@ -326,9 +346,68 @@ export const useViewFilter = (workspaceSlug: string, projectId: string | undefin } }; + const displayFilterIdsWithKey = (displayFilterKey: keyof TViewDisplayFilters): string[] | undefined => { + if (!displayFilterKey) return undefined; + + switch (displayFilterKey) { + case "group_by": + return Object.keys(GROUP_BY_PROPERTY) || undefined; + case "sub_group_by": + return Object.keys(GROUP_BY_PROPERTY) || undefined; + case "order_by": + return Object.keys(ORDER_BY_PROPERTY) || undefined; + case "type": + return Object.keys(TYPE_PROPERTY) || undefined; + default: + return undefined; + } + }; + + const displayPropertyDetails = ( + displayFilterKey: keyof TViewDisplayFilters, + propertyId: string + ): TDisplayFilterPropertyDetails | undefined => { + if (!displayFilterKey) return undefined; + + switch (displayFilterKey) { + case "group_by": + const groupBy = GROUP_BY_PROPERTY?.[propertyId as TViewDisplayFiltersGrouped | "null"]; + if (!groupBy) return undefined; + return { + icon: undefined, + label: groupBy.label, + }; + case "sub_group_by": + const subGroupBy = GROUP_BY_PROPERTY?.[propertyId as TViewDisplayFiltersGrouped | "null"]; + if (!subGroupBy) return undefined; + return { + icon: undefined, + label: subGroupBy.label, + }; + case "order_by": + const orderBy = ORDER_BY_PROPERTY?.[propertyId as TViewDisplayFiltersOrderBy]; + if (!orderBy) return undefined; + return { + icon: undefined, + label: orderBy.label, + }; + case "type": + const type = TYPE_PROPERTY?.[propertyId as TViewDisplayFiltersType | "null"]; + if (!type) return undefined; + return { + icon: undefined, + label: type.label, + }; + default: + return undefined; + } + }; + return { filterIdsWithKey, propertyDefaultDetails, propertyDetails, + displayFilterIdsWithKey, + displayPropertyDetails, }; }; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/views/private/[viewId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/views/private/[viewId].tsx index c0500b9b0..b3dc969ab 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/views/private/[viewId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/views/private/[viewId].tsx @@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view"; // types import { NextPageWithLayout } from "lib/types"; // constants -import { VIEW_TYPES } from "constants/view"; +import { EViewPageType, VIEW_TYPES } from "constants/view"; const ProjectPrivateViewPage: NextPageWithLayout = () => { const router = useRouter(); @@ -38,6 +38,7 @@ const ProjectPrivateViewPage: NextPageWithLayout = () => { projectId={projectId.toString()} viewId={viewId.toString()} viewType={VIEW_TYPES.PROJECT_PRIVATE_VIEWS} + viewPageType={EViewPageType.PROJECT} baseRoute={`/${workspaceSlug?.toString()}/projects/${projectId}/views/private`} workspaceViewTabOptions={workspaceViewTabOptions} /> diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/views/private/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/views/private/index.tsx index 5e806c992..a5c34bc86 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/views/private/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/views/private/index.tsx @@ -1,49 +1,16 @@ -import { ReactElement, useMemo } from "react"; +import { ReactElement } from "react"; import { useRouter } from "next/router"; // layouts import { AppLayout } from "layouts/app-layout"; -// components -import { GlobalViewRoot } from "components/view"; // types import { NextPageWithLayout } from "lib/types"; -// constants -import { VIEW_TYPES } from "constants/view"; const ProjectPrivateViewPage: NextPageWithLayout = () => { const router = useRouter(); const { workspaceSlug, projectId, viewId } = router.query; - const workspaceViewTabOptions = useMemo( - () => [ - { - key: VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS, - title: "Private", - href: `/${workspaceSlug}/projects/${projectId}/views/private`, - }, - { - key: VIEW_TYPES.WORKSPACE_PUBLIC_VIEWS, - title: "Public", - href: `/${workspaceSlug}/projects/${projectId}/views/public`, - }, - ], - [workspaceSlug, projectId] - ); - if (!workspaceSlug || !projectId || !viewId) return <>; - return ( -
-
- -
-
- ); + return
; }; ProjectPrivateViewPage.getLayout = function getLayout(page: ReactElement) { diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/views/public/[viewId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/views/public/[viewId].tsx index 852ab91bb..3a82caa51 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/views/public/[viewId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/views/public/[viewId].tsx @@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view"; // types import { NextPageWithLayout } from "lib/types"; // constants -import { VIEW_TYPES } from "constants/view"; +import { EViewPageType, VIEW_TYPES } from "constants/view"; const ProjectPublicViewPage: NextPageWithLayout = () => { const router = useRouter(); @@ -38,6 +38,7 @@ const ProjectPublicViewPage: NextPageWithLayout = () => { projectId={undefined} viewId={viewId.toString()} viewType={VIEW_TYPES.PROJECT_PUBLIC_VIEWS} + viewPageType={EViewPageType.PROJECT} baseRoute={`/${workspaceSlug?.toString()}/views/public`} workspaceViewTabOptions={workspaceViewTabOptions} /> diff --git a/web/pages/[workspaceSlug]/views/private/[viewId].tsx b/web/pages/[workspaceSlug]/views/private/[viewId].tsx index a4a3b4b11..0dac0cf9c 100644 --- a/web/pages/[workspaceSlug]/views/private/[viewId].tsx +++ b/web/pages/[workspaceSlug]/views/private/[viewId].tsx @@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view"; // types import { NextPageWithLayout } from "lib/types"; // constants -import { VIEW_TYPES } from "constants/view"; +import { EViewPageType, VIEW_TYPES } from "constants/view"; const WorkspacePrivateViewPage: NextPageWithLayout = () => { const router = useRouter(); @@ -38,6 +38,7 @@ const WorkspacePrivateViewPage: NextPageWithLayout = () => { projectId={undefined} viewId={viewId.toString()} viewType={VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS} + viewPageType={EViewPageType.ALL} baseRoute={`/${workspaceSlug?.toString()}/views/private`} workspaceViewTabOptions={workspaceViewTabOptions} /> diff --git a/web/pages/[workspaceSlug]/views/public/[viewId].tsx b/web/pages/[workspaceSlug]/views/public/[viewId].tsx index 6226492b2..657975b18 100644 --- a/web/pages/[workspaceSlug]/views/public/[viewId].tsx +++ b/web/pages/[workspaceSlug]/views/public/[viewId].tsx @@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view"; // types import { NextPageWithLayout } from "lib/types"; // constants -import { VIEW_TYPES } from "constants/view"; +import { EViewPageType, VIEW_TYPES } from "constants/view"; const WorkspacePublicViewPage: NextPageWithLayout = () => { const router = useRouter(); @@ -38,6 +38,7 @@ const WorkspacePublicViewPage: NextPageWithLayout = () => { projectId={undefined} viewId={viewId.toString()} viewType={VIEW_TYPES.WORKSPACE_PUBLIC_VIEWS} + viewPageType={EViewPageType.ALL} baseRoute={`/${workspaceSlug?.toString()}/views/public`} workspaceViewTabOptions={workspaceViewTabOptions} /> diff --git a/web/store/view/helpers/filters_helpers.ts b/web/store/view/helpers/filters_helpers.ts index c1a14277f..9aceec4c6 100644 --- a/web/store/view/helpers/filters_helpers.ts +++ b/web/store/view/helpers/filters_helpers.ts @@ -8,6 +8,8 @@ import { TViewFilterProps, TViewFilterQueryParams, } from "@plane/types"; +// constants +import { EViewPageType, viewPageDefaultLayoutsByPageType } from "constants/view"; export class FiltersHelper { // computed filters @@ -29,21 +31,26 @@ export class FiltersHelper { // computed display filters computedDisplayFilters = ( + viewPageType: EViewPageType, displayFilters: TViewDisplayFilters, defaultValues?: Partial - ): TViewDisplayFilters => ({ - layout: defaultValues?.layout || displayFilters?.layout || "list", - group_by: defaultValues?.group_by || displayFilters?.group_by || undefined, - sub_group_by: defaultValues?.sub_group_by || displayFilters?.sub_group_by || undefined, - order_by: defaultValues?.order_by || displayFilters?.order_by || "sort_order", - type: defaultValues?.type || displayFilters?.type || undefined, - sub_issue: defaultValues?.sub_issue || displayFilters?.sub_issue || false, - show_empty_groups: defaultValues?.show_empty_groups || displayFilters?.show_empty_groups || false, - calendar: { - show_weekends: defaultValues?.calendar?.show_weekends || displayFilters?.calendar?.show_weekends || false, - layout: defaultValues?.calendar?.layout || displayFilters?.calendar?.layout || "month", - }, - }); + ): TViewDisplayFilters => { + const viewPageDefaultLayout = viewPageDefaultLayoutsByPageType(viewPageType)?.[0] || "list"; + + return { + layout: defaultValues?.layout || displayFilters?.layout || viewPageDefaultLayout, + group_by: defaultValues?.group_by || displayFilters?.group_by || undefined, + sub_group_by: defaultValues?.sub_group_by || displayFilters?.sub_group_by || undefined, + order_by: defaultValues?.order_by || displayFilters?.order_by || "sort_order", + type: defaultValues?.type || displayFilters?.type || undefined, + sub_issue: defaultValues?.sub_issue || displayFilters?.sub_issue || false, + show_empty_groups: defaultValues?.show_empty_groups || displayFilters?.show_empty_groups || false, + calendar: { + show_weekends: defaultValues?.calendar?.show_weekends || displayFilters?.calendar?.show_weekends || false, + layout: defaultValues?.calendar?.layout || displayFilters?.calendar?.layout || "month", + }, + }; + }; // computed display properties computedDisplayProperties = ( diff --git a/web/store/view/root.store.ts b/web/store/view/root.store.ts index 088fbe0ed..66dd2e2dd 100644 --- a/web/store/view/root.store.ts +++ b/web/store/view/root.store.ts @@ -11,6 +11,8 @@ import { } from "services/view"; // types import { RootStore } from "store/root.store"; +// constants +import { EViewPageType } from "constants/view"; export class GlobalViewRootStore { workspacePrivateViewStore: ViewRootStore; @@ -59,25 +61,29 @@ export class GlobalViewRootStore { this.store, workspacePrivateDefaultViews, new WorkspacePrivateViewService(), - new WorkspaceFiltersService() + new WorkspaceFiltersService(), + EViewPageType.ALL ); this.workspacePublicViewStore = new ViewRootStore( this.store, workspacePublicDefaultViews, new WorkspacePublicViewService(), - new WorkspaceFiltersService() + new WorkspaceFiltersService(), + EViewPageType.ALL ); this.projectPrivateViewStore = new ViewRootStore( this.store, undefined, new ProjectPrivateViewService(), - new ProjectFiltersService() + new ProjectFiltersService(), + EViewPageType.PROJECT ); this.projectPublicViewStore = new ViewRootStore( this.store, undefined, new ProjectPublicViewService(), - new ProjectFiltersService() + new ProjectFiltersService(), + EViewPageType.PROJECT ); } } diff --git a/web/store/view/view-root.store.ts b/web/store/view/view-root.store.ts index ba6d960fa..9bc25c0b1 100644 --- a/web/store/view/view-root.store.ts +++ b/web/store/view/view-root.store.ts @@ -9,6 +9,8 @@ import { ViewStore } from "./view.store"; // types import { TUserViewService, TViewService } from "services/view/types"; import { TView } from "@plane/types"; +// constants +import { EViewPageType } from "constants/view"; export type TLoader = "init-loader" | "mutation-loader" | "submitting" | undefined; @@ -37,7 +39,8 @@ export class ViewRootStore implements TViewRootStore { private store: RootStore, private defaultViews: TView[] = [], private service: TViewService, - private userService: TUserViewService + private userService: TUserViewService, + private viewPageType: EViewPageType ) { makeObservable(this, { // observables @@ -70,7 +73,12 @@ export class ViewRootStore implements TViewRootStore { // actions localViewCreate = async (view: TView) => { runInAction(() => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); }; @@ -84,7 +92,12 @@ export class ViewRootStore implements TViewRootStore { if (this.defaultViews && this.defaultViews.length > 0) runInAction(() => { this.defaultViews?.forEach((view) => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); }); @@ -93,7 +106,12 @@ export class ViewRootStore implements TViewRootStore { runInAction(() => { views.forEach((view) => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); this.loader = undefined; }); @@ -105,9 +123,13 @@ export class ViewRootStore implements TViewRootStore { const { workspaceSlug, projectId } = this.store.app.router; if (!workspaceSlug || !viewId) return; + // fetching display properties and display_filters const userView = await this.userService.fetch(workspaceSlug, projectId); if (!userView) return; + // fetching kanban display filters from local + + // fetching display filters from local and from the view if (["all-issues", "assigned", "created", "subscribed"].includes(viewId)) { const view = { ...this.viewById(viewId) }; if (!view) return; @@ -124,7 +146,12 @@ export class ViewRootStore implements TViewRootStore { view?.display_properties && (view.display_properties = userView.display_properties); runInAction(() => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); } } catch {} @@ -139,7 +166,12 @@ export class ViewRootStore implements TViewRootStore { if (!view) return; runInAction(() => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); if (data.id) this.remove(data.id); @@ -169,7 +201,12 @@ export class ViewRootStore implements TViewRootStore { if (!view) return; runInAction(() => { - if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService)); + if (view.id) + set( + this.viewMap, + [view.id], + new ViewStore(this.store, view, this.service, this.userService, this.viewPageType) + ); }); } catch {} }; diff --git a/web/store/view/view.store.ts b/web/store/view/view.store.ts index 155504ca2..1dd46329c 100644 --- a/web/store/view/view.store.ts +++ b/web/store/view/view.store.ts @@ -20,6 +20,8 @@ import { } from "@plane/types"; // helpers import { FiltersHelper } from "./helpers/filters_helpers"; +// constants +import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view"; type TLoader = "updating" | undefined; @@ -79,7 +81,8 @@ export class ViewStore extends FiltersHelper implements TViewStore { private store: RootStore, _view: TView, private service: TViewService, - private userService: TUserViewService + private userService: TUserViewService, + private viewPageType: EViewPageType ) { super(); this.id = _view.id; @@ -89,7 +92,7 @@ export class ViewStore extends FiltersHelper implements TViewStore { this.description = _view.description; this.query = _view.query; this.filters = this.computedFilters(_view.filters); - this.display_filters = this.computedDisplayFilters(_view.display_filters); + this.display_filters = this.computedDisplayFilters(this.viewPageType, _view.display_filters); this.display_properties = this.computedDisplayProperties(_view.display_properties); this.access = _view.access; this.owned_by = _view.owned_by; @@ -108,7 +111,7 @@ export class ViewStore extends FiltersHelper implements TViewStore { name: this.name, description: this.description, filters: this.computedFilters(_view.filters), - display_filters: this.computedDisplayFilters(_view.display_filters), + display_filters: this.computedDisplayFilters(this.viewPageType, _view.display_filters), display_properties: this.computedDisplayProperties(_view.display_properties), }; @@ -164,7 +167,11 @@ export class ViewStore extends FiltersHelper implements TViewStore { get appliedFilters() { return { filters: this.computedFilters(this.filters, this.filtersToUpdate.filters), - display_filters: this.computedDisplayFilters(this.display_filters, this.filtersToUpdate.display_filters), + display_filters: this.computedDisplayFilters( + this.viewPageType, + this.display_filters, + this.filtersToUpdate.display_filters + ), display_properties: this.computedDisplayProperties( this.display_properties, this.filtersToUpdate.display_properties @@ -173,9 +180,17 @@ export class ViewStore extends FiltersHelper implements TViewStore { } get appliedFiltersQueryParams() { - const filters = this.appliedFilters; - if (!filters) return undefined; - return this.computeAppliedFiltersQueryParameters(filters, [])?.query || undefined; + const appliedFilters = this.appliedFilters; + if (!appliedFilters) return undefined; + + const layout = appliedFilters?.display_filters?.layout; + const requiredFilterProperties = viewDefaultFilterParametersByViewTypeAndLayout( + this.viewPageType, + layout, + "filters" + ); + + return this.computeAppliedFiltersQueryParameters(appliedFilters, requiredFilterProperties)?.query || undefined; } get isFiltersApplied() { @@ -247,12 +262,18 @@ export class ViewStore extends FiltersHelper implements TViewStore { set(this.filtersToUpdate, ["display_filters", _key], display_filters[_key]); }); }); + + // update display properties globally + + // updating display properties locally for kanban filters }; setDisplayProperties = async (displayPropertyKey: keyof TViewDisplayProperties) => { runInAction(() => { update(this.filtersToUpdate, ["display_properties", displayPropertyKey], (_value: boolean = true) => !_value); }); + + // update display properties globally }; setIsEditable = (is_editable: boolean) => {