[WEB-2357] fix: update and redefine user roles across the platform (#5466)

* chore: removed viewer role

* chore: indentation

* chore: remove viewer role

* chore: handled user permissions in store

* chore: updated the migration file

* chore: updated user permissions store

* chore: removed the owner key

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* fix: build error

* chore: updated user permissions store and handled the permissions fetch in workspace and project wrappers

* chore: package user enum updated

* chore: user permission updated

* chore: user permission updated

* chore: resolved build errors

* chore: resolved build error

* chore: resolved build errors

* chore: computedFn deep map issue resolved

* chore: added back migration

* chore: added new field in project table

* chore: removed member store in users

* chore: private project for admins

* chore: workspace notification access validation updated

* fix: workspace member edit option

* fix: project intake permission validation updated

* chore: workspace export settings permission updated

* chore: guest_view_all_issues added

* chore: guest_view_all_issues added

* chore: key changed for guest access

* chore: added validation for individual issues

* chore: changed the dashboard issues count

* chore: added new yarn file

* chore: modified yarn file

* chore: project page permission updated

* chore: project page permission updated

* chore: member setting ux updated

* chore: build error

* fix: yarn lock

* fix: build error

---------

Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
Bavisetti Narayan 2024-09-11 17:10:15 +05:30 committed by GitHub
parent 7013a36629
commit fdcd9a376c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
172 changed files with 2057 additions and 1627 deletions

View file

@ -21,7 +21,6 @@ import {
EIssuesStoreType,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { cn } from "@/helpers/common.helper";
import { isIssueFilterActive } from "@/helpers/filter.helper";
@ -34,13 +33,14 @@ import {
useMember,
useProject,
useProjectState,
useUser,
useIssues,
useCommandPalette,
useUserPermissions,
} from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import useLocalStorage from "@/hooks/use-local-storage";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => {
// router
@ -81,9 +81,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
const { currentProjectCycleIds, getCycleById } = useCycle();
const { toggleCreateIssueModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const {
membership: { currentProjectRole },
} = useUser();
const { currentProjectDetails, loader } = useProject();
const { projectStates } = useProjectState();
const { projectLabels } = useLabel();
@ -91,6 +88,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
project: { projectMemberIds },
} = useMember();
const { isMobile } = usePlatformOS();
const { allowPermissions } = useUserPermissions();
const activeLayout = issueFilters?.displayFilters?.layout;
@ -149,8 +147,10 @@ export const CycleIssuesHeader: React.FC = observer(() => {
// derived values
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
const isCompletedCycle = cycleDetails?.status?.toLocaleLowerCase() === "completed";
const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateIssue = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
const issuesCount = getGroupIssueCount(undefined, undefined, false);

View file

@ -8,11 +8,11 @@ import { Breadcrumbs, Button, ContrastIcon, Header } from "@plane/ui";
// components
import { BreadcrumbLink, Logo } from "@/components/common";
import { CyclesViewHeader } from "@/components/cycles";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// constants
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const CyclesListHeader: FC = observer(() => {
// router
@ -21,13 +21,13 @@ export const CyclesListHeader: FC = observer(() => {
// store hooks
const { toggleCreateCycleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
const canUserCreateCycle =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateCycle = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
return (
<Header>

View file

@ -9,10 +9,9 @@ import { Breadcrumbs, Button, Intake, Header } from "@plane/ui";
// components
import { BreadcrumbLink, Logo } from "@/components/common";
import { InboxIssueCreateEditModalRoot } from "@/components/inbox";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useProject, useProjectInbox, useUser } from "@/hooks/store";
import { useProject, useProjectInbox, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ProjectInboxHeader: FC = observer(() => {
// states
@ -20,14 +19,16 @@ export const ProjectInboxHeader: FC = observer(() => {
// router
const { workspaceSlug, projectId } = useParams();
// store hooks
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader: currentProjectDetailsLoader } = useProject();
const { loader } = useProjectInbox();
// derived value
const isViewer = currentProjectRole === EUserProjectRoles.VIEWER;
const isAuthorized = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST],
EUserPermissionsLevel.PROJECT
);
return (
<Header>
@ -66,7 +67,7 @@ export const ProjectInboxHeader: FC = observer(() => {
</div>
</Header.LeftItem>
<Header.RightItem>
{currentProjectDetails?.inbox_view && workspaceSlug && projectId && !isViewer ? (
{currentProjectDetails?.inbox_view && workspaceSlug && projectId && isAuthorized ? (
<div className="flex items-center gap-2">
<InboxIssueCreateEditModalRoot
workspaceSlug={workspaceSlug.toString()}

View file

@ -12,22 +12,19 @@ import { BreadcrumbLink, CountChip, Logo } from "@/components/common";
import HeaderFilters from "@/components/issues/filters";
import { EIssuesStoreType } from "@/constants/issue";
// helpers
import { EUserProjectRoles } from "@/constants/project";
import { SPACE_BASE_PATH, SPACE_BASE_URL } from "@/helpers/common.helper";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
import { useEventTracker, useProject, useCommandPalette, useUserPermissions } from "@/hooks/store";
import { useIssues } from "@/hooks/store/use-issues";
import { useAppRouter } from "@/hooks/use-app-router";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ProjectIssuesHeader = observer(() => {
// router
const router = useAppRouter();
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
// store hooks
const {
membership: { currentProjectRole },
} = useUser();
const {
issues: { getGroupIssueCount },
} = useIssues(EIssuesStoreType.PROJECT);
@ -36,14 +33,17 @@ export const ProjectIssuesHeader = observer(() => {
const { toggleCreateIssueModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const { allowPermissions } = useUserPermissions();
const { isMobile } = usePlatformOS();
const SPACE_APP_URL = (SPACE_BASE_URL.trim() === "" ? window.location.origin : SPACE_BASE_URL) + SPACE_BASE_PATH;
const publishedURL = `${SPACE_APP_URL}/issues/${currentProjectDetails?.anchor}`;
const issuesCount = getGroupIssueCount(undefined, undefined, false);
const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateIssue = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
return (
<Header>

View file

@ -21,7 +21,6 @@ import {
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// helpers
import { cn } from "@/helpers/common.helper";
import { isIssueFilterActive } from "@/helpers/filter.helper";
@ -34,14 +33,15 @@ import {
useModule,
useProject,
useProjectState,
useUser,
useIssues,
useCommandPalette,
useUserPermissions,
} from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
import { useIssuesActions } from "@/hooks/use-issues-actions";
import useLocalStorage from "@/hooks/use-local-storage";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => {
// router
@ -83,9 +83,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
const { projectModuleIds, getModuleById } = useModule();
const { toggleCreateIssueModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
const { projectLabels } = useLabel();
const { projectStates } = useProjectState();
@ -149,8 +147,10 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
// derived values
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateIssue = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
const issuesCount = getGroupIssueCount(undefined, undefined, false);

View file

@ -7,11 +7,11 @@ import { Breadcrumbs, Button, DiceIcon, Header } from "@plane/ui";
// components
import { BreadcrumbLink, Logo } from "@/components/common";
import { ModuleViewHeader } from "@/components/modules";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// constants
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ModulesListHeader: React.FC = observer(() => {
// router
@ -20,14 +20,15 @@ export const ModulesListHeader: React.FC = observer(() => {
// store hooks
const { toggleCreateModuleModal } = useCommandPalette();
const { setTrackElement } = useEventTracker();
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
// auth
const canUserCreateModule =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateModule = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
return (
<Header>

View file

@ -9,9 +9,9 @@ import { Breadcrumbs, Button, Header } from "@plane/ui";
import { BreadcrumbLink, Logo } from "@/components/common";
// constants
import { EPageAccess } from "@/constants/page";
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
import { useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const PagesListHeader = observer(() => {
// router
@ -20,14 +20,15 @@ export const PagesListHeader = observer(() => {
const pageType = searchParams.get("type");
// store hooks
const { toggleCreatePageModal } = useCommandPalette();
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
const { setTrackElement } = useEventTracker();
const canUserCreatePage =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreatePage = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
return (
<Header>

View file

@ -11,18 +11,19 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { AutoArchiveAutomation, AutoCloseAutomation } from "@/components/automation";
import { PageHead } from "@/components/core";
// hooks
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const AutomationSettingsPage = observer(() => {
// router
const { workspaceSlug, projectId } = useParams();
// store hooks
const {
canPerformProjectAdminActions,
membership: { currentProjectRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { currentProjectDetails: projectDetails, updateProject } = useProject();
// derived values
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
const handleChange = async (formData: Partial<IProject>) => {
if (!workspaceSlug || !projectId || !projectDetails) return;
@ -38,7 +39,7 @@ const AutomationSettingsPage = observer(() => {
// derived values
const pageTitle = projectDetails?.name ? `${projectDetails?.name} - Automations` : undefined;
if (currentProjectRole && !canPerformProjectAdminActions) {
if (workspaceUserInfo && !canPerformProjectAdminActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -7,22 +7,22 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import { EstimateRoot } from "@/components/estimates";
// hooks
import { useUser, useProject } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const EstimatesSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
const {
canPerformProjectAdminActions,
membership: { currentProjectRole },
} = useUser();
// store
const { currentProjectDetails } = useProject();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
// derived values
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Estimates` : undefined;
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
if (!workspaceSlug || !projectId) return <></>;
if (currentProjectRole && !canPerformProjectAdminActions) {
if (workspaceUserInfo && !canPerformProjectAdminActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -7,22 +7,22 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import { ProjectFeaturesList } from "@/components/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const FeaturesSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
// store
const {
canPerformProjectAdminActions,
membership: { currentProjectRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { currentProjectDetails } = useProject();
// derived values
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Features` : undefined;
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
if (!workspaceSlug || !projectId) return null;
if (currentProjectRole && !canPerformProjectAdminActions) {
if (workspaceUserInfo && !canPerformProjectAdminActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -9,25 +9,21 @@ import { Breadcrumbs, CustomMenu, Header } from "@plane/ui";
// components
import { BreadcrumbLink, Logo } from "@/components/common";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web constants
import { PROJECT_SETTINGS_LINKS } from "@/plane-web/constants/project";
import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ProjectSettingHeader: FC = observer(() => {
// router
const router = useAppRouter();
const { workspaceSlug, projectId } = useParams();
// store hooks
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
const projectMemberInfo = currentProjectRole || EUserProjectRoles.GUEST;
return (
<Header>
<Header.LeftItem>
@ -74,7 +70,12 @@ export const ProjectSettingHeader: FC = observer(() => {
>
{PROJECT_SETTINGS_LINKS.map(
(item) =>
projectMemberInfo >= item.access && (
allowPermissions(
item.access,
EUserPermissionsLevel.PROJECT,
workspaceSlug.toString(),
projectId.toString()
) && (
<CustomMenu.MenuItem
key={item.key}
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}${item.href}`)}

View file

@ -9,19 +9,24 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import { ProjectSettingsLabelList } from "@/components/labels";
// hooks
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const LabelsSettingsPage = observer(() => {
// store hooks
const { currentProjectDetails } = useProject();
const {
canPerformProjectMemberActions,
membership: { currentProjectRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Labels` : undefined;
const scrollableContainerRef = useRef<HTMLDivElement | null>(null);
// derived values
const canPerformProjectMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
// Enable Auto Scroll for Labels list
useEffect(() => {
const element = scrollableContainerRef.current;
@ -35,7 +40,7 @@ const LabelsSettingsPage = observer(() => {
);
}, [scrollableContainerRef?.current]);
if (currentProjectRole && !canPerformProjectMemberActions) {
if (workspaceUserInfo && !canPerformProjectMemberActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -6,19 +6,21 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import { ProjectMemberList, ProjectSettingsMemberDefaults } from "@/components/project";
// hooks
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const MembersSettingsPage = observer(() => {
// store
const { currentProjectDetails } = useProject();
const {
canPerformProjectViewerActions,
membership: { currentProjectRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
// derived values
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Members` : undefined;
const canPerformProjectMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
if (currentProjectRole && !canPerformProjectViewerActions) {
if (workspaceUserInfo && !canPerformProjectMemberActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -15,7 +15,8 @@ import {
ProjectDetailsFormLoader,
} from "@/components/project";
// hooks
import { useProject } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const GeneralSettingsPage = observer(() => {
// states
@ -25,6 +26,8 @@ const GeneralSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
// store hooks
const { currentProjectDetails, fetchProjectDetails } = useProject();
const { allowPermissions } = useUserPermissions();
// api call to fetch project details
// TODO: removed this API if not necessary
const { isLoading } = useSWR(
@ -32,7 +35,13 @@ const GeneralSettingsPage = observer(() => {
workspaceSlug && projectId ? () => fetchProjectDetails(workspaceSlug.toString(), projectId.toString()) : null
);
// derived values
const isAdmin = currentProjectDetails?.member_role === 20;
const isAdmin = allowPermissions(
[EUserPermissions.ADMIN],
EUserPermissionsLevel.PROJECT,
workspaceSlug.toString(),
projectId.toString()
);
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - General Settings` : undefined;
// const currentNetwork = NETWORK_CHOICES.find((n) => n.key === projectDetails?.network);
// const selectedNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network"));
@ -69,7 +78,7 @@ const GeneralSettingsPage = observer(() => {
<ProjectDetailsFormLoader />
)}
{isAdmin && (
{isAdmin && currentProjectDetails && (
<>
<ArchiveProjectSelection
projectDetails={currentProjectDetails}

View file

@ -8,22 +8,20 @@ import { useParams, usePathname } from "next/navigation";
import { Loader } from "@plane/ui";
// components
import { SidebarNavItem } from "@/components/sidebar";
// constants
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useUser } from "@/hooks/store";
import { useUserPermissions } from "@/hooks/store";
// plane web constants
import { PROJECT_SETTINGS_LINKS } from "@/plane-web/constants/project";
import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ProjectSettingsSidebar = observer(() => {
const { workspaceSlug, projectId } = useParams();
const pathname = usePathname();
// mobx store
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions, projectUserInfo } = useUserPermissions();
const projectMemberInfo = currentProjectRole || EUserProjectRoles.GUEST;
// derived values
const currentProjectRole = projectUserInfo?.[workspaceSlug?.toString()]?.[projectId?.toString()]?.role;
if (!currentProjectRole) {
return (
@ -47,7 +45,12 @@ export const ProjectSettingsSidebar = observer(() => {
<div className="flex w-full flex-col gap-1">
{PROJECT_SETTINGS_LINKS.map(
(link) =>
projectMemberInfo >= link.access && (
allowPermissions(
link.access,
EUserPermissionsLevel.PROJECT,
workspaceSlug.toString(),
projectId.toString()
) && (
<Link key={link.key} href={`/${workspaceSlug}/projects/${projectId}${link.href}`}>
<SidebarNavItem
key={link.key}

View file

@ -7,20 +7,24 @@ import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import { ProjectStateRoot } from "@/components/project-states";
// hook
import { useProject, useUser } from "@/hooks/store";
import { useProject, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const StatesSettingsPage = observer(() => {
const { workspaceSlug, projectId } = useParams();
// store
const { currentProjectDetails } = useProject();
const {
canPerformProjectMemberActions,
membership: { currentProjectRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
// derived values
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - States` : undefined;
// derived values
const canPerformProjectMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
if (currentProjectRole && !canPerformProjectMemberActions) {
if (workspaceUserInfo && !canPerformProjectMemberActions) {
return <NotAuthorizedView section="settings" isProjectView />;
}

View file

@ -19,7 +19,6 @@ import {
EIssueLayoutTypes,
ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
} from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
import { EViewAccess } from "@/constants/views";
// helpers
import { isIssueFilterActive } from "@/helpers/filter.helper";
@ -35,8 +34,9 @@ import {
useProject,
useProjectState,
useProjectView,
useUser,
useUserPermissions,
} from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export const ProjectViewIssuesHeader: React.FC = observer(() => {
// router
@ -47,9 +47,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
} = useIssues(EIssuesStoreType.PROJECT_VIEW);
const { setTrackElement } = useEventTracker();
const { toggleCreateIssueModal } = useCommandPalette();
const {
membership: { currentProjectRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const { currentProjectDetails, loader } = useProject();
const { projectViewIds, getViewById } = useProjectView();
const { projectStates } = useProjectState();
@ -131,8 +130,10 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
const viewDetails = viewId ? getViewById(viewId.toString()) : null;
const canUserCreateIssue =
currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole);
const canUserCreateIssue = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.PROJECT
);
const publishLink = getPublishViewLink(viewDetails?.anchor);
return (