fix: incomplete cycle issues auth (#4299)

This commit is contained in:
Aaryan Khandelwal 2024-04-29 00:50:15 +05:30 committed by GitHub
parent 6ac3cb9b31
commit 0e3d5cc4eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 87 additions and 33 deletions

View File

@ -416,7 +416,7 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
to: "End date", to: "End date",
}} }}
required={cycleDetails.status !== "draft"} required={cycleDetails.status !== "draft"}
disabled={isArchived} disabled={!isEditingAllowed || isArchived}
/> />
)} )}
/> />

View File

@ -1,10 +1,12 @@
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
// hooks
import { EmptyState } from "@/components/common";
import { EIssuesStoreType } from "@/constants/issue";
import { useApplication, useEventTracker } from "@/hooks/store";
// components // components
import { EmptyState } from "@/components/common";
// constants
import { EIssuesStoreType } from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useApplication, useEventTracker, useUser } from "@/hooks/store";
// assets // assets
import emptyIssue from "public/empty-state/issue.svg"; import emptyIssue from "public/empty-state/issue.svg";
@ -12,6 +14,11 @@ export const ProjectViewEmptyState: React.FC = observer(() => {
// store hooks // store hooks
const { commandPalette: commandPaletteStore } = useApplication(); const { commandPalette: commandPaletteStore } = useApplication();
const { setTrackElement } = useEventTracker(); const { setTrackElement } = useEventTracker();
const {
membership: { currentProjectRole },
} = useUser();
// auth
const isCreatingIssueAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
return ( return (
<div className="grid h-full w-full place-items-center"> <div className="grid h-full w-full place-items-center">
@ -19,14 +26,18 @@ export const ProjectViewEmptyState: React.FC = observer(() => {
title="View issues will appear here" title="View issues will appear here"
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done." description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
image={emptyIssue} image={emptyIssue}
primaryButton={{ primaryButton={
text: "New issue", isCreatingIssueAllowed
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />, ? {
onClick: () => { text: "New issue",
setTrackElement("View issue empty state"); icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
commandPaletteStore.toggleCreateIssueModal(true, EIssuesStoreType.PROJECT_VIEW); onClick: () => {
}, setTrackElement("View issue empty state");
}} commandPaletteStore.toggleCreateIssueModal(true, EIssuesStoreType.PROJECT_VIEW);
},
}
: undefined
}
/> />
</div> </div>
); );

View File

@ -1,12 +1,13 @@
import React, { useCallback } from "react"; import React, { useCallback } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// hooks // components
import { CycleIssueQuickActions } from "@/components/issues"; import { CycleIssueQuickActions } from "@/components/issues";
// constants
import { EIssuesStoreType } from "@/constants/issue"; import { EIssuesStoreType } from "@/constants/issue";
import { useCycle, useIssues } from "@/hooks/store"; import { EUserProjectRoles } from "@/constants/project";
// ui // hooks
// types import { useCycle, useIssues, useUser } from "@/hooks/store";
// components // components
import { BaseKanBanRoot } from "../base-kanban-root"; import { BaseKanBanRoot } from "../base-kanban-root";
@ -19,11 +20,18 @@ export const CycleKanBanLayout: React.FC = observer(() => {
// store // store
const { issues } = useIssues(EIssuesStoreType.CYCLE); const { issues } = useIssues(EIssuesStoreType.CYCLE);
const { currentProjectCompletedCycleIds } = useCycle(); const { currentProjectCompletedCycleIds } = useCycle();
const {
membership: { currentProjectRole },
} = useUser();
const isCompletedCycle = const isCompletedCycle =
cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false; cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const canEditIssueProperties = useCallback(() => !isCompletedCycle, [isCompletedCycle]); const canEditIssueProperties = useCallback(
() => !isCompletedCycle && isEditingAllowed,
[isCompletedCycle, isEditingAllowed]
);
const addIssuesToView = useCallback( const addIssuesToView = useCallback(
(issueIds: string[]) => { (issueIds: string[]) => {

View File

@ -1,13 +1,14 @@
import React, { useCallback } from "react"; import React, { useCallback } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// hooks
import { CycleIssueQuickActions } from "@/components/issues";
import { EIssuesStoreType } from "@/constants/issue";
import { useCycle, useIssues } from "@/hooks/store";
// components // components
// types import { CycleIssueQuickActions } from "@/components/issues";
// constants // constants
import { EIssuesStoreType } from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCycle, useIssues, useUser } from "@/hooks/store";
// types
import { BaseListRoot } from "../base-list-root"; import { BaseListRoot } from "../base-list-root";
export interface ICycleListLayout {} export interface ICycleListLayout {}
@ -17,12 +18,19 @@ export const CycleListLayout: React.FC = observer(() => {
const { workspaceSlug, projectId, cycleId } = router.query; const { workspaceSlug, projectId, cycleId } = router.query;
// store // store
const { issues } = useIssues(EIssuesStoreType.CYCLE); const { issues } = useIssues(EIssuesStoreType.CYCLE);
const { currentProjectCompletedCycleIds } = useCycle(); const { currentProjectCompletedCycleIds } = useCycle(); // mobx store
const {
membership: { currentProjectRole },
} = useUser();
const isCompletedCycle = const isCompletedCycle =
cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false; cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const canEditIssueProperties = useCallback(() => !isCompletedCycle, [isCompletedCycle]); const canEditIssueProperties = useCallback(
() => !isCompletedCycle && isEditingAllowed,
[isCompletedCycle, isEditingAllowed]
);
const addIssuesToView = useCallback( const addIssuesToView = useCallback(
(issueIds: string[]) => { (issueIds: string[]) => {

View File

@ -1,22 +1,33 @@
import React, { useCallback } from "react"; import React, { useCallback } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// mobx store // constants
import { EIssuesStoreType } from "@/constants/issue"; import { EIssuesStoreType } from "@/constants/issue";
import { useCycle } from "@/hooks/store"; import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCycle, useUser } from "@/hooks/store";
// components // components
import { CycleIssueQuickActions } from "../../quick-action-dropdowns"; import { CycleIssueQuickActions } from "../../quick-action-dropdowns";
import { BaseSpreadsheetRoot } from "../base-spreadsheet-root"; import { BaseSpreadsheetRoot } from "../base-spreadsheet-root";
export const CycleSpreadsheetLayout: React.FC = observer(() => { export const CycleSpreadsheetLayout: React.FC = observer(() => {
// router
const router = useRouter(); const router = useRouter();
const { cycleId } = router.query; const { cycleId } = router.query;
// store hooks
const { currentProjectCompletedCycleIds } = useCycle(); const { currentProjectCompletedCycleIds } = useCycle();
const {
membership: { currentProjectRole },
} = useUser();
// auth
const isCompletedCycle = const isCompletedCycle =
cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false; cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false;
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const canEditIssueProperties = useCallback(() => !isCompletedCycle, [isCompletedCycle]); const canEditIssueProperties = useCallback(
() => !isCompletedCycle && isEditingAllowed,
[isCompletedCycle, isEditingAllowed]
);
if (!cycleId) return null; if (!cycleId) return null;

View File

@ -480,7 +480,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
from: "Start date", from: "Start date",
to: "Target date", to: "Target date",
}} }}
disabled={isArchived} disabled={!isEditingAllowed || isArchived}
/> />
); );
}} }}
@ -510,7 +510,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
multiple={false} multiple={false}
buttonVariant="background-with-text" buttonVariant="background-with-text"
placeholder="Lead" placeholder="Lead"
disabled={isArchived} disabled={!isEditingAllowed || isArchived}
/> />
</div> </div>
)} )}

View File

@ -4,10 +4,13 @@ import { ArchiveRestoreIcon, Clipboard, Copy, Link, Lock, LockOpen } from "lucid
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor"; import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor";
// ui // ui
import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui"; import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// constants
import { EUserProjectRoles } from "@/constants/project";
// helpers // helpers
import { cn } from "@/helpers/common.helper";
import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper"; import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper";
// hooks // hooks
import { useApplication } from "@/hooks/store"; import { useApplication, useUser } from "@/hooks/store";
// store // store
import { IPageStore } from "@/store/pages/page.store"; import { IPageStore } from "@/store/pages/page.store";
@ -38,6 +41,11 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
const { const {
router: { workspaceSlug, projectId }, router: { workspaceSlug, projectId },
} = useApplication(); } = useApplication();
const {
membership: { currentProjectRole },
} = useUser();
// auth
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const handleArchivePage = async () => const handleArchivePage = async () =>
await archive().catch(() => await archive().catch(() =>
@ -146,9 +154,17 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
full_width: !view_props?.full_width, full_width: !view_props?.full_width,
}) })
} }
disabled={!isEditingAllowed}
> >
Full width Full width
<ToggleSwitch value={!!view_props?.full_width} onChange={() => {}} /> <ToggleSwitch
value={!!view_props?.full_width}
onChange={() => {}}
className={cn({
"opacity-40": !isEditingAllowed,
})}
disabled={!isEditingAllowed}
/>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
{MENU_ITEMS.map((item) => { {MENU_ITEMS.map((item) => {
if (!item.shouldRender) return null; if (!item.shouldRender) return null;