forked from github/plane
Merge branch 'develop' of https://github.com/makeplane/plane into fix/description_field
This commit is contained in:
commit
fb5983e23e
@ -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) => (
|
||||||
|
@ -2,10 +2,12 @@ import React, { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
// services
|
// services
|
||||||
import { CycleService } from "services/cycle.service";
|
import { CycleService } from "services/cycle.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
//icons
|
//icons
|
||||||
import { ContrastIcon, TransferIcon } from "@plane/ui";
|
import { ContrastIcon, TransferIcon } from "@plane/ui";
|
||||||
import { AlertCircle, Search, X } from "lucide-react";
|
import { AlertCircle, Search, X } from "lucide-react";
|
||||||
@ -23,17 +25,19 @@ type Props = {
|
|||||||
|
|
||||||
const cycleService = new CycleService();
|
const cycleService = new CycleService();
|
||||||
|
|
||||||
export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) => {
|
export const TransferIssuesModal: React.FC<Props> = observer(({ isOpen, handleClose }) => {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
|
const { cycleIssues: cycleIssueStore } = useMobxStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const transferIssue = async (payload: any) => {
|
const transferIssue = async (payload: any) => {
|
||||||
await cycleService
|
await cycleIssueStore
|
||||||
.transferIssues(workspaceSlug as string, projectId as string, cycleId as string, payload)
|
.transferIssuesFromCycle(workspaceSlug as string, projectId as string, cycleId as string, payload)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -159,4 +163,4 @@ export const TransferIssuesModal: React.FC<Props> = ({ isOpen, handleClose }) =>
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -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);
|
||||||
|
@ -18,6 +18,7 @@ import { Loader, StateGroupIcon } 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: "",
|
||||||
@ -167,6 +168,8 @@ export const InboxMainContent: React.FC = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{issueDetails ? (
|
{issueDetails ? (
|
||||||
@ -273,7 +276,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;
|
||||||
|
@ -15,6 +15,8 @@ import { IIssue } from "types";
|
|||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
|
|
||||||
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
|
|
||||||
interface IPeekOverviewIssueDetails {
|
interface IPeekOverviewIssueDetails {
|
||||||
@ -35,7 +37,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
|
|||||||
projectIssues: { isSubmitting, setIsSubmitting },
|
projectIssues: { isSubmitting, setIsSubmitting },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const { currentProjectRole } = userStore;
|
const { currentProjectRole } = userStore;
|
||||||
const isAllowed = [15, 20].includes(currentProjectRole || 0);
|
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
// states
|
// states
|
||||||
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>
|
||||||
|
@ -28,6 +28,7 @@ import { MinusCircle, RefreshCw } 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;
|
||||||
@ -123,6 +124,8 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
}
|
}
|
||||||
}, [isSubmitting, setShowAlert]);
|
}, [isSubmitting, setShowAlert]);
|
||||||
|
|
||||||
|
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rounded-lg">
|
<div className="rounded-lg">
|
||||||
@ -215,7 +218,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;
|
||||||
@ -248,7 +249,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;
|
||||||
|
|
||||||
const currentIssueState = projectId
|
const currentIssueState = projectId
|
||||||
? states[projectId.toString()]?.find((s) => s.id === issueDetail?.state)
|
? states[projectId.toString()]?.find((s) => s.id === issueDetail?.state)
|
||||||
@ -314,7 +315,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"
|
||||||
@ -344,7 +345,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -365,7 +366,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -386,7 +387,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -407,7 +408,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -435,7 +436,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
onChange(val);
|
onChange(val);
|
||||||
}}
|
}}
|
||||||
issueDetails={issueDetail}
|
issueDetails={issueDetail}
|
||||||
disabled={isNotAllowed || uneditable}
|
disabled={!isAllowed || uneditable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -460,7 +461,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")) && (
|
||||||
@ -481,7 +482,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")) && (
|
||||||
@ -499,7 +500,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")) && (
|
||||||
@ -517,7 +518,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")) && (
|
||||||
@ -541,7 +542,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -569,7 +570,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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -590,7 +591,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>
|
||||||
@ -605,7 +606,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>
|
||||||
@ -624,7 +625,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>
|
||||||
@ -634,7 +635,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) {
|
||||||
|
@ -62,7 +62,14 @@ export interface ICycleIssuesStore {
|
|||||||
issueId: string,
|
issueId: string,
|
||||||
issueBridgeId: string
|
issueBridgeId: string
|
||||||
) => Promise<IIssue>;
|
) => Promise<IIssue>;
|
||||||
|
transferIssuesFromCycle: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
cycleId: string,
|
||||||
|
payload: {
|
||||||
|
new_cycle_id: string;
|
||||||
|
}
|
||||||
|
) => Promise<IIssue>;
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +110,7 @@ export class CycleIssuesStore extends IssueBaseStore implements ICycleIssuesStor
|
|||||||
quickAddIssue: action,
|
quickAddIssue: action,
|
||||||
addIssueToCycle: action,
|
addIssueToCycle: action,
|
||||||
removeIssueFromCycle: action,
|
removeIssueFromCycle: action,
|
||||||
|
transferIssuesFromCycle: action,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootStore = _rootStore;
|
this.rootStore = _rootStore;
|
||||||
@ -348,4 +356,28 @@ export class CycleIssuesStore extends IssueBaseStore implements ICycleIssuesStor
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
transferIssuesFromCycle = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
cycleId: string,
|
||||||
|
payload: {
|
||||||
|
new_cycle_id: string;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await this.cycleService.transferIssues(
|
||||||
|
workspaceSlug as string,
|
||||||
|
projectId as string,
|
||||||
|
cycleId as string,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
await this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user