2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 12:06:44 +00:00

[PUI] Tab permissions (#7692)

* [PUI] Hide main nav tabs based on user roles

* Add permission checks on top-level pages

* Specify return type
This commit is contained in:
Oliver 2024-07-19 16:54:55 +10:00 committed by GitHub
parent 0a2817dbf3
commit d4cd7d4a72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 19 deletions

View File

@ -2,7 +2,7 @@ import { ActionIcon, Container, Group, Indicator, Tabs } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { IconBell, IconSearch } from '@tabler/icons-react'; import { IconBell, IconSearch } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useEffect, useState } from 'react'; import { ReactNode, useEffect, useMemo, useState } from 'react';
import { useMatch, useNavigate } from 'react-router-dom'; import { useMatch, useNavigate } from 'react-router-dom';
import { api } from '../../App'; import { api } from '../../App';
@ -132,10 +132,35 @@ export function Header() {
} }
function NavTabs() { function NavTabs() {
const user = useUserState();
const navigate = useNavigate(); const navigate = useNavigate();
const match = useMatch(':tabName/*'); const match = useMatch(':tabName/*');
const tabValue = match?.params.tabName; const tabValue = match?.params.tabName;
const tabs: ReactNode[] = useMemo(() => {
let _tabs: ReactNode[] = [];
mainNavTabs.forEach((tab) => {
if (tab.role && !user.hasViewRole(tab.role)) {
return;
}
_tabs.push(
<Tabs.Tab
value={tab.name}
key={tab.name}
onClick={(event: any) =>
navigateToLink(`/${tab.name}`, navigate, event)
}
>
{tab.text}
</Tabs.Tab>
);
});
return _tabs;
}, [mainNavTabs, user]);
return ( return (
<Tabs <Tabs
defaultValue="home" defaultValue="home"
@ -146,19 +171,7 @@ function NavTabs() {
}} }}
value={tabValue} value={tabValue}
> >
<Tabs.List> <Tabs.List>{tabs.map((tab) => tab)}</Tabs.List>
{mainNavTabs.map((tab) => (
<Tabs.Tab
value={tab.name}
key={tab.name}
onClick={(event: any) =>
navigateToLink(`/${tab.name}`, navigate, event)
}
>
{tab.text}
</Tabs.Tab>
))}
</Tabs.List>
</Tabs> </Tabs>
); );
} }

View File

@ -3,6 +3,7 @@ import { openContextModal } from '@mantine/modals';
import { DocumentationLinkItem } from '../components/items/DocumentationLinks'; import { DocumentationLinkItem } from '../components/items/DocumentationLinks';
import { StylishText } from '../components/items/StylishText'; import { StylishText } from '../components/items/StylishText';
import { UserRoles } from '../enums/Roles';
import { IS_DEV_OR_DEMO } from '../main'; import { IS_DEV_OR_DEMO } from '../main';
export const footerLinks = [ export const footerLinks = [
@ -25,12 +26,17 @@ export const footerLinks = [
export const navTabs = [ export const navTabs = [
{ text: <Trans>Home</Trans>, name: 'home' }, { text: <Trans>Home</Trans>, name: 'home' },
{ text: <Trans>Dashboard</Trans>, name: 'dashboard' }, { text: <Trans>Dashboard</Trans>, name: 'dashboard' },
{ text: <Trans>Parts</Trans>, name: 'part' }, { text: <Trans>Parts</Trans>, name: 'part', role: UserRoles.part },
{ text: <Trans>Stock</Trans>, name: 'stock' }, { text: <Trans>Stock</Trans>, name: 'stock', role: UserRoles.stock },
{ text: <Trans>Build</Trans>, name: 'build' }, { text: <Trans>Build</Trans>, name: 'build', role: UserRoles.build },
{ text: <Trans>Purchasing</Trans>, name: 'purchasing' }, {
{ text: <Trans>Sales</Trans>, name: 'sales' } text: <Trans>Purchasing</Trans>,
name: 'purchasing',
role: UserRoles.purchase_order
},
{ text: <Trans>Sales</Trans>, name: 'sales', role: UserRoles.sales_order }
]; ];
if (IS_DEV_OR_DEMO) { if (IS_DEV_OR_DEMO) {
navTabs.push({ text: <Trans>Playground</Trans>, name: 'playground' }); navTabs.push({ text: <Trans>Playground</Trans>, name: 'playground' });
} }

View File

@ -1,13 +1,22 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Stack } from '@mantine/core'; import { Stack } from '@mantine/core';
import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { UserRoles } from '../../enums/Roles';
import { useUserState } from '../../states/UserState';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable'; import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
/** /**
* Build Order index page * Build Order index page
*/ */
export default function BuildIndex() { export default function BuildIndex() {
const user = useUserState();
if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.build)) {
return <PermissionDenied />;
}
return ( return (
<Stack> <Stack>
<PageDetail title={t`Build Orders`} actions={[]} /> <PageDetail title={t`Build Orders`} actions={[]} />

View File

@ -7,12 +7,17 @@ import {
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup'; import { PanelGroup } from '../../components/nav/PanelGroup';
import { UserRoles } from '../../enums/Roles';
import { useUserState } from '../../states/UserState';
import { CompanyTable } from '../../tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable'; import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
export default function PurchasingIndex() { export default function PurchasingIndex() {
const user = useUserState();
const panels = useMemo(() => { const panels = useMemo(() => {
return [ return [
{ {
@ -46,6 +51,10 @@ export default function PurchasingIndex() {
]; ];
}, []); }, []);
if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.purchase_order)) {
return <PermissionDenied />;
}
return ( return (
<Stack> <Stack>
<PageDetail title={t`Purchasing`} /> <PageDetail title={t`Purchasing`} />

View File

@ -7,13 +7,18 @@ import {
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup'; import { PanelGroup } from '../../components/nav/PanelGroup';
import { UserRoles } from '../../enums/Roles';
import { useUserState } from '../../states/UserState';
import { CompanyTable } from '../../tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable'; import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable';
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable'; import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
export default function PurchasingIndex() { export default function PurchasingIndex() {
const user = useUserState();
const panels = useMemo(() => { const panels = useMemo(() => {
return [ return [
{ {
@ -39,6 +44,10 @@ export default function PurchasingIndex() {
]; ];
}, []); }, []);
if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.sales_order)) {
return <PermissionDenied />;
}
return ( return (
<Stack> <Stack>
<PageDetail title={t`Sales`} /> <PageDetail title={t`Sales`} />