forked from github/plane
fix: Permission levels for project settings (#2978)
* fix add subgroup issue FED-1101 * fix subgroup by None assignee FED-1100 * fix grouping by asignee or labels FED-1096 * fix create view popup FED-1093 * fix subgroup exception in swimlanes * fix show sub issue filter FED-1102 * use Enums instead of numbers * fix Estimates setting permission for admin * disable access to project settings for viewers and guests * fix project unautorized flicker * add observer to estimates * add permissions to member list
This commit is contained in:
parent
199357560d
commit
657d8e97da
@ -11,6 +11,7 @@ import { ArchiveRestore } from "lucide-react";
|
|||||||
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
||||||
// types
|
// types
|
||||||
import { IProject } from "types";
|
import { IProject } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
||||||
@ -28,6 +29,8 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
|||||||
const projectDetails = projectStore.currentProjectDetails;
|
const projectDetails = projectStore.currentProjectDetails;
|
||||||
const userRole = userStore.currentProjectRole;
|
const userRole = userStore.currentProjectRole;
|
||||||
|
|
||||||
|
const isAdmin = userRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SelectMonthModal
|
<SelectMonthModal
|
||||||
@ -56,7 +59,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
|||||||
projectDetails?.archive_in === 0 ? handleChange({ archive_in: 1 }) : handleChange({ archive_in: 0 })
|
projectDetails?.archive_in === 0 ? handleChange({ archive_in: 1 }) : handleChange({ archive_in: 0 })
|
||||||
}
|
}
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={userRole !== 20}
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -74,7 +77,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
input
|
input
|
||||||
width="w-full"
|
width="w-full"
|
||||||
disabled={userRole !== 20}
|
disabled={!isAdmin}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
||||||
|
@ -11,6 +11,7 @@ import { ArchiveX } from "lucide-react";
|
|||||||
import { IProject } from "types";
|
import { IProject } from "types";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
||||||
@ -53,6 +54,8 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
|||||||
default_state: defaultState,
|
default_state: defaultState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAdmin = userRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SelectMonthModal
|
<SelectMonthModal
|
||||||
@ -83,7 +86,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
|||||||
: handleChange({ close_in: 0, default_state: null })
|
: handleChange({ close_in: 0, default_state: null })
|
||||||
}
|
}
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={userRole !== 20}
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -102,7 +105,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
input
|
input
|
||||||
width="w-full"
|
width="w-full"
|
||||||
disabled={userRole !== 20}
|
disabled={!isAdmin}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
||||||
|
@ -22,6 +22,7 @@ import { Button } from "@plane/ui";
|
|||||||
import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Inbox, Trash2, XCircle } from "lucide-react";
|
import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Inbox, Trash2, XCircle } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import type { TInboxStatus } from "types";
|
import type { TInboxStatus } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export const InboxActionsHeader = observer(() => {
|
export const InboxActionsHeader = observer(() => {
|
||||||
const [date, setDate] = useState(new Date());
|
const [date, setDate] = useState(new Date());
|
||||||
@ -71,7 +72,7 @@ export const InboxActionsHeader = observer(() => {
|
|||||||
}, [issue]);
|
}, [issue]);
|
||||||
|
|
||||||
const issueStatus = issue?.issue_inbox[0].status;
|
const issueStatus = issue?.issue_inbox[0].status;
|
||||||
const isAllowed = userRole === 15 || userRole === 20;
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const tomorrow = new Date(today);
|
const tomorrow = new Date(today);
|
||||||
|
@ -16,6 +16,7 @@ import { Loader } from "@plane/ui";
|
|||||||
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IInboxIssue, IIssue } from "types";
|
import { IInboxIssue, IIssue } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const defaultValues: Partial<IInboxIssue> = {
|
const defaultValues: Partial<IInboxIssue> = {
|
||||||
name: "",
|
name: "",
|
||||||
@ -144,6 +145,8 @@ export const InboxMainContent: React.FC = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{issueDetails ? (
|
{issueDetails ? (
|
||||||
@ -222,7 +225,7 @@ export const InboxMainContent: React.FC = observer(() => {
|
|||||||
description_html: issueDetails.description_html,
|
description_html: issueDetails.description_html,
|
||||||
}}
|
}}
|
||||||
handleFormSubmit={submitChanges}
|
handleFormSubmit={submitChanges}
|
||||||
isAllowed={userRole === 15 || userRole === 20 || user?.id === issueDetails.created_by}
|
isAllowed={isAllowed || user?.id === issueDetails.created_by}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
IViewIssuesStore,
|
IViewIssuesStore,
|
||||||
} from "store/issues";
|
} from "store/issues";
|
||||||
import { TUnGroupedIssues } from "store/issues/types";
|
import { TUnGroupedIssues } from "store/issues/types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
interface IBaseGanttRoot {
|
interface IBaseGanttRoot {
|
||||||
issueFiltersStore:
|
issueFiltersStore:
|
||||||
@ -69,7 +70,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAllowed = currentProjectRole && currentProjectRole >= 15;
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -31,6 +31,7 @@ import { KanBan } from "./default";
|
|||||||
import { KanBanSwimLanes } from "./swimlanes";
|
import { KanBanSwimLanes } from "./swimlanes";
|
||||||
import { EProjectStore } from "store/command-palette.store";
|
import { EProjectStore } from "store/command-palette.store";
|
||||||
import { IssuePeekOverview } from "components/issues";
|
import { IssuePeekOverview } from "components/issues";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export interface IBaseKanBanLayout {
|
export interface IBaseKanBanLayout {
|
||||||
issueStore:
|
issueStore:
|
||||||
@ -93,7 +94,7 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
|||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const issues = issueStore?.getIssues || {};
|
const issues = issueStore?.getIssues || {};
|
||||||
const issueIds = issueStore?.getIssuesIds || [];
|
const issueIds = issueStore?.getIssuesIds || [];
|
||||||
|
@ -25,6 +25,7 @@ import { IIssueResponse } from "store/issues/types";
|
|||||||
import { EProjectStore } from "store/command-palette.store";
|
import { EProjectStore } from "store/command-palette.store";
|
||||||
import { IssuePeekOverview } from "components/issues";
|
import { IssuePeekOverview } from "components/issues";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
enum EIssueActions {
|
enum EIssueActions {
|
||||||
UPDATE = "update",
|
UPDATE = "update",
|
||||||
@ -83,7 +84,7 @@ export const BaseListRoot = observer((props: IBaseListRoot) => {
|
|||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const issueIds = issueStore?.getIssuesIds || [];
|
const issueIds = issueStore?.getIssuesIds || [];
|
||||||
const issues = issueStore?.getIssues;
|
const issues = issueStore?.getIssues;
|
||||||
|
@ -18,6 +18,7 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { EFilterType, TUnGroupedIssues } from "store/issues/types";
|
import { EFilterType, TUnGroupedIssues } from "store/issues/types";
|
||||||
import { EIssueActions } from "../types";
|
import { EIssueActions } from "../types";
|
||||||
import { IQuickActionProps } from "../list/list-view-types";
|
import { IQuickActionProps } from "../list/list-view-types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
interface IBaseSpreadsheetRoot {
|
interface IBaseSpreadsheetRoot {
|
||||||
issueFiltersStore:
|
issueFiltersStore:
|
||||||
@ -49,7 +50,7 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
|
|||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const issuesResponse = issueStore.getIssues;
|
const issuesResponse = issueStore.getIssues;
|
||||||
const issueIds = (issueStore.getIssuesIds ?? []) as TUnGroupedIssues;
|
const issueIds = (issueStore.getIssuesIds ?? []) as TUnGroupedIssues;
|
||||||
|
@ -14,6 +14,7 @@ import { IIssue } from "types";
|
|||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
|||||||
// store
|
// store
|
||||||
const { user: userStore } = useMobxStore();
|
const { user: userStore } = useMobxStore();
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isAllowed = [15, 20].includes(currentProjectRole || 0);
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
// states
|
// states
|
||||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||||
const [characterLimit, setCharacterLimit] = useState(false);
|
const [characterLimit, setCharacterLimit] = useState(false);
|
||||||
|
@ -12,6 +12,7 @@ import { IssueView } from "./view";
|
|||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
interface IIssuePeekOverview {
|
interface IIssuePeekOverview {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -118,7 +119,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const userRole = userStore.currentProjectRole ?? 5;
|
const userRole = userStore.currentProjectRole ?? EUserWorkspaceRoles.GUEST;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
@ -26,6 +26,7 @@ import { MinusCircle } from "lucide-react";
|
|||||||
import { IIssue, IIssueComment } from "types";
|
import { IIssue, IIssueComment } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUES_ACTIVITY, SUB_ISSUES } from "constants/fetch-keys";
|
import { PROJECT_ISSUES_ACTIVITY, SUB_ISSUES } from "constants/fetch-keys";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issueDetails: IIssue;
|
issueDetails: IIssue;
|
||||||
@ -100,6 +101,8 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rounded-lg">
|
<div className="rounded-lg">
|
||||||
@ -166,7 +169,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
workspaceSlug={workspaceSlug as string}
|
workspaceSlug={workspaceSlug as string}
|
||||||
issue={issueDetails}
|
issue={issueDetails}
|
||||||
handleFormSubmit={submitChanges}
|
handleFormSubmit={submitChanges}
|
||||||
isAllowed={userRole === 20 || userRole === 15 || !uneditable}
|
isAllowed={isAllowed || !uneditable}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IssueReaction workspaceSlug={workspaceSlug} issueId={issueId} projectId={projectId} />
|
<IssueReaction workspaceSlug={workspaceSlug} issueId={issueId} projectId={projectId} />
|
||||||
|
@ -40,6 +40,7 @@ import { copyTextToClipboard } from "helpers/string.helper";
|
|||||||
import type { IIssue, IIssueLink, linkDetails } from "types";
|
import type { IIssue, IIssueLink, linkDetails } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
control: any;
|
control: any;
|
||||||
@ -245,7 +246,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
setLinkModal(true);
|
setLinkModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNotAllowed = userRole === 5 || userRole === 10;
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -295,7 +296,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<LinkIcon className="h-3.5 w-3.5" />
|
<LinkIcon className="h-3.5 w-3.5" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{!isNotAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
{isAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-500/20 focus:outline-none"
|
className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-500/20 focus:outline-none"
|
||||||
@ -325,7 +326,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarStateSelect
|
<SidebarStateSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: string) => submitChanges({ state: val })}
|
onChange={(val: string) => submitChanges({ state: val })}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -346,7 +347,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarAssigneeSelect
|
<SidebarAssigneeSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: string[]) => submitChanges({ assignees: val })}
|
onChange={(val: string[]) => submitChanges({ assignees: val })}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -367,7 +368,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarPrioritySelect
|
<SidebarPrioritySelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val) => submitChanges({ priority: val })}
|
onChange={(val) => submitChanges({ priority: val })}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -388,7 +389,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarEstimateSelect
|
<SidebarEstimateSelect
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(val: number | null) => submitChanges({ estimate_point: val })}
|
onChange={(val: number | null) => submitChanges({ estimate_point: val })}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -416,7 +417,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
onChange(val);
|
onChange(val);
|
||||||
}}
|
}}
|
||||||
issueDetails={issueDetail}
|
issueDetails={issueDetail}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -441,7 +442,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && (
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && (
|
||||||
@ -462,7 +463,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("duplicate")) && (
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("duplicate")) && (
|
||||||
@ -480,7 +481,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("relates_to")) && (
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("relates_to")) && (
|
||||||
@ -498,7 +499,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && (
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && (
|
||||||
@ -522,7 +523,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
}
|
}
|
||||||
className="bg-custom-background-80 border-none"
|
className="bg-custom-background-80 border-none"
|
||||||
maxDate={maxDate ?? undefined}
|
maxDate={maxDate ?? undefined}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -550,7 +551,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
}
|
}
|
||||||
className="bg-custom-background-80 border-none"
|
className="bg-custom-background-80 border-none"
|
||||||
minDate={minDate ?? undefined}
|
minDate={minDate ?? undefined}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -571,7 +572,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarCycleSelect
|
<SidebarCycleSelect
|
||||||
issueDetail={issueDetail}
|
issueDetail={issueDetail}
|
||||||
handleCycleChange={handleCycleChange}
|
handleCycleChange={handleCycleChange}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -586,7 +587,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<SidebarModuleSelect
|
<SidebarModuleSelect
|
||||||
issueDetail={issueDetail}
|
issueDetail={issueDetail}
|
||||||
handleModuleChange={handleModuleChange}
|
handleModuleChange={handleModuleChange}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -605,7 +606,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
issueDetails={issueDetail}
|
issueDetails={issueDetail}
|
||||||
labelList={issueDetail?.labels ?? []}
|
labelList={issueDetail?.labels ?? []}
|
||||||
submitChanges={submitChanges}
|
submitChanges={submitChanges}
|
||||||
isNotAllowed={isNotAllowed}
|
isNotAllowed={!isAllowed}
|
||||||
uneditable={uneditable ?? false}
|
uneditable={uneditable ?? false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -615,7 +616,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<div className={`min-h-[116px] py-1 text-xs ${uneditable ? "opacity-60" : ""}`}>
|
<div className={`min-h-[116px] py-1 text-xs ${uneditable ? "opacity-60" : ""}`}>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<h4>Links</h4>
|
<h4>Links</h4>
|
||||||
{!isNotAllowed && (
|
{isAllowed && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-custom-background-90 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-custom-background-90 ${
|
||||||
|
@ -22,6 +22,7 @@ import { IUser, IIssue, ISearchIssueResponse } from "types";
|
|||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { SUB_ISSUES } from "constants/fetch-keys";
|
import { SUB_ISSUES } from "constants/fetch-keys";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export interface ISubIssuesRoot {
|
export interface ISubIssuesRoot {
|
||||||
parentIssue: IIssue;
|
parentIssue: IIssue;
|
||||||
@ -176,7 +177,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
|
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const isEditable = userRole === 5 || userRole === 10 ? false : true;
|
const isEditable = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const mutateSubIssues = (parentIssueId: string | null) => {
|
const mutateSubIssues = (parentIssueId: string | null) => {
|
||||||
if (parentIssueId) mutate(SUB_ISSUES(parentIssueId));
|
if (parentIssueId) mutate(SUB_ISSUES(parentIssueId));
|
||||||
|
@ -33,6 +33,7 @@ import { linkDetails, IModule, ModuleLink } from "types";
|
|||||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||||
// constant
|
// constant
|
||||||
import { MODULE_STATUS } from "constants/module";
|
import { MODULE_STATUS } from "constants/module";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const defaultValues: Partial<IModule> = {
|
const defaultValues: Partial<IModule> = {
|
||||||
lead: "",
|
lead: "",
|
||||||
@ -588,10 +589,10 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
handleEditLink={handleEditLink}
|
handleEditLink={handleEditLink}
|
||||||
handleDeleteLink={handleDeleteLink}
|
handleDeleteLink={handleDeleteLink}
|
||||||
userAuth={{
|
userAuth={{
|
||||||
isGuest: userRole === 5,
|
isGuest: userRole === EUserWorkspaceRoles.GUEST,
|
||||||
isViewer: userRole === 10,
|
isViewer: userRole === EUserWorkspaceRoles.VIEWER,
|
||||||
isMember: userRole === 15,
|
isMember: userRole === EUserWorkspaceRoles.MEMBER,
|
||||||
isOwner: userRole === 20,
|
isOwner: userRole === EUserWorkspaceRoles.ADMIN,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -26,6 +26,7 @@ import { CustomMenu, Tooltip } from "@plane/ui";
|
|||||||
import { CreateUpdatePageModal, DeletePageModal } from "components/pages";
|
import { CreateUpdatePageModal, DeletePageModal } from "components/pages";
|
||||||
// types
|
// types
|
||||||
import { IPage } from "types";
|
import { IPage } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export interface IPagesListItem {
|
export interface IPagesListItem {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -144,7 +145,7 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
|||||||
setCreateUpdatePageModal(true);
|
setCreateUpdatePageModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const userCanEdit = currentProjectRole === 15 || currentProjectRole === 20;
|
const userCanEdit = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -13,7 +13,7 @@ import { CustomSelect, Tooltip } from "@plane/ui";
|
|||||||
// icons
|
// icons
|
||||||
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { ROLE } from "constants/workspace";
|
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
|
||||||
// types
|
// types
|
||||||
import { IProjectMember, TUserProjectRole } from "types";
|
import { IProjectMember, TUserProjectRole } from "types";
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
|||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
// derived values
|
// derived values
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
const memberDetails = member.member;
|
const memberDetails = member.member;
|
||||||
|
|
||||||
const handleRemove = async () => {
|
const handleRemove = async () => {
|
||||||
@ -148,12 +148,13 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
|||||||
disabled={
|
disabled={
|
||||||
memberDetails.id === currentUser?.id ||
|
memberDetails.id === currentUser?.id ||
|
||||||
!member.member ||
|
!member.member ||
|
||||||
(currentProjectRole && currentProjectRole !== 20 && currentProjectRole < member.role)
|
!currentProjectRole ||
|
||||||
|
currentProjectRole < member.role
|
||||||
}
|
}
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
>
|
>
|
||||||
{Object.keys(ROLE).map((key) => {
|
{Object.keys(ROLE).map((key) => {
|
||||||
if (currentProjectRole && currentProjectRole !== 20 && currentProjectRole < parseInt(key)) return null;
|
if (currentProjectRole && !isAdmin && currentProjectRole < parseInt(key)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomSelect.Option key={key} value={parseInt(key, 10)}>
|
<CustomSelect.Option key={key} value={parseInt(key, 10)}>
|
||||||
|
@ -15,6 +15,7 @@ import { Loader } from "@plane/ui";
|
|||||||
import { IProject, IUserLite, IWorkspace } from "types";
|
import { IProject, IUserLite, IWorkspace } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const defaultValues: Partial<IProject> = {
|
const defaultValues: Partial<IProject> = {
|
||||||
project_lead: null,
|
project_lead: null,
|
||||||
@ -29,7 +30,7 @@ export const ProjectSettingsMemberDefaults: React.FC = observer(() => {
|
|||||||
const { user: userStore, project: projectStore } = useMobxStore();
|
const { user: userStore, project: projectStore } = useMobxStore();
|
||||||
const { currentProjectDetails } = projectStore;
|
const { currentProjectDetails } = projectStore;
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// form info
|
// form info
|
||||||
|
@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
|
|||||||
// types
|
// types
|
||||||
import { IProjectMember, TUserProjectRole } from "types";
|
import { IProjectMember, TUserProjectRole } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { ROLE } from "constants/workspace";
|
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -246,7 +246,8 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
|||||||
width="w-full"
|
width="w-full"
|
||||||
>
|
>
|
||||||
{Object.entries(ROLE).map(([key, label]) => {
|
{Object.entries(ROLE).map(([key, label]) => {
|
||||||
if (parseInt(key) > (currentProjectRole ?? 5)) return null;
|
if (parseInt(key) > (currentProjectRole ?? EUserWorkspaceRoles.GUEST))
|
||||||
|
return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomSelect.Option key={key} value={key}>
|
<CustomSelect.Option key={key} value={key}>
|
||||||
|
@ -9,6 +9,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// types
|
// types
|
||||||
import { IProject } from "types";
|
import { IProject } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
user: { currentUser, currentProjectRole },
|
user: { currentUser, currentProjectRole },
|
||||||
trackEvent: { setTrackElement, postHogEventTracker },
|
trackEvent: { setTrackElement, postHogEventTracker },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
project_id: currentProjectDetails?.id,
|
project_id: currentProjectDetails?.id,
|
||||||
project_name: currentProjectDetails?.name,
|
project_name: currentProjectDetails?.name,
|
||||||
project_identifier: currentProjectDetails?.identifier,
|
project_identifier: currentProjectDetails?.identifier,
|
||||||
enabled: !currentProjectDetails?.[feature.property as keyof IProject]
|
enabled: !currentProjectDetails?.[feature.property as keyof IProject],
|
||||||
});
|
});
|
||||||
handleSubmit({
|
handleSubmit({
|
||||||
[feature.property]: !currentProjectDetails?.[feature.property as keyof IProject],
|
[feature.property]: !currentProjectDetails?.[feature.property as keyof IProject],
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
export const getUserRole = (role: number) => {
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
|
export const getUserRole = (role: EUserWorkspaceRoles) => {
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case 5:
|
case EUserWorkspaceRoles.GUEST:
|
||||||
return "GUEST";
|
return "GUEST";
|
||||||
case 10:
|
case EUserWorkspaceRoles.VIEWER:
|
||||||
return "VIEWER";
|
return "VIEWER";
|
||||||
case 15:
|
case EUserWorkspaceRoles.MEMBER:
|
||||||
return "MEMBER";
|
return "MEMBER";
|
||||||
case 20:
|
case EUserWorkspaceRoles.ADMIN:
|
||||||
return "ADMIN";
|
return "ADMIN";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
import { FC, ReactNode } from "react";
|
import { FC, ReactNode } from "react";
|
||||||
// components
|
// components
|
||||||
import { ProjectSettingsSidebar } from "./sidebar";
|
import { ProjectSettingsSidebar } from "./sidebar";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
import { NotAuthorizedView } from "components/auth-screens";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
export interface IProjectSettingLayout {
|
export interface IProjectSettingLayout {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProjectSettingLayout: FC<IProjectSettingLayout> = (props) => {
|
export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props) => {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
|
|
||||||
return (
|
const {
|
||||||
|
user: { currentProjectRole },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
|
const restrictViewSettings = currentProjectRole && currentProjectRole <= EUserWorkspaceRoles.VIEWER;
|
||||||
|
|
||||||
|
return restrictViewSettings ? (
|
||||||
|
<NotAuthorizedView type="project" />
|
||||||
|
) : (
|
||||||
<div className="flex gap-2 h-full w-full overflow-x-hidden overflow-y-scroll">
|
<div className="flex gap-2 h-full w-full overflow-x-hidden overflow-y-scroll">
|
||||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||||
<ProjectSettingsSidebar />
|
<ProjectSettingsSidebar />
|
||||||
@ -17,4 +29,4 @@ export const ProjectSettingLayout: FC<IProjectSettingLayout> = (props) => {
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -14,6 +14,7 @@ import { ProjectSettingHeader } from "components/headers";
|
|||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "types/app";
|
import { NextPageWithLayout } from "types/app";
|
||||||
import { IProject } from "types";
|
import { IProject } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const AutomationSettingsPage: NextPageWithLayout = observer(() => {
|
const AutomationSettingsPage: NextPageWithLayout = observer(() => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -39,7 +40,7 @@ const AutomationSettingsPage: NextPageWithLayout = observer(() => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||||
|
@ -7,12 +7,23 @@ import { ProjectSettingHeader } from "components/headers";
|
|||||||
import { EstimatesList } from "components/estimates";
|
import { EstimatesList } from "components/estimates";
|
||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "types/app";
|
import { NextPageWithLayout } from "types/app";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
const EstimatesSettingsPage: NextPageWithLayout = () => (
|
const EstimatesSettingsPage: NextPageWithLayout = observer(() => {
|
||||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
const {
|
||||||
|
user: { currentProjectRole },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
|
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60 pointer-events-none"}`}>
|
||||||
<EstimatesList />
|
<EstimatesList />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
return (
|
return (
|
||||||
|
@ -5,6 +5,7 @@ import { RootStore } from "../root";
|
|||||||
import { InboxService } from "services/inbox.service";
|
import { InboxService } from "services/inbox.service";
|
||||||
// types
|
// types
|
||||||
import { IInbox, IInboxFilterOptions, IInboxQueryParams } from "types";
|
import { IInbox, IInboxFilterOptions, IInboxQueryParams } from "types";
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export interface IInboxFiltersStore {
|
export interface IInboxFiltersStore {
|
||||||
// states
|
// states
|
||||||
@ -132,8 +133,8 @@ export class InboxFiltersStore implements IInboxFiltersStore {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const userRole = this.rootStore.user?.projectMemberInfo?.[projectId]?.role || 0;
|
const userRole = this.rootStore.user?.currentProjectRole || EUserWorkspaceRoles.GUEST;
|
||||||
if (userRole > 10) {
|
if (userRole > EUserWorkspaceRoles.VIEWER) {
|
||||||
await this.inboxService.patchInbox(workspaceSlug, projectId, inboxId, { view_props: newViewProps });
|
await this.inboxService.patchInbox(workspaceSlug, projectId, inboxId, { view_props: newViewProps });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user