[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

@ -14,7 +14,7 @@ import { IssuePeekOverview } from "@/components/issues";
import { EmptyStateType } from "@/constants/empty-state";
import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification";
// hooks
import { useIssueDetail, useUser, useWorkspace, useWorkspaceNotifications } from "@/hooks/store";
import { useIssueDetail, useUserPermissions, useWorkspace, useWorkspaceNotifications } from "@/hooks/store";
import { useWorkspaceIssueProperties } from "@/hooks/use-workspace-issue-properties";
const WorkspaceDashboardPage = observer(() => {
@ -28,9 +28,7 @@ const WorkspaceDashboardPage = observer(() => {
notificationIdsByWorkspaceId,
getNotifications,
} = useWorkspaceNotifications();
const {
membership: { fetchUserProjectInfo },
} = useUser();
const { fetchUserProjectInfo } = useUserPermissions();
const { setPeekIssue } = useIssueDetail();
// derived values
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Inbox` : undefined;

View file

@ -2,16 +2,15 @@
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// ui
import { Button } from "@plane/ui";
// components
import { PageHead } from "@/components/core";
import { DownloadActivityButton, WorkspaceActivityListPage } from "@/components/profile";
// constants
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
import { useUserPermissions } from "@/hooks/store";
// plane-web constants
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const PER_PAGE = 100;
@ -21,13 +20,7 @@ const ProfileActivityPage = observer(() => {
const [totalPages, setTotalPages] = useState(0);
const [resultsCount, setResultsCount] = useState(0);
// router
const { userId } = useParams();
// store hooks
const { data: currentUser } = useUser();
const {
membership: { currentWorkspaceRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
const updateTotalPages = (count: number) => setTotalPages(count);
@ -47,8 +40,10 @@ const ProfileActivityPage = observer(() => {
/>
);
const canDownloadActivity =
currentUser?.id === userId && !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
const canDownloadActivity = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
return (
<>

View file

@ -12,9 +12,9 @@ import { BreadcrumbLink } from "@/components/common";
// components
import { ProfileIssuesFilter } from "@/components/profile";
import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile";
import { EUserWorkspaceRoles } from "@/constants/workspace";
import { cn } from "@/helpers/common.helper";
import { useAppTheme, useUser } from "@/hooks/store";
import { useAppTheme, useUser, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
type TUserProfileHeader = {
userProjectsData: IUserProfileProjectSegregation | undefined;
@ -28,14 +28,15 @@ export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
const { workspaceSlug, userId } = useParams();
// store hooks
const { toggleProfileSidebar, profileSidebarCollapsed } = useAppTheme();
const {
membership: { currentWorkspaceRole },
data: currentUser,
} = useUser();
const { data: currentUser } = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
// derived values
const isAuthorized = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.VIEWER;
const isAuthorized = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
if (!currentWorkspaceRole) return null;
if (!workspaceUserInfo) return null;
const tabsList = isAuthorized ? [...PROFILE_VIEWER_TAB, ...PROFILE_ADMINS_TAB] : PROFILE_VIEWER_TAB;

View file

@ -9,10 +9,10 @@ import { ProfileSidebar } from "@/components/profile";
// constants
import { USER_PROFILE_PROJECT_SEGREGATION } from "@/constants/fetch-keys";
import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile";
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
import { useUserPermissions } from "@/hooks/store";
import useSize from "@/hooks/use-window-size";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
// local components
import { UserService } from "@/services/user.service";
import { UserProfileHeader } from "./header";
@ -25,17 +25,18 @@ type Props = {
children: React.ReactNode;
};
const AUTHORIZED_ROLES = [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.VIEWER];
const UseProfileLayout: React.FC<Props> = observer((props) => {
const { children } = props;
// router
const { workspaceSlug, userId } = useParams();
const pathname = usePathname();
// store hooks
const {
membership: { currentWorkspaceRole },
} = useUser();
const { allowPermissions } = useUserPermissions();
// derived values
const isAuthorized = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
const windowSize = useSize();
const isSmallerScreen = windowSize[0] >= 768;
@ -47,7 +48,6 @@ const UseProfileLayout: React.FC<Props> = observer((props) => {
: null
);
// derived values
const isAuthorized = currentWorkspaceRole && AUTHORIZED_ROLES.includes(currentWorkspaceRole);
const isAuthorizedPath =
pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
const isIssuesTab = pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");

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 (

View file

@ -16,7 +16,8 @@ import { APITokenSettingsLoader } from "@/components/ui";
import { EmptyStateType } from "@/constants/empty-state";
import { API_TOKENS_LIST } from "@/constants/fetch-keys";
// store hooks
import { useUser, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
// services
import { APITokenService } from "@/services/api_token.service";
@ -28,11 +29,10 @@ const ApiTokensPage = observer(() => {
// router
const { workspaceSlug } = useParams();
// store hooks
const {
canPerformWorkspaceAdminActions,
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
// derived values
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const { data: tokens } = useSWR(
workspaceSlug && canPerformWorkspaceAdminActions ? API_TOKENS_LIST(workspaceSlug.toString()) : null,
@ -42,7 +42,7 @@ const ApiTokensPage = observer(() => {
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - API Tokens` : undefined;
if (currentWorkspaceRole && !canPerformWorkspaceAdminActions) {
if (workspaceUserInfo && !canPerformWorkspaceAdminActions) {
return <NotAuthorizedView section="settings" />;
}

View file

@ -5,21 +5,20 @@ import { observer } from "mobx-react";
import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
// hooks
import { useUser, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
// plane web components
import { BillingRoot } from "@/plane-web/components/workspace";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const BillingSettingsPage = observer(() => {
// store hooks
const {
canPerformWorkspaceAdminActions,
membership: { currentWorkspaceRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { currentWorkspace } = useWorkspace();
// derived values
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Billing & Plans` : undefined;
if (currentWorkspaceRole && !canPerformWorkspaceAdminActions) {
if (workspaceUserInfo && !canPerformWorkspaceAdminActions) {
return <NotAuthorizedView section="settings" />;
}

View file

@ -8,22 +8,23 @@ import ExportGuide from "@/components/exporter/guide";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useUser, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const ExportsPage = observer(() => {
// store hooks
const {
canPerformWorkspaceViewerActions,
canPerformWorkspaceMemberActions,
membership: { currentWorkspaceRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { currentWorkspace } = useWorkspace();
// derived values
const canPerformWorkspaceMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Exports` : undefined;
// if user is not authorized to view this page
if (currentWorkspaceRole && !canPerformWorkspaceViewerActions) {
if (workspaceUserInfo && !canPerformWorkspaceMemberActions) {
return <NotAuthorizedView section="settings" />;
}

View file

@ -4,20 +4,17 @@ import { observer } from "mobx-react";
// components
import { PageHead } from "@/components/core";
import IntegrationGuide from "@/components/integration/guide";
// constants
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const ImportsPage = observer(() => {
// store hooks
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
const { allowPermissions } = useUserPermissions();
// derived values
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Imports` : undefined;
if (!isAdmin)

View file

@ -8,9 +8,9 @@ import { SingleIntegrationCard } from "@/components/integration";
import { IntegrationAndImportExportBanner, IntegrationsSettingsLoader } from "@/components/ui";
// constants
import { APP_INTEGRATIONS } from "@/constants/fetch-keys";
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
// services
import { IntegrationService } from "@/services/integrations";
@ -20,13 +20,11 @@ const WorkspaceIntegrationsPage = observer(() => {
// router
const { workspaceSlug } = useParams();
// store hooks
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWorkspace } = useWorkspace();
const { allowPermissions } = useUserPermissions();
// derived values
const isAdmin = currentWorkspaceRole === EUserWorkspaceRoles.ADMIN;
const isAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Integrations` : undefined;
if (!isAdmin)

View file

@ -18,7 +18,8 @@ import { MEMBER_INVITED } from "@/constants/event-tracker";
import { cn } from "@/helpers/common.helper";
import { getUserRole } from "@/helpers/user.helper";
// hooks
import { useEventTracker, useMember, useUser, useWorkspace } from "@/hooks/store";
import { useEventTracker, useMember, useUserPermissions, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const WorkspaceMembersSettingsPage = observer(() => {
// states
@ -27,18 +28,20 @@ const WorkspaceMembersSettingsPage = observer(() => {
// router
const { workspaceSlug } = useParams();
// store hooks
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { captureEvent } = useEventTracker();
const {
canPerformWorkspaceAdminActions,
canPerformWorkspaceViewerActions,
canPerformWorkspaceMemberActions,
membership: { currentWorkspaceRole },
} = useUser();
const {
workspace: { inviteMembersToWorkspace },
} = useMember();
const { currentWorkspace } = useWorkspace();
// derived values
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const canPerformWorkspaceMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
const handleWorkspaceInvite = (data: IWorkspaceBulkInviteFormData) => {
if (!workspaceSlug) return;
@ -49,7 +52,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
emails: [
...data.emails.map((email) => ({
email: email.email,
role: getUserRole(email.role),
role: getUserRole(email.role as unknown as EUserPermissions),
})),
],
project_id: undefined,
@ -67,7 +70,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
emails: [
...data.emails.map((email) => ({
email: email.email,
role: getUserRole(email.role),
role: getUserRole(email.role as unknown as EUserPermissions),
})),
],
project_id: undefined,
@ -86,7 +89,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Members` : undefined;
// if user is not authorized to view this page
if (currentWorkspaceRole && !canPerformWorkspaceViewerActions) {
if (workspaceUserInfo && !canPerformWorkspaceMemberActions) {
return <NotAuthorizedView section="settings" />;
}

View file

@ -1,11 +1,10 @@
import { observer } from "mobx-react";
import { useParams, usePathname } from "next/navigation";
// constants
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
import { useUserPermissions } from "@/hooks/store";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web constants
import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
import { WORKSPACE_SETTINGS_LINKS } from "@/plane-web/constants/workspace";
// plane web helpers
import { shouldRenderSettingLink } from "@/plane-web/helpers/workspace.helper";
@ -15,19 +14,14 @@ export const MobileWorkspaceSettingsTabs = observer(() => {
const { workspaceSlug } = useParams();
const pathname = usePathname();
// mobx store
const {
membership: { currentWorkspaceRole },
} = useUser();
// derived values
const workspaceMemberInfo = currentWorkspaceRole || EUserWorkspaceRoles.GUEST;
const { allowPermissions } = useUserPermissions();
return (
<div className="flex-shrink-0 md:hidden sticky inset-0 flex overflow-x-auto bg-custom-background-100 z-10">
{WORKSPACE_SETTINGS_LINKS.map(
(item, index) =>
shouldRenderSettingLink(item.key) &&
workspaceMemberInfo >= item.access && (
allowPermissions(item.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString()) && (
<div
className={`${
item.highlight(pathname, `/${workspaceSlug}`)

View file

@ -6,11 +6,10 @@ import Link from "next/link";
import { useParams, usePathname } from "next/navigation";
// components
import { SidebarNavItem } from "@/components/sidebar";
// constants
import { EUserWorkspaceRoles } from "@/constants/workspace";
// hooks
import { useUser } from "@/hooks/store";
import { useUserPermissions } from "@/hooks/store";
// plane web constants
import { EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
import { WORKSPACE_SETTINGS_LINKS } from "@/plane-web/constants/workspace";
// plane web helpers
import { shouldRenderSettingLink } from "@/plane-web/helpers/workspace.helper";
@ -20,12 +19,7 @@ export const WorkspaceSettingsSidebar = observer(() => {
const { workspaceSlug } = useParams();
const pathname = usePathname();
// mobx store
const {
membership: { currentWorkspaceRole },
} = useUser();
// derived values
const workspaceMemberInfo = currentWorkspaceRole || EUserWorkspaceRoles.GUEST;
const { allowPermissions } = useUserPermissions();
return (
<div className="flex w-[280px] flex-col gap-6">
@ -35,7 +29,7 @@ export const WorkspaceSettingsSidebar = observer(() => {
{WORKSPACE_SETTINGS_LINKS.map(
(link) =>
shouldRenderSettingLink(link.key) &&
workspaceMemberInfo >= link.access && (
allowPermissions(link.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString()) && (
<Link key={link.key} href={`/${workspaceSlug}${link.href}`}>
<SidebarNavItem
key={link.key}

View file

@ -12,7 +12,8 @@ import { LogoSpinner } from "@/components/common";
import { PageHead } from "@/components/core";
import { DeleteWebhookModal, WebhookDeleteSection, WebhookForm } from "@/components/web-hooks";
// hooks
import { useUser, useWebhook, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWebhook, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const WebhookDetailsPage = observer(() => {
// states
@ -20,18 +21,17 @@ const WebhookDetailsPage = observer(() => {
// router
const { workspaceSlug, webhookId } = useParams();
// mobx store
const {
membership: { currentWorkspaceRole },
} = useUser();
const { currentWebhook, fetchWebhookById, updateWebhook } = useWebhook();
const { currentWorkspace } = useWorkspace();
const { allowPermissions } = useUserPermissions();
// TODO: fix this error
// useEffect(() => {
// if (isCreated !== "true") clearSecretKey();
// }, [clearSecretKey, isCreated]);
const isAdmin = currentWorkspaceRole === 20;
// derived values
const isAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Webhook` : undefined;
useSWR(

View file

@ -15,7 +15,8 @@ import { WebhooksList, CreateWebhookModal } from "@/components/web-hooks";
// constants
import { EmptyStateType } from "@/constants/empty-state";
// hooks
import { useUser, useWebhook, useWorkspace } from "@/hooks/store";
import { useUserPermissions, useWebhook, useWorkspace } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
const WebhooksListPage = observer(() => {
// states
@ -23,13 +24,13 @@ const WebhooksListPage = observer(() => {
// router
const { workspaceSlug } = useParams();
// mobx store
const {
canPerformWorkspaceAdminActions,
membership: { currentWorkspaceRole },
} = useUser();
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { fetchWebhooks, webhooks, clearSecretKey, webhookSecretKey, createWebhook } = useWebhook();
const { currentWorkspace } = useWorkspace();
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
useSWR(
workspaceSlug && canPerformWorkspaceAdminActions ? `WEBHOOKS_LIST_${workspaceSlug}` : null,
workspaceSlug && canPerformWorkspaceAdminActions ? () => fetchWebhooks(workspaceSlug.toString()) : null
@ -42,7 +43,7 @@ const WebhooksListPage = observer(() => {
if (!showCreateWebhookModal && webhookSecretKey) clearSecretKey();
}, [showCreateWebhookModal, webhookSecretKey, clearSecretKey]);
if (currentWorkspaceRole && !canPerformWorkspaceAdminActions) {
if (workspaceUserInfo && !canPerformWorkspaceAdminActions) {
return <NotAuthorizedView section="settings" />;
}

View file

@ -13,22 +13,29 @@ import {
import { SidebarFavoritesMenu } from "@/components/workspace/sidebar/favorites/favorites-menu";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useUser } from "@/hooks/store";
import { useAppTheme, useUserPermissions } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// plane web components
import useSize from "@/hooks/use-window-size";
import { SidebarAppSwitcher } from "@/plane-web/components/sidebar";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
export interface IAppSidebar {}
export const AppSidebar: FC<IAppSidebar> = observer(() => {
// store hooks
const { canPerformWorkspaceMemberActions } = useUser();
const { allowPermissions } = useUserPermissions();
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
const windowSize = useSize();
// refs
const ref = useRef<HTMLDivElement>(null);
// derived values
const canPerformWorkspaceMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
useOutsideClickDetector(ref, () => {
if (sidebarCollapsed === false) {
if (window.innerWidth < 768) {