diff --git a/src/frontend/src/components/nav/Layout.tsx b/src/frontend/src/components/nav/Layout.tsx index 7ab9435bbf..b808959436 100644 --- a/src/frontend/src/components/nav/Layout.tsx +++ b/src/frontend/src/components/nav/Layout.tsx @@ -56,7 +56,7 @@ export default function LayoutComponent() { setActions(defaultActions); setCustomActions(false); } - }, [location]); + }, [customActions, defaultActions, location]); return ( diff --git a/src/frontend/src/defaults/actions.tsx b/src/frontend/src/defaults/actions.tsx index 665271391b..c8ac22fd81 100644 --- a/src/frontend/src/defaults/actions.tsx +++ b/src/frontend/src/defaults/actions.tsx @@ -1,11 +1,22 @@ import { t } from '@lingui/core/macro'; import type { SpotlightActionData } from '@mantine/spotlight'; -import { IconBarcode, IconLink, IconPointer } from '@tabler/icons-react'; +import { + IconBarcode, + IconLink, + IconPointer, + IconSettings, + IconUserBolt, + IconUserCog +} from '@tabler/icons-react'; import type { NavigateFunction } from 'react-router-dom'; +import { ModelInformationDict } from '@lib/enums/ModelInformation'; +import { UserRoles } from '@lib/index'; import { openContextModal } from '@mantine/modals'; +import { useMemo } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { useLocalState } from '../states/LocalState'; +import { useGlobalSettingsState } from '../states/SettingsStates'; import { useUserState } from '../states/UserState'; import { aboutInvenTree, docLinks, licenseInfo, serverInfo } from './links'; @@ -20,71 +31,133 @@ export function getActions(navigate: NavigateFunction) { const setNavigationOpen = useLocalState( useShallow((state) => state.setNavigationOpen) ); - const { user } = useUserState(); + const globalSettings = useGlobalSettingsState(); + const user = useUserState(); - const actions: SpotlightActionData[] = [ - { - id: 'dashboard', - label: t`Dashboard`, - description: t`Go to the InvenTree dashboard`, - onClick: () => navigate('/'), - leftSection: - }, - { - id: 'documentation', - label: t`Documentation`, - description: t`Visit the documentation to learn more about InvenTree`, - onClick: () => { - window.location.href = docLinks.faq; + const actions: SpotlightActionData[] = useMemo(() => { + const _actions: SpotlightActionData[] = [ + { + id: 'dashboard', + label: t`Dashboard`, + description: t`Go to the InvenTree dashboard`, + onClick: () => navigate('/'), + leftSection: }, - leftSection: - }, - { - id: 'about', - label: t`About InvenTree`, - description: t`About the InvenTree org`, - onClick: () => aboutInvenTree(), - leftSection: - }, - { - id: 'server-info', - label: t`Server Information`, - description: t`About this InvenTree instance`, - onClick: () => serverInfo(), - leftSection: - }, - { - id: 'license-info', - label: t`License Information`, - description: t`Licenses for dependencies of the service`, - onClick: () => licenseInfo(), - leftSection: - }, - { - id: 'navigation', - label: t`Open Navigation`, - description: t`Open the main navigation menu`, - onClick: () => setNavigationOpen(true), - leftSection: - }, - { - id: 'scan', - label: t`Scan`, - description: t`Scan a barcode or QR code`, - onClick: () => openQrModal(navigate), - leftSection: - } - ]; + { + id: 'documentation', + label: t`Documentation`, + description: t`Visit the documentation to learn more about InvenTree`, + onClick: () => { + window.location.href = docLinks.faq; + }, + leftSection: + }, + { + id: 'about', + label: t`About InvenTree`, + description: t`About the InvenTree org`, + onClick: () => aboutInvenTree(), + leftSection: + }, + { + id: 'server-info', + label: t`Server Information`, + description: t`About this InvenTree instance`, + onClick: () => serverInfo(), + leftSection: + }, + { + id: 'license-info', + label: t`License Information`, + description: t`Licenses for dependencies of the service`, + onClick: () => licenseInfo(), + leftSection: + }, + { + id: 'navigation', + label: t`Open Navigation`, + description: t`Open the main navigation menu`, + onClick: () => setNavigationOpen(true), + leftSection: + }, + { + id: 'scan', + label: t`Scan`, + description: t`Scan a barcode or QR code`, + onClick: () => openQrModal(navigate), + leftSection: + }, + { + id: 'user-settings', + label: t`User Settings`, - // Staff actions - user?.is_staff && - actions.push({ - id: 'admin-center', - label: t`Admin Center`, - description: t`Go to the Admin Center`, - onClick: () => {}, /// navigate(menuItems['settings-admin'].link),} - leftSection: - }); + description: t`Go to your user settings`, + onClick: () => navigate('/settings/user'), + leftSection: + } + ]; + + // Page Actions + user?.hasViewRole(UserRoles.purchase_order) && + _actions.push({ + id: 'purchase-orders', + label: t`Purchase Orders`, + description: t`Go to Purchase Orders`, + onClick: () => + navigate(ModelInformationDict['purchaseorder'].url_overview!), + leftSection: + }); + + user?.hasViewRole(UserRoles.sales_order) && + _actions.push({ + id: 'sales-orders', + label: t`Sales Orders`, + description: t`Go to Sales Orders`, + onClick: () => + navigate(ModelInformationDict['salesorder'].url_overview!), + leftSection: + }); + + globalSettings.isSet('RETURNORDER_ENABLED') && + user?.hasViewRole(UserRoles.return_order) && + _actions.push({ + id: 'return-orders', + label: t`Return Orders`, + description: t`Go to Return Orders`, + onClick: () => + navigate(ModelInformationDict['returnorder'].url_overview!), + leftSection: + }); + + user?.hasViewRole(UserRoles.build) && + _actions.push({ + id: 'builds', + label: t`Build Orders`, + description: t`Go to Build Orders`, + onClick: () => navigate(ModelInformationDict['build'].url_overview!), + leftSection: + }); + + user?.isStaff() && + _actions.push({ + id: 'system-settings', + label: t`System Settings`, + description: t`Go to System Settings`, + onClick: () => navigate('/settings/system'), + leftSection: + }); + + user?.isStaff() && + _actions.push({ + id: 'admin-center', + label: t`Admin Center`, + description: t`Go to the Admin Center`, + onClick: () => {}, /// navigate(menuItems['settings-admin'].link),} + leftSection: + }); + + return _actions; + }, [navigate, setNavigationOpen, globalSettings, user]); return actions; } diff --git a/src/frontend/tests/pui_settings.spec.ts b/src/frontend/tests/pui_settings.spec.ts index edbcea7b65..52361ab0bd 100644 --- a/src/frontend/tests/pui_settings.spec.ts +++ b/src/frontend/tests/pui_settings.spec.ts @@ -336,12 +336,29 @@ test('Settings - Admin - Barcode History', async ({ browser }) => { for (let i = 0; i < barcodes.length; i++) { const barcode = barcodes[i]; - await api.post('barcode/', { - data: { - barcode: barcode - }, - timeout: 5000 - }); + + let attempts = 5; + + while (attempts > 0) { + let result = false; + + await api + .post('barcode/', { + data: { + barcode: barcode + }, + timeout: 5000 + }) + .then(() => { + result = true; + }); + + if (result) { + break; + } else { + attempts -= 1; + } + } } await page.getByRole('button', { name: 'admin' }).click();