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:
Prateek Shourya 2023-12-18 13:25:03 +05:30 committed by GitHub
parent b7a0f3c693
commit 184db0156c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 108 additions and 67 deletions

View File

@ -19,7 +19,7 @@ type Props = {
icon?: any;
text: string;
onClick: () => void;
};
} | null;
disabled?: boolean;
};

View File

@ -31,14 +31,18 @@ export const ProjectEmptyState: React.FC = observer(() => {
description:
"Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues.",
}}
primaryButton={{
text: "Create your first issue",
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
onClick: () => {
setTrackElement("PROJECT_EMPTY_STATE");
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
},
}}
primaryButton={
isEditingAllowed
? {
text: "Create your first issue",
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
onClick: () => {
setTrackElement("PROJECT_EMPTY_STATE");
commandPaletteStore.toggleCreateIssueModal(true, EProjectStore.PROJECT);
},
}
: null
}
disabled={!isEditingAllowed}
/>
</div>

View File

@ -96,11 +96,15 @@ export const ModulesListView: React.FC = observer(() => {
description:
"A cart module, a chassis module, and a warehouse module are all good example of this grouping.",
}}
primaryButton={{
icon: <Plus className="h-4 w-4" />,
text: "Build your first module",
onClick: () => commandPaletteStore.toggleCreateModuleModal(true),
}}
primaryButton={
isEditingAllowed
? {
icon: <Plus className="h-4 w-4" />,
text: "Build your first module",
onClick: () => commandPaletteStore.toggleCreateModuleModal(true),
}
: null
}
disabled={!isEditingAllowed}
/>
)}

View File

@ -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" />
<span className="p-0.5 text-xs text-custom-text-300">No links added yet</span>
</div>
<button
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
</button>
{isEditingAllowed && (
<button
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
</button>
)}
</div>
)}
</div>

View File

@ -93,13 +93,17 @@ export const WorkspaceDashboardView = observer(() => {
direction: "right",
description: "A project could be a products roadmap, a marketing campaign, or launching a new car.",
}}
primaryButton={{
text: "Build your first project",
onClick: () => {
setTrackElement("DASHBOARD_PAGE");
commandPaletteStore.toggleCreateProjectModal(true);
},
}}
primaryButton={
isEditingAllowed
? {
text: "Build your first project",
onClick: () => {
setTrackElement("DASHBOARD_PAGE");
commandPaletteStore.toggleCreateProjectModal(true);
},
}
: null
}
disabled={!isEditingAllowed}
/>
)

View File

@ -58,11 +58,15 @@ export const PagesListView: FC<IPagesListView> = observer(({ pages }) => {
"We wrote Parth and Meeras love story. You could write your projects mission, goals, and eventual vision.",
direction: "right",
}}
primaryButton={{
icon: <Plus className="h-4 w-4" />,
text: "Create your first page",
onClick: () => toggleCreatePageModal(true),
}}
primaryButton={
isEditingAllowed
? {
icon: <Plus className="h-4 w-4" />,
text: "Create your first page",
onClick: () => toggleCreatePageModal(true),
}
: null
}
disabled={!isEditingAllowed}
/>
)}

View File

@ -66,11 +66,15 @@ export const RecentPagesList: FC = observer(() => {
"We wrote Parth and Meeras love story. You could write your projects mission, goals, and eventual vision.",
direction: "right",
}}
primaryButton={{
icon: <Plus className="h-4 w-4" />,
text: "Create your first page",
onClick: () => commandPaletteStore.toggleCreatePageModal(true),
}}
primaryButton={
isEditingAllowed
? {
icon: <Plus className="h-4 w-4" />,
text: "Create your first page",
onClick: () => commandPaletteStore.toggleCreatePageModal(true),
}
: null
}
disabled={!isEditingAllowed}
/>
</>

View File

@ -67,13 +67,17 @@ export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
direction: "right",
description: "A project could be a products roadmap, a marketing campaign, or launching a new car.",
}}
primaryButton={{
text: "Start your first project",
onClick: () => {
setTrackElement("PROJECTS_EMPTY_STATE");
commandPaletteStore.toggleCreateProjectModal(true);
},
}}
primaryButton={
isEditingAllowed
? {
text: "Start your first project",
onClick: () => {
setTrackElement("PROJECTS_EMPTY_STATE");
commandPaletteStore.toggleCreateProjectModal(true);
},
}
: null
}
disabled={!isEditingAllowed}
/>
)}

View File

@ -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.",
direction: "right",
}}
primaryButton={{
icon: <Plus size={14} strokeWidth={2} />,
text: "Build your first view",
onClick: () => commandPaletteStore.toggleCreateViewModal(true),
}}
primaryButton={
isEditingAllowed
? {
icon: <Plus size={14} strokeWidth={2} />,
text: "Build your first view",
onClick: () => commandPaletteStore.toggleCreateViewModal(true),
}
: null
}
disabled={!isEditingAllowed}
/>
)}

View File

@ -9,7 +9,7 @@ import { CreateUpdateWorkspaceViewModal } from "components/workspace";
// icon
import { Plus } from "lucide-react";
// constants
import { DEFAULT_GLOBAL_VIEWS_LIST } from "constants/workspace";
import { DEFAULT_GLOBAL_VIEWS_LIST, EUserWorkspaceRoles } from "constants/workspace";
export const GlobalViewsHeader: React.FC = observer(() => {
const [createViewModal, setCreateViewModal] = useState(false);
@ -17,7 +17,10 @@ export const GlobalViewsHeader: React.FC = observer(() => {
const router = useRouter();
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
useEffect(() => {
@ -28,11 +31,13 @@ export const GlobalViewsHeader: React.FC = observer(() => {
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
}, [globalViewId]);
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
const isTabSelected = (tabKey: string) => router.pathname.includes(tabKey);
return (
<>
<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) => (
<Link key={tab.key} href={`/${workspaceSlug}/workspace-views/${tab.key}`}>
<span
@ -62,13 +67,15 @@ export const GlobalViewsHeader: React.FC = observer(() => {
</Link>
))}
<button
type="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"
onClick={() => setCreateViewModal(true)}
>
<Plus className="h-4 w-4 text-custom-primary-200" />
</button>
{isAuthorizedUser && (
<button
type="button"
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>
)}
</div>
</>
);

View File

@ -103,13 +103,17 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
description:
"A sprint, an iteration, and or any other term you use for weekly or fortnightly tracking of work is a cycle.",
}}
primaryButton={{
icon: <Plus className="h-4 w-4" />,
text: "Set your first cycle",
onClick: () => {
setCreateModal(true);
},
}}
primaryButton={
isEditingAllowed
? {
icon: <Plus className="h-4 w-4" />,
text: "Set your first cycle",
onClick: () => {
setCreateModal(true);
},
}
: null
}
disabled={!isEditingAllowed}
/>
</div>