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
b527ec582f
commit
8a8eea38f9
@ -11,6 +11,7 @@ import { ArchiveRestore } from "lucide-react";
|
||||
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
type Props = {
|
||||
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
||||
@ -28,6 +29,8 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
||||
const projectDetails = projectStore.currentProjectDetails;
|
||||
const userRole = userStore.currentProjectRole;
|
||||
|
||||
const isAdmin = userRole === EUserWorkspaceRoles.ADMIN;
|
||||
|
||||
return (
|
||||
<>
|
||||
<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 })
|
||||
}
|
||||
size="sm"
|
||||
disabled={userRole !== 20}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -74,7 +77,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
|
||||
}}
|
||||
input
|
||||
width="w-full"
|
||||
disabled={userRole !== 20}
|
||||
disabled={!isAdmin}
|
||||
>
|
||||
<>
|
||||
{PROJECT_AUTOMATION_MONTHS.map((month) => (
|
||||
|
@ -11,6 +11,7 @@ import { ArchiveX } from "lucide-react";
|
||||
import { IProject } from "types";
|
||||
// fetch keys
|
||||
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
type Props = {
|
||||
handleChange: (formData: Partial<IProject>) => Promise<void>;
|
||||
@ -53,6 +54,8 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
||||
default_state: defaultState,
|
||||
};
|
||||
|
||||
const isAdmin = userRole === EUserWorkspaceRoles.ADMIN;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SelectMonthModal
|
||||
@ -83,7 +86,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
||||
: handleChange({ close_in: 0, default_state: null })
|
||||
}
|
||||
size="sm"
|
||||
disabled={userRole !== 20}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -102,7 +105,7 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
|
||||
}}
|
||||
input
|
||||
width="w-full"
|
||||
disabled={userRole !== 20}
|
||||
disabled={!isAdmin}
|
||||
>
|
||||
<>
|
||||
{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";
|
||||
// types
|
||||
import type { TInboxStatus } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
export const InboxActionsHeader = observer(() => {
|
||||
const [date, setDate] = useState(new Date());
|
||||
@ -71,7 +72,7 @@ export const InboxActionsHeader = observer(() => {
|
||||
}, [issue]);
|
||||
|
||||
const issueStatus = issue?.issue_inbox[0].status;
|
||||
const isAllowed = userRole === 15 || userRole === 20;
|
||||
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const today = new Date();
|
||||
const tomorrow = new Date(today);
|
||||
|
@ -16,6 +16,7 @@ import { Loader } from "@plane/ui";
|
||||
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { IInboxIssue, IIssue } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
const defaultValues: Partial<IInboxIssue> = {
|
||||
name: "",
|
||||
@ -144,6 +145,8 @@ export const InboxMainContent: React.FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
|
||||
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
return (
|
||||
<>
|
||||
{issueDetails ? (
|
||||
@ -222,7 +225,7 @@ export const InboxMainContent: React.FC = observer(() => {
|
||||
description_html: issueDetails.description_html,
|
||||
}}
|
||||
handleFormSubmit={submitChanges}
|
||||
isAllowed={userRole === 15 || userRole === 20 || user?.id === issueDetails.created_by}
|
||||
isAllowed={isAllowed || user?.id === issueDetails.created_by}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
IViewIssuesStore,
|
||||
} from "store/issues";
|
||||
import { TUnGroupedIssues } from "store/issues/types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
interface IBaseGanttRoot {
|
||||
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 (
|
||||
<>
|
||||
|
@ -31,6 +31,7 @@ import { KanBan } from "./default";
|
||||
import { KanBanSwimLanes } from "./swimlanes";
|
||||
import { EProjectStore } from "store/command-palette.store";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
export interface IBaseKanBanLayout {
|
||||
issueStore:
|
||||
@ -93,7 +94,7 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
||||
} = useMobxStore();
|
||||
|
||||
const { currentProjectRole } = userStore;
|
||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const issues = issueStore?.getIssues || {};
|
||||
const issueIds = issueStore?.getIssuesIds || [];
|
||||
|
@ -25,6 +25,7 @@ import { IIssueResponse } from "store/issues/types";
|
||||
import { EProjectStore } from "store/command-palette.store";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
import { useRouter } from "next/router";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
enum EIssueActions {
|
||||
UPDATE = "update",
|
||||
@ -83,7 +84,7 @@ export const BaseListRoot = observer((props: IBaseListRoot) => {
|
||||
} = useMobxStore();
|
||||
|
||||
const { currentProjectRole } = userStore;
|
||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const issueIds = issueStore?.getIssuesIds || [];
|
||||
const issues = issueStore?.getIssues;
|
||||
|
@ -18,6 +18,7 @@ import { observer } from "mobx-react-lite";
|
||||
import { EFilterType, TUnGroupedIssues } from "store/issues/types";
|
||||
import { EIssueActions } from "../types";
|
||||
import { IQuickActionProps } from "../list/list-view-types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
interface IBaseSpreadsheetRoot {
|
||||
issueFiltersStore:
|
||||
@ -49,7 +50,7 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
|
||||
} = useMobxStore();
|
||||
|
||||
const { currentProjectRole } = userStore;
|
||||
const isEditingAllowed = [15, 20].includes(currentProjectRole || 0);
|
||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const issuesResponse = issueStore.getIssues;
|
||||
const issueIds = (issueStore.getIssuesIds ?? []) as TUnGroupedIssues;
|
||||
|
@ -14,6 +14,7 @@ import { IIssue } from "types";
|
||||
// services
|
||||
import { FileService } from "services/file.service";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
const fileService = new FileService();
|
||||
|
||||
@ -32,7 +33,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
||||
// store
|
||||
const { user: userStore } = useMobxStore();
|
||||
const { currentProjectRole } = userStore;
|
||||
const isAllowed = [15, 20].includes(currentProjectRole || 0);
|
||||
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
// states
|
||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||
const [characterLimit, setCharacterLimit] = useState(false);
|
||||
|
@ -12,6 +12,7 @@ import { IssueView } from "./view";
|
||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
interface IIssuePeekOverview {
|
||||
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 (
|
||||
<Fragment>
|
||||
|
@ -26,6 +26,7 @@ import { MinusCircle } from "lucide-react";
|
||||
import { IIssue, IIssueComment } from "types";
|
||||
// fetch-keys
|
||||
import { PROJECT_ISSUES_ACTIVITY, SUB_ISSUES } from "constants/fetch-keys";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
type Props = {
|
||||
issueDetails: IIssue;
|
||||
@ -100,6 +101,8 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rounded-lg">
|
||||
@ -166,7 +169,7 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
||||
workspaceSlug={workspaceSlug as string}
|
||||
issue={issueDetails}
|
||||
handleFormSubmit={submitChanges}
|
||||
isAllowed={userRole === 20 || userRole === 15 || !uneditable}
|
||||
isAllowed={isAllowed || !uneditable}
|
||||
/>
|
||||
|
||||
<IssueReaction workspaceSlug={workspaceSlug} issueId={issueId} projectId={projectId} />
|
||||
|
@ -40,6 +40,7 @@ import { copyTextToClipboard } from "helpers/string.helper";
|
||||
import type { IIssue, IIssueLink, linkDetails } from "types";
|
||||
// fetch-keys
|
||||
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
type Props = {
|
||||
control: any;
|
||||
@ -245,7 +246,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
setLinkModal(true);
|
||||
};
|
||||
|
||||
const isNotAllowed = userRole === 5 || userRole === 10;
|
||||
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -295,7 +296,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
<LinkIcon className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
)}
|
||||
{!isNotAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
||||
{isAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && (
|
||||
<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"
|
||||
@ -325,7 +326,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
<SidebarStateSelect
|
||||
value={value}
|
||||
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
|
||||
value={value}
|
||||
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
|
||||
value={value}
|
||||
onChange={(val) => submitChanges({ priority: val })}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -388,7 +389,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
<SidebarEstimateSelect
|
||||
value={value}
|
||||
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);
|
||||
}}
|
||||
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));
|
||||
}}
|
||||
watch={watchIssue}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
{(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));
|
||||
}}
|
||||
watch={watchIssue}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
{(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));
|
||||
}}
|
||||
watch={watchIssue}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
{(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));
|
||||
}}
|
||||
watch={watchIssue}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
{(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"
|
||||
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"
|
||||
minDate={minDate ?? undefined}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -571,7 +572,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
<SidebarCycleSelect
|
||||
issueDetail={issueDetail}
|
||||
handleCycleChange={handleCycleChange}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -586,7 +587,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
<SidebarModuleSelect
|
||||
issueDetail={issueDetail}
|
||||
handleModuleChange={handleModuleChange}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
disabled={!isAllowed || uneditable}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -605,7 +606,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
issueDetails={issueDetail}
|
||||
labelList={issueDetail?.labels ?? []}
|
||||
submitChanges={submitChanges}
|
||||
isNotAllowed={isNotAllowed}
|
||||
isNotAllowed={!isAllowed}
|
||||
uneditable={uneditable ?? false}
|
||||
/>
|
||||
</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="flex items-center justify-between gap-2">
|
||||
<h4>Links</h4>
|
||||
{!isNotAllowed && (
|
||||
{isAllowed && (
|
||||
<button
|
||||
type="button"
|
||||
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";
|
||||
// fetch keys
|
||||
import { SUB_ISSUES } from "constants/fetch-keys";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
export interface ISubIssuesRoot {
|
||||
parentIssue: IIssue;
|
||||
@ -176,7 +177,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
|
||||
);
|
||||
|
||||
const isEditable = userRole === 5 || userRole === 10 ? false : true;
|
||||
const isEditable = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const mutateSubIssues = (parentIssueId: string | null) => {
|
||||
if (parentIssueId) mutate(SUB_ISSUES(parentIssueId));
|
||||
|
@ -33,6 +33,7 @@ import { linkDetails, IModule, ModuleLink } from "types";
|
||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||
// constant
|
||||
import { MODULE_STATUS } from "constants/module";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
const defaultValues: Partial<IModule> = {
|
||||
lead: "",
|
||||
@ -588,10 +589,10 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
handleEditLink={handleEditLink}
|
||||
handleDeleteLink={handleDeleteLink}
|
||||
userAuth={{
|
||||
isGuest: userRole === 5,
|
||||
isViewer: userRole === 10,
|
||||
isMember: userRole === 15,
|
||||
isOwner: userRole === 20,
|
||||
isGuest: userRole === EUserWorkspaceRoles.GUEST,
|
||||
isViewer: userRole === EUserWorkspaceRoles.VIEWER,
|
||||
isMember: userRole === EUserWorkspaceRoles.MEMBER,
|
||||
isOwner: userRole === EUserWorkspaceRoles.ADMIN,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
@ -26,6 +26,7 @@ import { CustomMenu, Tooltip } from "@plane/ui";
|
||||
import { CreateUpdatePageModal, DeletePageModal } from "components/pages";
|
||||
// types
|
||||
import { IPage } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
export interface IPagesListItem {
|
||||
workspaceSlug: string;
|
||||
@ -144,7 +145,7 @@ export const PagesListItem: FC<IPagesListItem> = observer((props) => {
|
||||
setCreateUpdatePageModal(true);
|
||||
};
|
||||
|
||||
const userCanEdit = currentProjectRole === 15 || currentProjectRole === 20;
|
||||
const userCanEdit = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -13,7 +13,7 @@ import { CustomSelect, Tooltip } from "@plane/ui";
|
||||
// icons
|
||||
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
||||
// constants
|
||||
import { ROLE } from "constants/workspace";
|
||||
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
|
||||
// types
|
||||
import { IProjectMember, TUserProjectRole } from "types";
|
||||
|
||||
@ -38,7 +38,7 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
// derived values
|
||||
const isAdmin = currentProjectRole === 20;
|
||||
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||
const memberDetails = member.member;
|
||||
|
||||
const handleRemove = async () => {
|
||||
@ -148,12 +148,13 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
||||
disabled={
|
||||
memberDetails.id === currentUser?.id ||
|
||||
!member.member ||
|
||||
(currentProjectRole && currentProjectRole !== 20 && currentProjectRole < member.role)
|
||||
!currentProjectRole ||
|
||||
currentProjectRole < member.role
|
||||
}
|
||||
placement="bottom-end"
|
||||
>
|
||||
{Object.keys(ROLE).map((key) => {
|
||||
if (currentProjectRole && currentProjectRole !== 20 && currentProjectRole < parseInt(key)) return null;
|
||||
if (currentProjectRole && !isAdmin && currentProjectRole < parseInt(key)) return null;
|
||||
|
||||
return (
|
||||
<CustomSelect.Option key={key} value={parseInt(key, 10)}>
|
||||
|
@ -15,6 +15,7 @@ import { Loader } from "@plane/ui";
|
||||
import { IProject, IUserLite, IWorkspace } from "types";
|
||||
// fetch-keys
|
||||
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
const defaultValues: Partial<IProject> = {
|
||||
project_lead: null,
|
||||
@ -29,7 +30,7 @@ export const ProjectSettingsMemberDefaults: React.FC = observer(() => {
|
||||
const { user: userStore, project: projectStore } = useMobxStore();
|
||||
const { currentProjectDetails } = projectStore;
|
||||
const { currentProjectRole } = userStore;
|
||||
const isAdmin = currentProjectRole === 20;
|
||||
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||
// hooks
|
||||
const { setToastAlert } = useToast();
|
||||
// form info
|
||||
|
@ -15,7 +15,7 @@ import useToast from "hooks/use-toast";
|
||||
// types
|
||||
import { IProjectMember, TUserProjectRole } from "types";
|
||||
// constants
|
||||
import { ROLE } from "constants/workspace";
|
||||
import { EUserWorkspaceRoles, ROLE } from "constants/workspace";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
@ -246,7 +246,8 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
||||
width="w-full"
|
||||
>
|
||||
{Object.entries(ROLE).map(([key, label]) => {
|
||||
if (parseInt(key) > (currentProjectRole ?? 5)) return null;
|
||||
if (parseInt(key) > (currentProjectRole ?? EUserWorkspaceRoles.GUEST))
|
||||
return null;
|
||||
|
||||
return (
|
||||
<CustomSelect.Option key={key} value={key}>
|
||||
|
@ -9,6 +9,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import useToast from "hooks/use-toast";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@ -56,7 +57,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
||||
user: { currentUser, currentProjectRole },
|
||||
trackEvent: { setTrackElement, postHogEventTracker },
|
||||
} = useMobxStore();
|
||||
const isAdmin = currentProjectRole === 20;
|
||||
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||
// hooks
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
@ -97,7 +98,7 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
||||
project_id: currentProjectDetails?.id,
|
||||
project_name: currentProjectDetails?.name,
|
||||
project_identifier: currentProjectDetails?.identifier,
|
||||
enabled: !currentProjectDetails?.[feature.property as keyof IProject]
|
||||
enabled: !currentProjectDetails?.[feature.property as keyof IProject],
|
||||
});
|
||||
handleSubmit({
|
||||
[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) {
|
||||
case 5:
|
||||
case EUserWorkspaceRoles.GUEST:
|
||||
return "GUEST";
|
||||
case 10:
|
||||
case EUserWorkspaceRoles.VIEWER:
|
||||
return "VIEWER";
|
||||
case 15:
|
||||
case EUserWorkspaceRoles.MEMBER:
|
||||
return "MEMBER";
|
||||
case 20:
|
||||
case EUserWorkspaceRoles.ADMIN:
|
||||
return "ADMIN";
|
||||
}
|
||||
};
|
||||
|
@ -1,15 +1,27 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
// components
|
||||
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 {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const ProjectSettingLayout: FC<IProjectSettingLayout> = (props) => {
|
||||
export const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((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="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<ProjectSettingsSidebar />
|
||||
@ -17,4 +29,4 @@ export const ProjectSettingLayout: FC<IProjectSettingLayout> = (props) => {
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -14,6 +14,7 @@ import { ProjectSettingHeader } from "components/headers";
|
||||
// types
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
import { IProject } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
const AutomationSettingsPage: NextPageWithLayout = observer(() => {
|
||||
const router = useRouter();
|
||||
@ -39,7 +40,7 @@ const AutomationSettingsPage: NextPageWithLayout = observer(() => {
|
||||
});
|
||||
};
|
||||
|
||||
const isAdmin = currentProjectRole === 20;
|
||||
const isAdmin = currentProjectRole === EUserWorkspaceRoles.ADMIN;
|
||||
|
||||
return (
|
||||
<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";
|
||||
// types
|
||||
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 = () => (
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<EstimatesList />
|
||||
</div>
|
||||
);
|
||||
const EstimatesSettingsPage: NextPageWithLayout = observer(() => {
|
||||
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 />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
|
@ -5,6 +5,7 @@ import { RootStore } from "../root";
|
||||
import { InboxService } from "services/inbox.service";
|
||||
// types
|
||||
import { IInbox, IInboxFilterOptions, IInboxQueryParams } from "types";
|
||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||
|
||||
export interface IInboxFiltersStore {
|
||||
// states
|
||||
@ -132,8 +133,8 @@ export class InboxFiltersStore implements IInboxFiltersStore {
|
||||
};
|
||||
});
|
||||
|
||||
const userRole = this.rootStore.user?.projectMemberInfo?.[projectId]?.role || 0;
|
||||
if (userRole > 10) {
|
||||
const userRole = this.rootStore.user?.currentProjectRole || EUserWorkspaceRoles.GUEST;
|
||||
if (userRole > EUserWorkspaceRoles.VIEWER) {
|
||||
await this.inboxService.patchInbox(workspaceSlug, projectId, inboxId, { view_props: newViewProps });
|
||||
}
|
||||
} catch (error) {
|
||||
|
Loading…
Reference in New Issue
Block a user