forked from github/plane
User role validation across workspace and projects. (#3167)
* chore: remove `add link` button for guests & viewer in modules sidebar. * chore: remove `+` (add view) icon for guests & viewer in `All Issues`. * chore: remove `Start Project` button from Dashboard & Projects empty state for guests & viewers. * chore: project level user role validation for empty states.
This commit is contained in:
parent
b7a0f3c693
commit
184db0156c
@ -19,7 +19,7 @@ type Props = {
|
|||||||
icon?: any;
|
icon?: any;
|
||||||
text: string;
|
text: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
};
|
} | null;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,14 +31,18 @@ export const ProjectEmptyState: React.FC = observer(() => {
|
|||||||
description:
|
description:
|
||||||
"Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.",
|
"Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
text: "Create your first issue",
|
isEditingAllowed
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
? {
|
||||||
onClick: () => {
|
text: "Create your first issue",
|
||||||
setTrackElement("PROJECT_EMPTY_STATE");
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
|
onClick: () => {
|
||||||
},
|
setTrackElement("PROJECT_EMPTY_STATE");
|
||||||
}}
|
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,11 +96,15 @@ export const ModulesListView: React.FC = observer(() => {
|
|||||||
description:
|
description:
|
||||||
"A cart module, a chassis module, and a warehouse module are all good example of this grouping.",
|
"A cart module, a chassis module, and a warehouse module are all good example of this grouping.",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
icon: <Plus className="h-4 w-4" />,
|
isEditingAllowed
|
||||||
text: "Build your first module",
|
? {
|
||||||
onClick: () => commandPaletteStore.toggleCreateModuleModal(true),
|
icon: <Plus className="h-4 w-4" />,
|
||||||
}}
|
text: "Build your first module",
|
||||||
|
onClick: () => commandPaletteStore.toggleCreateModuleModal(true),
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -626,13 +626,15 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<Info className="h-3.5 w-3.5 stroke-[1.5] text-custom-text-300" />
|
<Info className="h-3.5 w-3.5 stroke-[1.5] text-custom-text-300" />
|
||||||
<span className="p-0.5 text-xs text-custom-text-300">No links added yet</span>
|
<span className="p-0.5 text-xs text-custom-text-300">No links added yet</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
{isEditingAllowed && (
|
||||||
className="flex items-center gap-1.5 text-sm font-medium text-custom-primary-100"
|
<button
|
||||||
onClick={() => setModuleLinkModal(true)}
|
className="flex items-center gap-1.5 text-sm font-medium text-custom-primary-100"
|
||||||
>
|
onClick={() => setModuleLinkModal(true)}
|
||||||
<Plus className="h-3 w-3" />
|
>
|
||||||
Add link
|
<Plus className="h-3 w-3" />
|
||||||
</button>
|
Add link
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,13 +93,17 @@ export const WorkspaceDashboardView = observer(() => {
|
|||||||
direction: "right",
|
direction: "right",
|
||||||
description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.",
|
description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
text: "Build your first project",
|
isEditingAllowed
|
||||||
onClick: () => {
|
? {
|
||||||
setTrackElement("DASHBOARD_PAGE");
|
text: "Build your first project",
|
||||||
commandPaletteStore.toggleCreateProjectModal(true);
|
onClick: () => {
|
||||||
},
|
setTrackElement("DASHBOARD_PAGE");
|
||||||
}}
|
commandPaletteStore.toggleCreateProjectModal(true);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -58,11 +58,15 @@ export const PagesListView: FC<IPagesListView> = observer(({ pages }) => {
|
|||||||
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
||||||
direction: "right",
|
direction: "right",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
icon: <Plus className="h-4 w-4" />,
|
isEditingAllowed
|
||||||
text: "Create your first page",
|
? {
|
||||||
onClick: () => toggleCreatePageModal(true),
|
icon: <Plus className="h-4 w-4" />,
|
||||||
}}
|
text: "Create your first page",
|
||||||
|
onClick: () => toggleCreatePageModal(true),
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -66,11 +66,15 @@ export const RecentPagesList: FC = observer(() => {
|
|||||||
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
"We wrote Parth and Meera’s love story. You could write your project’s mission, goals, and eventual vision.",
|
||||||
direction: "right",
|
direction: "right",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
icon: <Plus className="h-4 w-4" />,
|
isEditingAllowed
|
||||||
text: "Create your first page",
|
? {
|
||||||
onClick: () => commandPaletteStore.toggleCreatePageModal(true),
|
icon: <Plus className="h-4 w-4" />,
|
||||||
}}
|
text: "Create your first page",
|
||||||
|
onClick: () => commandPaletteStore.toggleCreatePageModal(true),
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -67,13 +67,17 @@ export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
|
|||||||
direction: "right",
|
direction: "right",
|
||||||
description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.",
|
description: "A project could be a product’s roadmap, a marketing campaign, or launching a new car.",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
text: "Start your first project",
|
isEditingAllowed
|
||||||
onClick: () => {
|
? {
|
||||||
setTrackElement("PROJECTS_EMPTY_STATE");
|
text: "Start your first project",
|
||||||
commandPaletteStore.toggleCreateProjectModal(true);
|
onClick: () => {
|
||||||
},
|
setTrackElement("PROJECTS_EMPTY_STATE");
|
||||||
}}
|
commandPaletteStore.toggleCreateProjectModal(true);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -76,11 +76,15 @@ export const ProjectViewsList = observer(() => {
|
|||||||
description: "You can create a view from here with as many properties as filters as you see fit.",
|
description: "You can create a view from here with as many properties as filters as you see fit.",
|
||||||
direction: "right",
|
direction: "right",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
icon: <Plus size={14} strokeWidth={2} />,
|
isEditingAllowed
|
||||||
text: "Build your first view",
|
? {
|
||||||
onClick: () => commandPaletteStore.toggleCreateViewModal(true),
|
icon: <Plus size={14} strokeWidth={2} />,
|
||||||
}}
|
text: "Build your first view",
|
||||||
|
onClick: () => commandPaletteStore.toggleCreateViewModal(true),
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -9,7 +9,7 @@ import { CreateUpdateWorkspaceViewModal } from "components/workspace";
|
|||||||
// icon
|
// icon
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { DEFAULT_GLOBAL_VIEWS_LIST } from "constants/workspace";
|
import { DEFAULT_GLOBAL_VIEWS_LIST, EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export const GlobalViewsHeader: React.FC = observer(() => {
|
export const GlobalViewsHeader: React.FC = observer(() => {
|
||||||
const [createViewModal, setCreateViewModal] = useState(false);
|
const [createViewModal, setCreateViewModal] = useState(false);
|
||||||
@ -17,7 +17,10 @@ export const GlobalViewsHeader: React.FC = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, globalViewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
|
|
||||||
const { globalViews: globalViewsStore } = useMobxStore();
|
const {
|
||||||
|
globalViews: globalViewsStore,
|
||||||
|
user: { currentWorkspaceRole },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
// bring the active view to the centre of the header
|
// bring the active view to the centre of the header
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -28,11 +31,13 @@ export const GlobalViewsHeader: React.FC = observer(() => {
|
|||||||
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
||||||
}, [globalViewId]);
|
}, [globalViewId]);
|
||||||
|
|
||||||
|
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
|
||||||
|
|
||||||
const isTabSelected = (tabKey: string) => router.pathname.includes(tabKey);
|
const isTabSelected = (tabKey: string) => router.pathname.includes(tabKey);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
|
<CreateUpdateWorkspaceViewModal isOpen={createViewModal} onClose={() => setCreateViewModal(false)} />
|
||||||
<div className="group relative flex w-full items-center overflow-x-scroll border-b border-custom-border-200 px-4">
|
<div className="group relative flex w-full items-center overflow-x-scroll border-b border-custom-border-200 px-4 py-2">
|
||||||
{DEFAULT_GLOBAL_VIEWS_LIST.map((tab) => (
|
{DEFAULT_GLOBAL_VIEWS_LIST.map((tab) => (
|
||||||
<Link key={tab.key} href={`/${workspaceSlug}/workspace-views/${tab.key}`}>
|
<Link key={tab.key} href={`/${workspaceSlug}/workspace-views/${tab.key}`}>
|
||||||
<span
|
<span
|
||||||
@ -62,13 +67,15 @@ export const GlobalViewsHeader: React.FC = observer(() => {
|
|||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<button
|
{isAuthorizedUser && (
|
||||||
type="button"
|
<button
|
||||||
className="sticky -right-4 flex w-12 flex-shrink-0 items-center justify-center border-transparent bg-custom-background-100 py-3 hover:border-custom-border-200 hover:text-custom-text-400"
|
type="button"
|
||||||
onClick={() => setCreateViewModal(true)}
|
className="sticky -right-4 flex w-12 flex-shrink-0 items-center justify-center border-transparent bg-custom-background-100 hover:border-custom-border-200 hover:text-custom-text-400"
|
||||||
>
|
onClick={() => setCreateViewModal(true)}
|
||||||
<Plus className="h-4 w-4 text-custom-primary-200" />
|
>
|
||||||
</button>
|
<Plus className="h-4 w-4 text-custom-primary-200" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -103,13 +103,17 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
|
|||||||
description:
|
description:
|
||||||
"A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.",
|
"A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.",
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={
|
||||||
icon: <Plus className="h-4 w-4" />,
|
isEditingAllowed
|
||||||
text: "Set your first cycle",
|
? {
|
||||||
onClick: () => {
|
icon: <Plus className="h-4 w-4" />,
|
||||||
setCreateModal(true);
|
text: "Set your first cycle",
|
||||||
},
|
onClick: () => {
|
||||||
}}
|
setCreateModal(true);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
disabled={!isEditingAllowed}
|
disabled={!isEditingAllowed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user