chore: guest user profile access-related problem (#3089)

* fix: resolve guest user profile access-related problem

* chore: header and app sidebar permission validation added
This commit is contained in:
Anmol Singh Bhatia 2023-12-13 23:05:50 +05:30 committed by GitHub
parent 2605b938f0
commit 6c61fbd102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 37 deletions

View File

@ -16,6 +16,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption
// constants // constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { EFilterType } from "store/issues/types"; import { EFilterType } from "store/issues/types";
import { EUserWorkspaceRoles } from "constants/workspace";
const GLOBAL_VIEW_LAYOUTS = [ const GLOBAL_VIEW_LAYOUTS = [
{ key: "list", title: "List", link: "/workspace-views", icon: List }, { key: "list", title: "List", link: "/workspace-views", icon: List },
@ -38,7 +39,7 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
workspace: { workspaceLabels }, workspace: { workspaceLabels },
workspaceMember: { workspaceMembers }, workspaceMember: { workspaceMembers },
project: { workspaceProjects }, project: { workspaceProjects },
user: { currentWorkspaceRole },
workspaceGlobalIssuesFilter: { issueFilters, updateFilters }, workspaceGlobalIssuesFilter: { issueFilters, updateFilters },
} = useMobxStore(); } = useMobxStore();
@ -77,6 +78,8 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
[workspaceSlug, updateFilters] [workspaceSlug, updateFilters]
); );
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
return ( return (
<> <>
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} /> <CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
@ -142,10 +145,11 @@ export const GlobalIssuesHeader: React.FC<Props> = observer((props) => {
</FiltersDropdown> </FiltersDropdown>
</> </>
)} )}
{isAuthorizedUser && (
<Button variant="primary" size="sm" prependIcon={<PlusIcon />} onClick={() => setCreateViewModal(true)}> <Button variant="primary" size="sm" prependIcon={<PlusIcon />} onClick={() => setCreateViewModal(true)}>
New View New View
</Button> </Button>
)}
</div> </div>
</div> </div>
</> </>

View File

@ -5,6 +5,8 @@ import { Breadcrumbs, Button } from "@plane/ui";
// hooks // hooks
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
export const ProjectsHeader = observer(() => { export const ProjectsHeader = observer(() => {
const router = useRouter(); const router = useRouter();
@ -15,10 +17,13 @@ export const ProjectsHeader = observer(() => {
project: projectStore, project: projectStore,
commandPalette: commandPaletteStore, commandPalette: commandPaletteStore,
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
user: { currentWorkspaceRole },
} = useMobxStore(); } = useMobxStore();
const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : []; const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : [];
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
return ( return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4"> <div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap"> <div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
@ -44,17 +49,18 @@ export const ProjectsHeader = observer(() => {
/> />
</div> </div>
)} )}
{isAuthorizedUser && (
<Button <Button
prependIcon={<Plus />} prependIcon={<Plus />}
size="sm" size="sm"
onClick={() => { onClick={() => {
setTrackElement("PROJECTS_PAGE_HEADER"); setTrackElement("PROJECTS_PAGE_HEADER");
commandPaletteStore.toggleCreateProjectModal(true); commandPaletteStore.toggleCreateProjectModal(true);
}} }}
> >
Add Project Add Project
</Button> </Button>
)}
</div> </div>
</div> </div>
); );

View File

@ -17,6 +17,8 @@ import { orderArrayBy } from "helpers/array.helper";
import { IProject } from "types"; import { IProject } from "types";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
export const ProjectSidebarList: FC = observer(() => { export const ProjectSidebarList: FC = observer(() => {
// states // states
@ -31,6 +33,7 @@ export const ProjectSidebarList: FC = observer(() => {
project: { joinedProjects, favoriteProjects, orderProjectsWithSortOrder, updateProjectView }, project: { joinedProjects, favoriteProjects, orderProjectsWithSortOrder, updateProjectView },
commandPalette: { toggleCreateProjectModal }, commandPalette: { toggleCreateProjectModal },
trackEvent: { setTrackElement }, trackEvent: { setTrackElement },
user: { currentWorkspaceRole },
} = useMobxStore(); } = useMobxStore();
// router // router
const router = useRouter(); const router = useRouter();
@ -39,6 +42,8 @@ export const ProjectSidebarList: FC = observer(() => {
// toast // toast
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
const orderedJoinedProjects: IProject[] | undefined = joinedProjects const orderedJoinedProjects: IProject[] | undefined = joinedProjects
? orderArrayBy(joinedProjects, "sort_order", "ascending") ? orderArrayBy(joinedProjects, "sort_order", "ascending")
: undefined; : undefined;
@ -138,16 +143,18 @@ export const ProjectSidebarList: FC = observer(() => {
<ChevronRight className="h-3 w-3 opacity-0 group-hover:opacity-100" /> <ChevronRight className="h-3 w-3 opacity-0 group-hover:opacity-100" />
)} )}
</Disclosure.Button> </Disclosure.Button>
<button {isAuthorizedUser && (
className="opacity-0 group-hover:opacity-100" <button
onClick={() => { className="opacity-0 group-hover:opacity-100"
setTrackElement("APP_SIDEBAR_FAVORITES_BLOCK"); onClick={() => {
setIsFavoriteProjectCreate(true); setTrackElement("APP_SIDEBAR_FAVORITES_BLOCK");
setIsProjectModalOpen(true); setIsFavoriteProjectCreate(true);
}} setIsProjectModalOpen(true);
> }}
<Plus className="h-3 w-3" /> >
</button> <Plus className="h-3 w-3" />
</button>
)}
</div> </div>
)} )}
<Transition <Transition
@ -213,15 +220,17 @@ export const ProjectSidebarList: FC = observer(() => {
<ChevronRight className="h-3 w-3 opacity-0 group-hover:opacity-100" /> <ChevronRight className="h-3 w-3 opacity-0 group-hover:opacity-100" />
)} )}
</Disclosure.Button> </Disclosure.Button>
<button {isAuthorizedUser && (
className="opacity-0 group-hover:opacity-100" <button
onClick={() => { className="opacity-0 group-hover:opacity-100"
setIsFavoriteProjectCreate(false); onClick={() => {
setIsProjectModalOpen(true); setIsFavoriteProjectCreate(false);
}} setIsProjectModalOpen(true);
> }}
<Plus className="h-3 w-3" /> >
</button> <Plus className="h-3 w-3" />
</button>
)}
</div> </div>
)} )}
<Transition <Transition
@ -260,7 +269,7 @@ export const ProjectSidebarList: FC = observer(() => {
</Droppable> </Droppable>
</DragDropContext> </DragDropContext>
{joinedProjects && joinedProjects.length === 0 && ( {isAuthorizedUser && joinedProjects && joinedProjects.length === 0 && (
<button <button
type="button" type="button"
className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200" className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200"

View File

@ -1,4 +1,5 @@
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
// mobx store // mobx store
import { useMobxStore } from "lib/mobx/store-provider"; import { useMobxStore } from "lib/mobx/store-provider";
// components // components
@ -14,6 +15,7 @@ const AUTHORIZED_ROLES = [20, 15, 10];
export const ProfileAuthWrapper: React.FC<Props> = observer((props) => { export const ProfileAuthWrapper: React.FC<Props> = observer((props) => {
const { children, className, showProfileIssuesFilter } = props; const { children, className, showProfileIssuesFilter } = props;
const router = useRouter();
const { const {
user: { currentWorkspaceRole }, user: { currentWorkspaceRole },
@ -23,12 +25,14 @@ export const ProfileAuthWrapper: React.FC<Props> = observer((props) => {
const isAuthorized = AUTHORIZED_ROLES.includes(currentWorkspaceRole); const isAuthorized = AUTHORIZED_ROLES.includes(currentWorkspaceRole);
const isAuthorizedPath = router.pathname.includes("assigned" || "created" || "subscribed");
return ( return (
<div className="h-full w-full md:flex md:flex-row-reverse md:overflow-hidden"> <div className="h-full w-full md:flex md:flex-row-reverse md:overflow-hidden">
<ProfileSidebar /> <ProfileSidebar />
<div className="flex w-full flex-col md:h-full md:overflow-hidden"> <div className="flex w-full flex-col md:h-full md:overflow-hidden">
<ProfileNavbar isAuthorized={isAuthorized} showProfileIssuesFilter={showProfileIssuesFilter} /> <ProfileNavbar isAuthorized={isAuthorized} showProfileIssuesFilter={showProfileIssuesFilter} />
{isAuthorized ? ( {isAuthorized || !isAuthorizedPath ? (
<div className={`w-full overflow-hidden md:h-full ${className}`}>{children}</div> <div className={`w-full overflow-hidden md:h-full ${className}`}>{children}</div>
) : ( ) : (
<div className="grid h-full w-full place-items-center text-custom-text-200"> <div className="grid h-full w-full place-items-center text-custom-text-200">