chore: access restriction for lower roles (#3067)

This commit is contained in:
Lakhan Baheti 2023-12-11 17:29:43 +05:30 committed by GitHub
parent f38278f465
commit 8041b23a63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 126 additions and 81 deletions

View File

@ -49,11 +49,11 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
state: "SUCCESS", state: "SUCCESS",
}); });
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Error in creating cycle. Please try again.", message: err.detail ?? "Error in creating cycle. Please try again.",
}); });
postHogEventTracker("CYCLE_CREATE", { postHogEventTracker("CYCLE_CREATE", {
state: "FAILED", state: "FAILED",
@ -73,11 +73,11 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
message: "Cycle updated successfully.", message: "Cycle updated successfully.",
}); });
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Error in updating cycle. Please try again.", message: err.detail ?? "Error in updating cycle. Please try again.",
}); });
}); });
}; };

View File

@ -21,6 +21,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EFilterType } from "store/issues/types"; import { EFilterType } from "store/issues/types";
import { EProjectStore } from "store/command-palette.store"; import { EProjectStore } from "store/command-palette.store";
import { EUserWorkspaceRoles } from "constants/workspace";
export const CycleIssuesHeader: React.FC = observer(() => { export const CycleIssuesHeader: React.FC = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
@ -42,6 +43,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
commandPalette: commandPaletteStore, commandPalette: commandPaletteStore,
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
cycleIssuesFilter: { issueFilters, updateFilters }, cycleIssuesFilter: { issueFilters, updateFilters },
user: { currentProjectRole },
} = useMobxStore(); } = useMobxStore();
const activeLayout = projectIssueFiltersStore.issueFilters?.displayFilters?.layout; const activeLayout = projectIssueFiltersStore.issueFilters?.displayFilters?.layout;
@ -99,6 +101,9 @@ export const CycleIssuesHeader: React.FC = observer(() => {
const cyclesList = cycleStore.projectCycles; const cyclesList = cycleStore.projectCycles;
const cycleDetails = cycleId ? cycleStore.getCycleById(cycleId.toString()) : undefined; const cycleDetails = cycleId ? cycleStore.getCycleById(cycleId.toString()) : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<> <>
<ProjectAnalyticsModal <ProjectAnalyticsModal
@ -190,16 +195,18 @@ export const CycleIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button {canUserCreateIssue && (
onClick={() => { <Button
setTrackElement("CYCLE_PAGE_HEADER"); onClick={() => {
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.CYCLE); setTrackElement("CYCLE_PAGE_HEADER");
}} commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.CYCLE);
size="sm" }}
prependIcon={<Plus />} size="sm"
> prependIcon={<Plus />}
Add Issue >
</Button> Add Issue
</Button>
)}
<button <button
type="button" type="button"
className="grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80" className="grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80"

View File

@ -8,6 +8,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui"; import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui";
// helpers // helpers
import { renderEmoji } from "helpers/emoji.helper"; import { renderEmoji } from "helpers/emoji.helper";
import { EUserWorkspaceRoles } from "constants/workspace";
export const CyclesHeader: FC = observer(() => { export const CyclesHeader: FC = observer(() => {
// router // router
@ -16,11 +17,15 @@ export const CyclesHeader: FC = observer(() => {
// store // store
const { const {
project: projectStore, project: projectStore,
user: { currentProjectRole },
commandPalette: commandPaletteStore, commandPalette: commandPaletteStore,
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
} = useMobxStore(); } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
const canUserCreateCycle =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4"> <div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap"> <div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
@ -50,19 +55,21 @@ export const CyclesHeader: FC = observer(() => {
</Breadcrumbs> </Breadcrumbs>
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> {canUserCreateCycle && (
<Button <div className="flex items-center gap-3">
variant="primary" <Button
size="sm" variant="primary"
prependIcon={<Plus />} size="sm"
onClick={() => { prependIcon={<Plus />}
setTrackElement("CYCLES_PAGE_HEADER"); onClick={() => {
commandPaletteStore.toggleCreateCycleModal(true); setTrackElement("CYCLES_PAGE_HEADER");
}} commandPaletteStore.toggleCreateCycleModal(true);
> }}
Add Cycle >
</Button> Add Cycle
</div> </Button>
</div>
)}
</div> </div>
); );
}); });

View File

@ -21,6 +21,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EFilterType } from "store/issues/types"; import { EFilterType } from "store/issues/types";
import { EProjectStore } from "store/command-palette.store"; import { EProjectStore } from "store/command-palette.store";
import { EUserWorkspaceRoles } from "constants/workspace";
export const ModuleIssuesHeader: React.FC = observer(() => { export const ModuleIssuesHeader: React.FC = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
@ -41,6 +42,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
projectLabel: { projectLabels }, projectLabel: { projectLabels },
moduleIssuesFilter: { issueFilters, updateFilters }, moduleIssuesFilter: { issueFilters, updateFilters },
user: { currentProjectRole },
} = useMobxStore(); } = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
@ -100,6 +102,9 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
const modulesList = projectId ? moduleStore.modules[projectId.toString()] : undefined; const modulesList = projectId ? moduleStore.modules[projectId.toString()] : undefined;
const moduleDetails = moduleId ? moduleStore.getModuleById(moduleId.toString()) : undefined; const moduleDetails = moduleId ? moduleStore.getModuleById(moduleId.toString()) : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<> <>
<ProjectAnalyticsModal <ProjectAnalyticsModal
@ -191,16 +196,18 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button {canUserCreateIssue && (
onClick={() => { <Button
setTrackElement("MODULE_PAGE_HEADER"); onClick={() => {
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.MODULE); setTrackElement("MODULE_PAGE_HEADER");
}} commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.MODULE);
size="sm" }}
prependIcon={<Plus />} size="sm"
> prependIcon={<Plus />}
Add Issue >
</Button> Add Issue
</Button>
)}
<button <button
type="button" type="button"
className="grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80" className="grid h-7 w-7 place-items-center rounded p-1 outline-none hover:bg-custom-sidebar-background-80"

View File

@ -11,17 +11,25 @@ import { Breadcrumbs, Button, Tooltip, DiceIcon } from "@plane/ui";
import { renderEmoji } from "helpers/emoji.helper"; import { renderEmoji } from "helpers/emoji.helper";
// constants // constants
import { MODULE_VIEW_LAYOUTS } from "constants/module"; import { MODULE_VIEW_LAYOUTS } from "constants/module";
import { EUserWorkspaceRoles } from "constants/workspace";
export const ModulesListHeader: React.FC = observer(() => { export const ModulesListHeader: React.FC = observer(() => {
// router // router
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store // store
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore(); const {
project: projectStore,
commandPalette: commandPaletteStore,
user: { currentProjectRole },
} = useMobxStore();
const { currentProjectDetails } = projectStore; const { currentProjectDetails } = projectStore;
const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid"); const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid");
const canUserCreateModule =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4"> <div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap"> <div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
@ -72,14 +80,16 @@ export const ModulesListHeader: React.FC = observer(() => {
</Tooltip> </Tooltip>
))} ))}
</div> </div>
<Button {canUserCreateModule && (
variant="primary" <Button
size="sm" variant="primary"
prependIcon={<Plus />} size="sm"
onClick={() => commandPaletteStore.toggleCreateModuleModal(true)} prependIcon={<Plus />}
> onClick={() => commandPaletteStore.toggleCreateModuleModal(true)}
Add Module >
</Button> Add Module
</Button>
)}
</div> </div>
</div> </div>
); );

View File

@ -18,6 +18,7 @@ import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { renderEmoji } from "helpers/emoji.helper"; import { renderEmoji } from "helpers/emoji.helper";
import { EFilterType } from "store/issues/types"; import { EFilterType } from "store/issues/types";
import { EProjectStore } from "store/command-palette.store"; import { EProjectStore } from "store/command-palette.store";
import { EUserWorkspaceRoles } from "constants/workspace";
export const ProjectIssuesHeader: React.FC = observer(() => { export const ProjectIssuesHeader: React.FC = observer(() => {
const [analyticsModal, setAnalyticsModal] = useState(false); const [analyticsModal, setAnalyticsModal] = useState(false);
@ -36,6 +37,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
// issue filters // issue filters
projectIssuesFilter: { issueFilters, updateFilters }, projectIssuesFilter: { issueFilters, updateFilters },
projectIssues: {}, projectIssues: {},
user: { currentProjectRole },
} = useMobxStore(); } = useMobxStore();
const activeLayout = issueFilters?.displayFilters?.layout; const activeLayout = issueFilters?.displayFilters?.layout;
@ -87,6 +89,9 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
const deployUrl = process.env.NEXT_PUBLIC_DEPLOY_URL; const deployUrl = process.env.NEXT_PUBLIC_DEPLOY_URL;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<> <>
<ProjectAnalyticsModal <ProjectAnalyticsModal
@ -200,16 +205,18 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm"> <Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
Analytics Analytics
</Button> </Button>
<Button {canUserCreateIssue && (
onClick={() => { <Button
setTrackElement("PROJECT_PAGE_HEADER"); onClick={() => {
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT); setTrackElement("PROJECT_PAGE_HEADER");
}} commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
size="sm" }}
prependIcon={<Plus />} size="sm"
> prependIcon={<Plus />}
Add Issue >
</Button> Add Issue
</Button>
)}
</div> </div>
</div> </div>
</> </>

View File

@ -1,6 +1,7 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Plus } from "lucide-react";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// components // components
@ -16,7 +17,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EFilterType } from "store/issues/types"; import { EFilterType } from "store/issues/types";
import { EProjectStore } from "store/command-palette.store"; import { EProjectStore } from "store/command-palette.store";
import { Plus } from "lucide-react"; import { EUserWorkspaceRoles } from "constants/workspace";
export const ProjectViewIssuesHeader: React.FC = observer(() => { export const ProjectViewIssuesHeader: React.FC = observer(() => {
const router = useRouter(); const router = useRouter();
@ -35,6 +36,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
viewIssuesFilter: { issueFilters, updateFilters }, viewIssuesFilter: { issueFilters, updateFilters },
commandPalette: commandPaletteStore, commandPalette: commandPaletteStore,
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
user: { currentProjectRole },
} = useMobxStore(); } = useMobxStore();
const activeLayout = issueFilters?.displayFilters?.layout; const activeLayout = issueFilters?.displayFilters?.layout;
@ -85,6 +87,9 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined; const viewsList = projectId ? projectViewsStore.viewsList[projectId.toString()] : undefined;
const viewDetails = viewId ? projectViewsStore.viewDetails[viewId.toString()] : undefined; const viewDetails = viewId ? projectViewsStore.viewDetails[viewId.toString()] : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole);
return ( return (
<div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4"> <div className="relative z-10 flex h-[3.75rem] w-full items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -170,16 +175,18 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
handleDisplayPropertiesUpdate={handleDisplayProperties} handleDisplayPropertiesUpdate={handleDisplayProperties}
/> />
</FiltersDropdown> </FiltersDropdown>
<Button {
onClick={() => { <Button
setTrackElement("PROJECT_VIEW_PAGE_HEADER"); onClick={() => {
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT_VIEW); setTrackElement("PROJECT_VIEW_PAGE_HEADER");
}} commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT_VIEW);
size="sm" }}
prependIcon={<Plus />} size="sm"
> prependIcon={<Plus />}
Add Issue >
</Button> Add Issue
</Button>
}
</div> </div>
</div> </div>
); );

View File

@ -266,11 +266,11 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
} }
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Issue could not be created. Please try again.", message: err.detail ?? "Issue could not be created. Please try again.",
}); });
postHogEventTracker( postHogEventTracker(
"ISSUE_CREATED", "ISSUE_CREATED",
@ -312,11 +312,11 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Issue could not be created. Please try again.", message: err.detail ?? "Issue could not be created. Please try again.",
}); });
}); });
}; };
@ -347,11 +347,11 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
} }
); );
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Issue could not be updated. Please try again.", message: err.detail ?? "Issue could not be updated. Please try again.",
}); });
postHogEventTracker( postHogEventTracker(
"ISSUE_UPDATED", "ISSUE_UPDATED",

View File

@ -69,11 +69,11 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
state: "SUCCESS", state: "SUCCESS",
}); });
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Module could not be created. Please try again.", message: err.detail ?? "Module could not be created. Please try again.",
}); });
postHogEventTracker("MODULE_CREATED", { postHogEventTracker("MODULE_CREATED", {
state: "FAILED", state: "FAILED",
@ -99,11 +99,11 @@ export const CreateUpdateModuleModal: React.FC<Props> = observer((props) => {
state: "SUCCESS", state: "SUCCESS",
}); });
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Module could not be updated. Please try again.", message: err.detail ?? "Module could not be updated. Please try again.",
}); });
postHogEventTracker("MODULE_UPDATED", { postHogEventTracker("MODULE_UPDATED", {
state: "FAILED", state: "FAILED",

View File

@ -60,11 +60,11 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
} }
); );
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Page could not be created. Please try again.", message: err.detail ?? "Page could not be created. Please try again.",
}); });
postHogEventTracker( postHogEventTracker(
"PAGE_CREATED", "PAGE_CREATED",
@ -104,11 +104,11 @@ export const CreateUpdatePageModal: FC<Props> = (props) => {
} }
); );
}) })
.catch(() => { .catch((err) => {
setToastAlert({ setToastAlert({
type: "error", type: "error",
title: "Error!", title: "Error!",
message: "Page could not be updated. Please try again.", message: err.detail ?? "Page could not be updated. Please try again.",
}); });
postHogEventTracker( postHogEventTracker(
"PAGE_UPDATED", "PAGE_UPDATED",