From 9302cfc99afa132398e026acba56bebca3f666a5 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Tue, 2 Apr 2024 16:39:36 +0530 Subject: [PATCH 1/4] chore: cycle and module feature issue block validation --- .../properties/all-properties.tsx | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/web/components/issues/issue-layouts/properties/all-properties.tsx b/web/components/issues/issue-layouts/properties/all-properties.tsx index 72614079a2a..ab1cad738b2 100644 --- a/web/components/issues/issue-layouts/properties/all-properties.tsx +++ b/web/components/issues/issue-layouts/properties/all-properties.tsx @@ -24,7 +24,7 @@ import { EIssuesStoreType } from "@/constants/issue"; import { cn } from "@/helpers/common.helper"; import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"; import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper"; -import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState } from "@/hooks/store"; +import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState, useProject } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // components import { IssuePropertyLabels } from "../properties/labels"; @@ -45,6 +45,7 @@ export interface IIssueProperties { export const IssueProperties: React.FC = observer((props) => { const { issue, updateIssue, displayProperties, activeLayout, isReadOnly, className } = props; // store hooks + const { getProjectById } = useProject(); const { labelMap } = useLabel(); const { captureIssueEvent } = useEventTracker(); const { @@ -56,6 +57,7 @@ export const IssueProperties: React.FC = observer((props) => { const { areEstimatesEnabledForCurrentProject } = useEstimate(); const { getStateById } = useProjectState(); const { isMobile } = usePlatformOS(); + const projectDetails = getProjectById(issue.project_id); // router const router = useRouter(); const { workspaceSlug } = router.query; @@ -349,36 +351,40 @@ export const IssueProperties: React.FC = observer((props) => { {/* modules */} - -
- -
-
+ {projectDetails?.module_view && ( + +
+ +
+
+ )} {/* cycles */} - -
- -
-
+ {projectDetails?.cycle_view && ( + +
+ +
+
+ )} {/* estimates */} {areEstimatesEnabledForCurrentProject && ( From 2fa9f3deb651c89d0a67bf9e238f38dd676fcc6d Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Tue, 2 Apr 2024 16:41:48 +0530 Subject: [PATCH 2/4] chore: cycle and module feature display properties validation --- web/components/cycles/cycle-mobile-header.tsx | 5 +- web/components/headers/cycle-issues.tsx | 2 + web/components/headers/module-issues.tsx | 2 + .../headers/project-draft-issues.tsx | 2 + web/components/headers/project-issues.tsx | 2 + .../headers/project-view-issues.tsx | 2 + .../issues/archived-issues-header.tsx | 5 +- .../display-filters-selection.tsx | 23 +++++++-- .../display-filters/display-properties.tsx | 47 ++++++++++++------- .../issues/issues-mobile-header.tsx | 2 + .../modules/module-mobile-header.tsx | 5 +- 11 files changed, 73 insertions(+), 24 deletions(-) diff --git a/web/components/cycles/cycle-mobile-header.tsx b/web/components/cycles/cycle-mobile-header.tsx index 8c168cbaa08..0aa91ca9920 100644 --- a/web/components/cycles/cycle-mobile-header.tsx +++ b/web/components/cycles/cycle-mobile-header.tsx @@ -10,7 +10,7 @@ import { CustomMenu } from "@plane/ui"; import { ProjectAnalyticsModal } from "@/components/analytics"; import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues"; import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue"; -import { useIssues, useCycle, useProjectState, useLabel, useMember } from "@/hooks/store"; +import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store"; export const CycleMobileHeader = () => { const [analyticsModal, setAnalyticsModal] = useState(false); @@ -24,6 +24,7 @@ export const CycleMobileHeader = () => { const { workspaceSlug, projectId, cycleId } = router.query; const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; // store hooks + const { currentProjectDetails } = useProject(); const { issuesFilter: { issueFilters, updateFilters }, } = useIssues(EIssuesStoreType.CYCLE); @@ -174,6 +175,8 @@ export const CycleMobileHeader = () => { displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} ignoreGroupedFilters={["cycle"]} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index 35a646c1c95..bad515d54f0 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -262,6 +262,8 @@ export const CycleIssuesHeader: React.FC = observer(() => { displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} ignoreGroupedFilters={["cycle"]} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx index 59cc2a42955..9d021a4df8e 100644 --- a/web/components/headers/module-issues.tsx +++ b/web/components/headers/module-issues.tsx @@ -264,6 +264,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => { displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} ignoreGroupedFilters={["module"]} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-draft-issues.tsx b/web/components/headers/project-draft-issues.tsx index bdfaebc8de7..86797290c1f 100644 --- a/web/components/headers/project-draft-issues.tsx +++ b/web/components/headers/project-draft-issues.tsx @@ -152,6 +152,8 @@ export const ProjectDraftIssueHeader: FC = observer(() => { handleDisplayFiltersUpdate={handleDisplayFilters} displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 7c018d5c2fe..c38648af1a5 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -203,6 +203,8 @@ export const ProjectIssuesHeader: React.FC = observer(() => { handleDisplayFiltersUpdate={handleDisplayFilters} displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index 6f545f25b1a..a3237e6f7e4 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -221,6 +221,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { handleDisplayFiltersUpdate={handleDisplayFilters} displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> {canUserCreateIssue && ( diff --git a/web/components/issues/archived-issues-header.tsx b/web/components/issues/archived-issues-header.tsx index cd5aca903c8..bf8c373323c 100644 --- a/web/components/issues/archived-issues-header.tsx +++ b/web/components/issues/archived-issues-header.tsx @@ -9,13 +9,14 @@ import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/com // constants import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue"; // hooks -import { useIssues, useLabel, useMember, useProjectState } from "@/hooks/store"; +import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store"; export const ArchivedIssuesHeader: FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; // store hooks + const { currentProjectDetails } = useProject(); const { issuesFilter: { issueFilters, updateFilters }, } = useIssues(EIssuesStoreType.ARCHIVED); @@ -89,6 +90,8 @@ export const ArchivedIssuesHeader: FC = observer(() => { layoutDisplayFiltersOptions={ activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined } + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/issues/issue-layouts/filters/header/display-filters/display-filters-selection.tsx b/web/components/issues/issue-layouts/filters/header/display-filters/display-filters-selection.tsx index d270d6a1ccd..eb2238a4b95 100644 --- a/web/components/issues/issue-layouts/filters/header/display-filters/display-filters-selection.tsx +++ b/web/components/issues/issue-layouts/filters/header/display-filters/display-filters-selection.tsx @@ -21,6 +21,8 @@ type Props = { handleDisplayPropertiesUpdate: (updatedDisplayProperties: Partial) => void; layoutDisplayFiltersOptions: ILayoutDisplayFiltersOptions | undefined; ignoreGroupedFilters?: Partial[]; + cycleViewDisabled?: boolean; + moduleViewDisabled?: boolean; }; export const DisplayFiltersSelection: React.FC = observer((props) => { @@ -31,17 +33,32 @@ export const DisplayFiltersSelection: React.FC = observer((props) => { handleDisplayPropertiesUpdate, layoutDisplayFiltersOptions, ignoreGroupedFilters = [], + cycleViewDisabled = false, + moduleViewDisabled = false, } = props; const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) => Object.keys(layoutDisplayFiltersOptions?.display_filters ?? {}).includes(displayFilter); + const computedIgnoreGroupedFilters: Partial[] = []; + if (cycleViewDisabled) { + ignoreGroupedFilters.push("cycle"); + } + if (moduleViewDisabled) { + ignoreGroupedFilters.push("module"); + } + return (
{/* display properties */} {layoutDisplayFiltersOptions?.display_properties && (
- +
)} @@ -56,7 +73,7 @@ export const DisplayFiltersSelection: React.FC = observer((props) => { group_by: val, }) } - ignoreGroupedFilters={ignoreGroupedFilters} + ignoreGroupedFilters={[...ignoreGroupedFilters, ...computedIgnoreGroupedFilters]} />
)} @@ -74,7 +91,7 @@ export const DisplayFiltersSelection: React.FC = observer((props) => { }) } subGroupByOptions={layoutDisplayFiltersOptions?.display_filters.sub_group_by ?? []} - ignoreGroupedFilters={ignoreGroupedFilters} + ignoreGroupedFilters={[...ignoreGroupedFilters, ...computedIgnoreGroupedFilters]} /> )} diff --git a/web/components/issues/issue-layouts/filters/header/display-filters/display-properties.tsx b/web/components/issues/issue-layouts/filters/header/display-filters/display-properties.tsx index 54cb0a439d8..aebb8d5cc11 100644 --- a/web/components/issues/issue-layouts/filters/header/display-filters/display-properties.tsx +++ b/web/components/issues/issue-layouts/filters/header/display-filters/display-properties.tsx @@ -10,13 +10,22 @@ import { FilterHeader } from "../helpers/filter-header"; type Props = { displayProperties: IIssueDisplayProperties; handleUpdate: (updatedDisplayProperties: Partial) => void; + cycleViewDisabled?: boolean; + moduleViewDisabled?: boolean; }; export const FilterDisplayProperties: React.FC = observer((props) => { - const { displayProperties, handleUpdate } = props; + const { displayProperties, handleUpdate, cycleViewDisabled = false, moduleViewDisabled = false } = props; const [previewEnabled, setPreviewEnabled] = React.useState(true); + // Filter out "cycle" and "module" keys if cycleViewDisabled or moduleViewDisabled is true + const filteredDisplayProperties = ISSUE_DISPLAY_PROPERTIES.filter((property) => { + if (cycleViewDisabled && property.key === "cycle") return false; + if (moduleViewDisabled && property.key === "modules") return false; + return true; + }); + return ( <> = observer((props) => { /> {previewEnabled && (
- {ISSUE_DISPLAY_PROPERTIES.map((displayProperty) => ( - + {filteredDisplayProperties.map((displayProperty) => ( + <> + + ))}
)} diff --git a/web/components/issues/issues-mobile-header.tsx b/web/components/issues/issues-mobile-header.tsx index 4bc90b686c0..5c356ae2fb7 100644 --- a/web/components/issues/issues-mobile-header.tsx +++ b/web/components/issues/issues-mobile-header.tsx @@ -154,6 +154,8 @@ export const IssuesMobileHeader = observer(() => { handleDisplayFiltersUpdate={handleDisplayFilters} displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/modules/module-mobile-header.tsx b/web/components/modules/module-mobile-header.tsx index 6419b13b08c..fe41c390b49 100644 --- a/web/components/modules/module-mobile-header.tsx +++ b/web/components/modules/module-mobile-header.tsx @@ -11,12 +11,13 @@ import { ProjectAnalyticsModal } from "@/components/analytics"; import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues"; // hooks import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue"; -import { useIssues, useLabel, useMember, useModule, useProjectState } from "@/hooks/store"; +import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; // types // constants export const ModuleMobileHeader = observer(() => { const [analyticsModal, setAnalyticsModal] = useState(false); + const { currentProjectDetails } = useProject(); const { getModuleById } = useModule(); const layouts = [ { key: "list", title: "List", icon: List }, @@ -157,6 +158,8 @@ export const ModuleMobileHeader = observer(() => { displayProperties={issueFilters?.displayProperties ?? {}} handleDisplayPropertiesUpdate={handleDisplayProperties} ignoreGroupedFilters={["module"]} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> From 99816f321ef7b51524105ea1fc4731cc7b4268da Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 3 Apr 2024 14:49:04 +0530 Subject: [PATCH 3/4] chore: cycle and module feature display filters validation --- web/components/cycles/cycle-mobile-header.tsx | 2 ++ web/components/headers/cycle-issues.tsx | 2 ++ web/components/headers/module-issues.tsx | 2 ++ web/components/headers/project-draft-issues.tsx | 2 ++ web/components/headers/project-issues.tsx | 2 ++ web/components/headers/project-view-issues.tsx | 2 ++ .../header/filters/filters-selection.tsx | 17 ++++++++++++++--- web/components/issues/issues-mobile-header.tsx | 2 ++ web/components/modules/module-mobile-header.tsx | 2 ++ 9 files changed, 30 insertions(+), 3 deletions(-) diff --git a/web/components/cycles/cycle-mobile-header.tsx b/web/components/cycles/cycle-mobile-header.tsx index 0aa91ca9920..54a2a311503 100644 --- a/web/components/cycles/cycle-mobile-header.tsx +++ b/web/components/cycles/cycle-mobile-header.tsx @@ -152,6 +152,8 @@ export const CycleMobileHeader = () => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index bad515d54f0..e1113910f68 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -250,6 +250,8 @@ export const CycleIssuesHeader: React.FC = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx index 9d021a4df8e..56da66d2fdf 100644 --- a/web/components/headers/module-issues.tsx +++ b/web/components/headers/module-issues.tsx @@ -252,6 +252,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-draft-issues.tsx b/web/components/headers/project-draft-issues.tsx index 86797290c1f..a9f5a93f746 100644 --- a/web/components/headers/project-draft-issues.tsx +++ b/web/components/headers/project-draft-issues.tsx @@ -141,6 +141,8 @@ export const ProjectDraftIssueHeader: FC = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index c38648af1a5..fd681cc4ad6 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -192,6 +192,8 @@ export const ProjectIssuesHeader: React.FC = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index a3237e6f7e4..27c6e5f9dcc 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -210,6 +210,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} /> diff --git a/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx b/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx index 7e6e44ebf2e..9220e9fd31e 100644 --- a/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx +++ b/web/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx @@ -30,10 +30,21 @@ type Props = { labels?: IIssueLabel[] | undefined; memberIds?: string[] | undefined; states?: IState[] | undefined; + cycleViewDisabled?: boolean; + moduleViewDisabled?: boolean; }; export const FilterSelection: React.FC = observer((props) => { - const { filters, handleFiltersUpdate, layoutDisplayFiltersOptions, labels, memberIds, states } = props; + const { + filters, + handleFiltersUpdate, + layoutDisplayFiltersOptions, + labels, + memberIds, + states, + cycleViewDisabled = false, + moduleViewDisabled = false, + } = props; // hooks const { router: { moduleId, cycleId }, @@ -111,7 +122,7 @@ export const FilterSelection: React.FC = observer((props) => { )} {/* cycle */} - {isFilterEnabled("cycle") && !cycleId && ( + {isFilterEnabled("cycle") && !cycleId && !cycleViewDisabled && (
= observer((props) => { )} {/* module */} - {isFilterEnabled("module") && !moduleId && ( + {isFilterEnabled("module") && !moduleId && !moduleViewDisabled && (
{ labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} />
diff --git a/web/components/modules/module-mobile-header.tsx b/web/components/modules/module-mobile-header.tsx index fe41c390b49..79486a37cc5 100644 --- a/web/components/modules/module-mobile-header.tsx +++ b/web/components/modules/module-mobile-header.tsx @@ -135,6 +135,8 @@ export const ModuleMobileHeader = observer(() => { labels={projectLabels} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} />
From 89418037a86de3c6e7c389e945d4b01207f35072 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 3 Apr 2024 14:51:40 +0530 Subject: [PATCH 4/4] chore: cycle and module feature project view validation --- web/components/views/form.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/components/views/form.tsx b/web/components/views/form.tsx index e758b7938ae..a8fa6b87cb9 100644 --- a/web/components/views/form.tsx +++ b/web/components/views/form.tsx @@ -6,7 +6,7 @@ import { IProjectView, IIssueFilterOptions } from "@plane/types"; import { Button, Input, TextArea } from "@plane/ui"; import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "@/components/issues"; import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue"; -import { useLabel, useMember, useProjectState } from "@/hooks/store"; +import { useLabel, useMember, useProject, useProjectState } from "@/hooks/store"; // components // ui // types @@ -27,6 +27,7 @@ const defaultValues: Partial = { export const ProjectViewForm: React.FC = observer((props) => { const { handleFormSubmit, handleClose, data, preLoadedData } = props; // store hooks + const { currentProjectDetails } = useProject(); const { projectStates } = useProjectState(); const { projectLabels } = useLabel(); const { @@ -184,6 +185,8 @@ export const ProjectViewForm: React.FC = observer((props) => { labels={projectLabels ?? undefined} memberIds={projectMemberIds ?? undefined} states={projectStates} + cycleViewDisabled={!currentProjectDetails?.cycle_view} + moduleViewDisabled={!currentProjectDetails?.module_view} />
)} @@ -212,8 +215,8 @@ export const ProjectViewForm: React.FC = observer((props) => { ? "Updating View..." : "Update View" : isSubmitting - ? "Creating View..." - : "Create View"} + ? "Creating View..." + : "Create View"}