From f38278f46566a758b9794aa8335fe002442ceea2 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:29:10 +0530 Subject: [PATCH] chore: user permission related fix (#3066) * chore: page action user permission validation * chore: cycle & module action user permission validation * chore: issue quick action user permission validation * chore: spreadsheet layout improvement --- web/components/cycles/cycles-board-card.tsx | 30 ++++--- web/components/cycles/cycles-list-item.tsx | 27 +++--- .../issues/issue-layouts/properties/state.tsx | 2 +- .../quick-action-dropdowns/project-issue.tsx | 88 +++++++++++-------- web/components/modules/module-card-item.tsx | 59 ++++++++----- web/components/modules/module-list-item.tsx | 54 +++++++----- web/components/pages/pages-list/list-item.tsx | 31 ++++--- 7 files changed, 170 insertions(+), 121 deletions(-) diff --git a/web/components/cycles/cycles-board-card.tsx b/web/components/cycles/cycles-board-card.tsx index 064d3f1aa..f020b0998 100644 --- a/web/components/cycles/cycles-board-card.tsx +++ b/web/components/cycles/cycles-board-card.tsx @@ -23,6 +23,7 @@ import { ICycle } from "types"; import { useMobxStore } from "lib/mobx/store-provider"; // constants import { CYCLE_STATUS } from "constants/cycle"; +import { EUserWorkspaceRoles } from "constants/workspace"; export interface ICyclesBoardCard { workspaceSlug: string; @@ -36,6 +37,7 @@ export const CyclesBoardCard: FC = (props) => { const { cycle: cycleStore, trackEvent: { setTrackElement }, + user: userStore, } = useMobxStore(); // toast const { setToastAlert } = useToast(); @@ -49,6 +51,9 @@ export const CyclesBoardCard: FC = (props) => { const startDate = new Date(cycle.start_date ?? ""); const isDateValid = cycle.start_date || cycle.end_date; + const { currentProjectRole } = userStore; + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; + const router = useRouter(); const currentCycle = CYCLE_STATUS.find((status) => status.value === cycleStatus); @@ -68,8 +73,8 @@ export const CyclesBoardCard: FC = (props) => { ? cycleTotalIssues === 0 ? "0 Issue" : cycleTotalIssues === cycle.completed_issues - ? `${cycleTotalIssues} Issue${cycleTotalIssues > 1 ? "s" : ""}` - : `${cycle.completed_issues}/${cycleTotalIssues} Issues` + ? `${cycleTotalIssues} Issue${cycleTotalIssues > 1 ? "s" : ""}` + : `${cycle.completed_issues}/${cycleTotalIssues} Issues` : "0 Issue"; const handleCopyText = (e: MouseEvent) => { @@ -235,17 +240,18 @@ export const CyclesBoardCard: FC = (props) => { No due date )}
- {cycle.is_favorite ? ( - - ) : ( - - )} + {isEditingAllowed && + (cycle.is_favorite ? ( + + ) : ( + + ))} - {!isCompleted && ( + {!isCompleted && isEditingAllowed && ( <> diff --git a/web/components/cycles/cycles-list-item.tsx b/web/components/cycles/cycles-list-item.tsx index d1f1f22de..86b3bffa9 100644 --- a/web/components/cycles/cycles-list-item.tsx +++ b/web/components/cycles/cycles-list-item.tsx @@ -24,6 +24,7 @@ import { copyTextToClipboard } from "helpers/string.helper"; import { ICycle } from "types"; // constants import { CYCLE_STATUS } from "constants/cycle"; +import { EUserWorkspaceRoles } from "constants/workspace"; type TCyclesListItem = { cycle: ICycle; @@ -41,6 +42,7 @@ export const CyclesListItem: FC = (props) => { const { cycle: cycleStore, trackEvent: { setTrackElement }, + user: userStore, } = useMobxStore(); // toast const { setToastAlert } = useToast(); @@ -53,6 +55,9 @@ export const CyclesListItem: FC = (props) => { const endDate = new Date(cycle.end_date ?? ""); const startDate = new Date(cycle.start_date ?? ""); + const { currentProjectRole } = userStore; + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; + const router = useRouter(); const cycleTotalIssues = @@ -226,19 +231,19 @@ export const CyclesListItem: FC = (props) => { )}
- - {cycle.is_favorite ? ( - - ) : ( - - )} + {isEditingAllowed && + (cycle.is_favorite ? ( + + ) : ( + + ))} - {!isCompleted && ( + {!isCompleted && isEditingAllowed && ( <> diff --git a/web/components/issues/issue-layouts/properties/state.tsx b/web/components/issues/issue-layouts/properties/state.tsx index 2541f81ce..bb45a4d92 100644 --- a/web/components/issues/issue-layouts/properties/state.tsx +++ b/web/components/issues/issue-layouts/properties/state.tsx @@ -94,7 +94,7 @@ export const IssuePropertyState: React.FC = observer((props const label = ( -
+
{selectedOption && } {selectedOption?.name ?? "State"}
diff --git a/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx b/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx index b72ee04bb..91b9a5d35 100644 --- a/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx +++ b/web/components/issues/issue-layouts/quick-action-dropdowns/project-issue.tsx @@ -2,6 +2,8 @@ import { useState } from "react"; import { useRouter } from "next/router"; import { CustomMenu } from "@plane/ui"; import { Copy, Link, Pencil, Trash2 } from "lucide-react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // hooks import useToast from "hooks/use-toast"; // components @@ -12,6 +14,8 @@ import { copyUrlToClipboard } from "helpers/string.helper"; import { IIssue } from "types"; import { IQuickActionProps } from "../list/list-view-types"; import { EProjectStore } from "store/command-palette.store"; +// constant +import { EUserWorkspaceRoles } from "constants/workspace"; export const ProjectIssueQuickActions: React.FC = (props) => { const { issue, handleDelete, handleUpdate, customActionButton } = props; @@ -24,6 +28,12 @@ export const ProjectIssueQuickActions: React.FC = (props) => const [issueToEdit, setIssueToEdit] = useState(null); const [deleteIssueModal, setDeleteIssueModal] = useState(false); + const { user: userStore } = useMobxStore(); + + const { currentProjectRole } = userStore; + + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; + const { setToastAlert } = useToast(); const handleCopyIssueLink = () => { @@ -71,43 +81,47 @@ export const ProjectIssueQuickActions: React.FC = (props) => Copy link
- { - e.preventDefault(); - e.stopPropagation(); - setIssueToEdit(issue); - setCreateUpdateIssueModal(true); - }} - > -
- - Edit issue -
-
- { - e.preventDefault(); - e.stopPropagation(); - setCreateUpdateIssueModal(true); - }} - > -
- - Make a copy -
-
- { - e.preventDefault(); - e.stopPropagation(); - setDeleteIssueModal(true); - }} - > -
- - Delete issue -
-
+ {isEditingAllowed && ( + <> + { + e.preventDefault(); + e.stopPropagation(); + setIssueToEdit(issue); + setCreateUpdateIssueModal(true); + }} + > +
+ + Edit issue +
+
+ { + e.preventDefault(); + e.stopPropagation(); + setCreateUpdateIssueModal(true); + }} + > +
+ + Make a copy +
+
+ { + e.preventDefault(); + e.stopPropagation(); + setDeleteIssueModal(true); + }} + > +
+ + Delete issue +
+
+ + )}
); diff --git a/web/components/modules/module-card-item.tsx b/web/components/modules/module-card-item.tsx index b77b81e6b..eb65084c1 100644 --- a/web/components/modules/module-card-item.tsx +++ b/web/components/modules/module-card-item.tsx @@ -19,6 +19,7 @@ import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper" import { IModule } from "types"; // constants import { MODULE_STATUS } from "constants/module"; +import { EUserWorkspaceRoles } from "constants/workspace"; type Props = { module: IModule; @@ -35,7 +36,11 @@ export const ModuleCardItem: React.FC = observer((props) => { const { setToastAlert } = useToast(); - const { module: moduleStore } = useMobxStore(); + const { module: moduleStore, user: userStore } = useMobxStore(); + + const { currentProjectRole } = userStore; + + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; const moduleTotalIssues = module.backlog_issues + @@ -59,8 +64,8 @@ export const ModuleCardItem: React.FC = observer((props) => { ? !moduleTotalIssues || moduleTotalIssues === 0 ? "0 Issue" : moduleTotalIssues === module.completed_issues - ? `${moduleTotalIssues} Issue${moduleTotalIssues > 1 ? "s" : ""}` - : `${module.completed_issues}/${moduleTotalIssues} Issues` + ? `${moduleTotalIssues} Issue${moduleTotalIssues > 1 ? "s" : ""}` + : `${module.completed_issues}/${moduleTotalIssues} Issues` : "0 Issue"; const handleAddToFavorites = (e: React.MouseEvent) => { @@ -217,28 +222,34 @@ export const ModuleCardItem: React.FC = observer((props) => { )}
- {module.is_favorite ? ( - - ) : ( - - )} + {isEditingAllowed && + (module.is_favorite ? ( + + ) : ( + + ))} + - - - - Edit module - - - - - - Delete module - - + {isEditingAllowed && ( + <> + + + + Edit module + + + + + + Delete module + + + + )} diff --git a/web/components/modules/module-list-item.tsx b/web/components/modules/module-list-item.tsx index 818f0b697..005d8beba 100644 --- a/web/components/modules/module-list-item.tsx +++ b/web/components/modules/module-list-item.tsx @@ -19,6 +19,7 @@ import { renderShortDate, renderShortMonthDate } from "helpers/date-time.helper" import { IModule } from "types"; // constants import { MODULE_STATUS } from "constants/module"; +import { EUserWorkspaceRoles } from "constants/workspace"; type Props = { module: IModule; @@ -35,7 +36,11 @@ export const ModuleListItem: React.FC = observer((props) => { const { setToastAlert } = useToast(); - const { module: moduleStore } = useMobxStore(); + const { module: moduleStore, user: userStore } = useMobxStore(); + + const { currentProjectRole } = userStore; + + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; const completionPercentage = ((module.completed_issues + module.cancelled_issues) / module.total_issues) * 100; @@ -194,29 +199,34 @@ export const ModuleListItem: React.FC = observer((props) => {
- {module.is_favorite ? ( - - ) : ( - - )} + {isEditingAllowed && + (module.is_favorite ? ( + + ) : ( + + ))} - - - - Edit module - - - - - - Delete module - - + {isEditingAllowed && ( + <> + + + + Edit module + + + + + + Delete module + + + + )} diff --git a/web/components/pages/pages-list/list-item.tsx b/web/components/pages/pages-list/list-item.tsx index c238e4b7e..6f02f7656 100644 --- a/web/components/pages/pages-list/list-item.tsx +++ b/web/components/pages/pages-list/list-item.tsx @@ -154,6 +154,7 @@ export const PagesListItem: FC = observer((props) => { const userCanChangeAccess = isCurrentUserOwner; const userCanArchive = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN; const userCanDelete = isCurrentUserOwner || currentProjectRole === EUserWorkspaceRoles.ADMIN; + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; return ( <> @@ -208,17 +209,19 @@ export const PagesListItem: FC = observer((props) => {

{render24HourFormatTime(page.updated_at)}

)} - - {page.is_favorite ? ( - - ) : ( - - )} - + {isEditingAllowed && ( + + {page.is_favorite ? ( + + ) : ( + + )} + + )} {userCanChangeAccess && ( = observer((props) => {
)} - {userCanDelete && ( + {userCanDelete && isEditingAllowed && (
@@ -266,7 +269,7 @@ export const PagesListItem: FC = observer((props) => { ) : ( <> - {userCanEdit && ( + {userCanEdit && isEditingAllowed && (
@@ -274,7 +277,7 @@ export const PagesListItem: FC = observer((props) => {
)} - {userCanArchive && ( + {userCanArchive && isEditingAllowed && (