From ba4b1bc07a0ff7b8857d7379737c2c3e9209bf31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 08:48:59 +1000 Subject: [PATCH 1/4] Bump sentry-sdk from 2.7.0 to 2.8.0 in /src/backend (#7683) * Bump sentry-sdk from 2.7.0 to 2.8.0 in /src/backend Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.7.0 to 2.8.0. - [Release notes](https://github.com/getsentry/sentry-python/releases) - [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-python/compare/2.7.0...2.8.0) --- updated-dependencies: - dependency-name: sentry-sdk dependency-type: direct:production ... Signed-off-by: dependabot[bot] * fix requirements format --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthias Mair --- src/backend/requirements-dev.txt | 6 +++--- src/backend/requirements.txt | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/backend/requirements-dev.txt b/src/backend/requirements-dev.txt index 46886c0cf4..c22dad58b4 100644 --- a/src/backend/requirements-dev.txt +++ b/src/backend/requirements-dev.txt @@ -398,9 +398,9 @@ pyyaml==6.0.1 \ # via # -c src/backend/requirements.txt # pre-commit -setuptools==70.3.0 \ - --hash=sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5 \ - --hash=sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc +setuptools==71.0.3 \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 # via # -c src/backend/requirements.txt # -r src/backend/requirements-dev.in diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 1c62ad36a0..1cfa4a0c7f 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -1543,15 +1543,15 @@ rpds-py==0.18.1 \ # via # jsonschema # referencing -sentry-sdk==2.7.0 \ - --hash=sha256:d846a211d4a0378b289ced3c434480945f110d0ede00450ba631fc2852e7a0d4 \ - --hash=sha256:db9594c27a4d21c1ebad09908b1f0dc808ef65c2b89c1c8e7e455143262e37c1 +sentry-sdk==2.8.0 \ + --hash=sha256:6051562d2cfa8087bb8b4b8b79dc44690f8a054762a29c07e22588b1f619bfb5 \ + --hash=sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f # via # -r src/backend/requirements.in # django-q-sentry -setuptools==70.3.0 \ - --hash=sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5 \ - --hash=sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc +setuptools==71.0.3 \ + --hash=sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d \ + --hash=sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207 # via # -r src/backend/requirements.in # django-money From 0f1645e3899ce8bfc58da917c4c176e5c21c1acd Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Fri, 19 Jul 2024 00:49:51 +0200 Subject: [PATCH 2/4] Various small packaging fixes (#7686) * move repo setting for packager to yml * fix python detection * fix persistent setting writing (during onboarding) * clean up OS before uninstalling --- .pkgr.yml | 2 ++ contrib/packager.io/before.sh | 9 ++++----- contrib/packager.io/functions.sh | 14 +++++++------- contrib/packager.io/preinstall.sh | 2 +- src/backend/InvenTree/config_template.yaml | 2 ++ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.pkgr.yml b/.pkgr.yml index 4ddf0a86f5..970723ef9d 100644 --- a/.pkgr.yml +++ b/.pkgr.yml @@ -14,8 +14,10 @@ env: - INVENTREE_BACKUP_DIR=/opt/inventree/backup - INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt - INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml + - APP_REPO=inventree/InvenTree before_install: contrib/packager.io/preinstall.sh after_install: contrib/packager.io/postinstall.sh +before_remove: contrib/packager.io/preinstall.sh before: - contrib/packager.io/before.sh dependencies: diff --git a/contrib/packager.io/before.sh b/contrib/packager.io/before.sh index 41ca3688b5..0da421fd38 100755 --- a/contrib/packager.io/before.sh +++ b/contrib/packager.io/before.sh @@ -6,7 +6,6 @@ set -eu # The sha is the second element in APP_PKG_ITERATION -REPO="inventree/InvenTree" VERSION="$APP_PKG_VERSION-$APP_PKG_ITERATION" SHA=$(echo $APP_PKG_ITERATION | cut -d'.' -f2) @@ -15,17 +14,17 @@ echo "INFO collection | Getting info from github for commit $SHA" curl -L -s -f \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/$REPO/commits/$SHA > commit.json + https://api.github.com/repos/$APP_REPO/commits/$SHA > commit.json echo "INFO collection | Got commit.json with size $(wc -c commit.json)" curl -L -s -f \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/$REPO/commits/$SHA/branches-where-head > branches.json + https://api.github.com/repos/$APP_REPO/commits/$SHA/branches-where-head > branches.json echo "INFO collection | Got branches.json with size $(wc -c branches.json)" curl -L -s -f \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/$REPO/commits/$APP_PKG_VERSION > tag.json + https://api.github.com/repos/$APP_REPO/commits/$APP_PKG_VERSION > tag.json echo "INFO collection | Got tag.json with size $(wc -c tag.json)" # Extract info @@ -60,7 +59,7 @@ if [ "$TAG_SHA" != "$FULL_SHA" ]; then echo "INFO frontend | Tag sha '$TAG_SHA' is not the same as commit sha $FULL_SHA, can not download frontend" else echo "INFO frontend | Getting frontend from github via tag" - curl https://github.com/$REPO/releases/download/$APP_PKG_VERSION/frontend-build.zip -L -O -f + curl https://github.com/$APP_REPO/releases/download/$APP_PKG_VERSION/frontend-build.zip -L -O -f mkdir -p src/backend/InvenTree/web/static echo "INFO frontend | Unzipping frontend" unzip -qq frontend-build.zip -d src/backend/InvenTree/web/static/web diff --git a/contrib/packager.io/functions.sh b/contrib/packager.io/functions.sh index 9087e1e0aa..29c9d53ff4 100755 --- a/contrib/packager.io/functions.sh +++ b/contrib/packager.io/functions.sh @@ -60,7 +60,7 @@ function detect_python() { fi # Try to detect a python between 3.9 and 3.12 in reverse order - if [ -z "${SETUP_PYTHON}" ]; then + if [ -z "$(which ${SETUP_PYTHON})" ]; then echo "# Trying to detecting python3.${PYTHON_FROM} to python3.${PYTHON_TO} - using newest version" for i in $(seq $PYTHON_TO -1 $PYTHON_FROM); do echo "# Checking for python3.${i}" @@ -318,17 +318,17 @@ function set_env() { sed -i s=debug:\ True=debug:\ False=g ${INVENTREE_CONFIG_FILE} # Database engine - sed -i s=#ENGINE:\ sampleengine=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ ENGINE:\ Database\ engine.\ Selection\ from:=ENGINE:\ ${INVENTREE_DB_ENGINE}=g ${INVENTREE_CONFIG_FILE} # Database name - sed -i s=#NAME:\ \'/path/to/database\'=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ NAME:\ Database\ name=NAME:\ \'${INVENTREE_DB_NAME}\'=g ${INVENTREE_CONFIG_FILE} # Database user - sed -i s=#USER:\ sampleuser=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ USER:\ Database\ username\ \(if\ required\)=USER:\ ${INVENTREE_DB_USER}=g ${INVENTREE_CONFIG_FILE} # Database password - sed -i s=#PASSWORD:\ samplepassword=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ PASSWORD:\ Database\ password\ \(if\ required\)=PASSWORD:\ ${INVENTREE_DB_PASSWORD}=g ${INVENTREE_CONFIG_FILE} # Database host - sed -i s=#HOST:\ samplehost=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ HOST:\ Database\ host\ address\ \(if\ required\)=HOST:\ ${INVENTREE_DB_HOST}=g ${INVENTREE_CONFIG_FILE} # Database port - sed -i s=#PORT:\ 123456=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE} + sed -i s=#\ PORT:\ Database\ host\ port\ \(if\ required\)=PORT:\ ${INVENTREE_DB_PORT}=g ${INVENTREE_CONFIG_FILE} # Fixing the permissions chown ${APP_USER}:${APP_GROUP} ${DATA_DIR} ${INVENTREE_CONFIG_FILE} diff --git a/contrib/packager.io/preinstall.sh b/contrib/packager.io/preinstall.sh index ba9ebc0d5d..0e59daebb2 100755 --- a/contrib/packager.io/preinstall.sh +++ b/contrib/packager.io/preinstall.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# packager.io preinstall script +# packager.io preinstall/preremove script # PATH=${APP_HOME}/env/bin:${APP_HOME}/:/sbin:/bin:/usr/sbin:/usr/bin: diff --git a/src/backend/InvenTree/config_template.yaml b/src/backend/InvenTree/config_template.yaml index a5b8495187..4ef1bf42bf 100644 --- a/src/backend/InvenTree/config_template.yaml +++ b/src/backend/InvenTree/config_template.yaml @@ -11,6 +11,8 @@ # Note: Database configuration options can also be specified from environmental variables, # with the prefix INVENTREE_DB_ # e.g INVENTREE_DB_NAME / INVENTREE_DB_USER / INVENTREE_DB_PASSWORD +# Do not change this section if you are using the package - use `inventree config` instead +# TO MAINTAINERS: Do not change database strings database: # --- Available options: --- # ENGINE: Database engine. Selection from: From 0a2817dbf3d582846896f7a30786cb4580ea097a Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Fri, 19 Jul 2024 00:50:53 +0200 Subject: [PATCH 3/4] Small typescript cleanups (#7685) * cleanup typescript:S1128 * fix typescript:S1854 * clean up typescript:S6749 * fix names for typescript:S6754 --- .../src/components/DashboardItemProxy.tsx | 4 +- .../src/components/buttons/AdminButton.tsx | 3 - .../components/buttons/PrintingActions.tsx | 2 +- .../src/components/details/DetailsImage.tsx | 65 ++++++++++--------- .../components/errors/GenericErrorPage.tsx | 1 - .../components/forms/fields/ApiFormField.tsx | 10 +-- .../components/forms/fields/TableField.tsx | 2 +- .../importer/ImporterImportProgress.tsx | 24 ++++--- .../items/GettingStartedCarousel.tsx | 2 +- .../src/components/modals/QrCodeModal.tsx | 16 ++--- .../src/components/nav/NotificationDrawer.tsx | 1 - .../src/components/render/Instance.tsx | 2 +- src/frontend/src/components/render/Part.tsx | 2 +- src/frontend/src/forms/BuildForms.tsx | 2 +- src/frontend/src/forms/PurchaseOrderForms.tsx | 5 +- src/frontend/src/forms/StockForms.tsx | 3 - src/frontend/src/hooks/UseImportSession.tsx | 2 - src/frontend/src/hooks/UseInstance.tsx | 2 +- src/frontend/src/pages/Auth/Logged-In.tsx | 30 ++++----- src/frontend/src/pages/Auth/Logout.tsx | 30 ++++----- src/frontend/src/pages/Index/Playground.tsx | 32 ++++----- src/frontend/src/pages/Index/Scan.tsx | 22 +++---- .../AccountSettings/SecurityContent.tsx | 4 +- .../src/pages/Index/Settings/UserSettings.tsx | 24 ++++--- src/frontend/src/pages/Notifications.tsx | 10 ++- src/frontend/src/pages/build/BuildIndex.tsx | 10 ++- .../src/pages/company/CompanyDetail.tsx | 1 - .../src/pages/part/PartPricingPanel.tsx | 6 +- .../pages/part/pricing/BomPricingPanel.tsx | 6 +- .../src/pages/purchasing/PurchasingIndex.tsx | 10 ++- src/frontend/src/pages/sales/SalesIndex.tsx | 10 ++- src/frontend/src/tables/DownloadAction.tsx | 13 ++-- src/frontend/src/tables/UploadAction.tsx | 6 +- .../src/tables/general/AttachmentTable.tsx | 4 +- .../src/tables/part/PartThumbTable.tsx | 54 ++++++++------- .../purchasing/PurchaseOrderLineItemTable.tsx | 1 - .../tables/settings/ImportSessionTable.tsx | 1 - .../src/tables/stock/InstalledItemsTable.tsx | 28 ++++---- src/frontend/tests/login.ts | 2 +- src/frontend/tests/pui_basic.spec.ts | 2 +- src/frontend/tests/pui_general.spec.ts | 2 +- src/frontend/tests/pui_settings.spec.ts | 2 +- 42 files changed, 198 insertions(+), 260 deletions(-) diff --git a/src/frontend/src/components/DashboardItemProxy.tsx b/src/frontend/src/components/DashboardItemProxy.tsx index cc0efa3bd0..d0ed0015c8 100644 --- a/src/frontend/src/components/DashboardItemProxy.tsx +++ b/src/frontend/src/components/DashboardItemProxy.tsx @@ -31,7 +31,7 @@ export function DashboardItemProxy({ queryFn: fetchData, refetchOnWindowFocus: autoupdate }); - const [dashdata, setDashData] = useState({ title: t`Title`, value: '000' }); + const [dashData, setDashData] = useState({ title: t`Title`, value: '000' }); useEffect(() => { if (data) { @@ -44,7 +44,7 @@ export function DashboardItemProxy({
diff --git a/src/frontend/src/components/buttons/AdminButton.tsx b/src/frontend/src/components/buttons/AdminButton.tsx index a9a81011d4..7adfe73f72 100644 --- a/src/frontend/src/components/buttons/AdminButton.tsx +++ b/src/frontend/src/components/buttons/AdminButton.tsx @@ -1,11 +1,8 @@ import { t } from '@lingui/macro'; import { IconUserStar } from '@tabler/icons-react'; import { useCallback, useMemo } from 'react'; -import { useNavigate } from 'react-router-dom'; import { ModelType } from '../../enums/ModelType'; -import { navigateToLink } from '../../functions/navigation'; -import { base_url } from '../../main'; import { useLocalState } from '../../states/LocalState'; import { useUserState } from '../../states/UserState'; import { ModelInformationDict } from '../render/ModelType'; diff --git a/src/frontend/src/components/buttons/PrintingActions.tsx b/src/frontend/src/components/buttons/PrintingActions.tsx index f355f4f00c..fbeb5deab1 100644 --- a/src/frontend/src/components/buttons/PrintingActions.tsx +++ b/src/frontend/src/components/buttons/PrintingActions.tsx @@ -2,7 +2,7 @@ import { t } from '@lingui/macro'; import { notifications } from '@mantine/notifications'; import { IconPrinter, IconReport, IconTags } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; import { api } from '../../App'; import { ApiEndpoints } from '../../enums/ApiEndpoints'; diff --git a/src/frontend/src/components/details/DetailsImage.tsx b/src/frontend/src/components/details/DetailsImage.tsx index fcc5a03ce5..f380997b9e 100644 --- a/src/frontend/src/components/details/DetailsImage.tsx +++ b/src/frontend/src/components/details/DetailsImage.tsx @@ -85,7 +85,7 @@ function UploadModal({ apiPath: string; setImage: (image: string) => void; }) { - const [file1, setFile] = useState(null); + const [currentFile, setCurrentFile] = useState(null); let uploading = false; // Components to show in the Dropzone when no file is selected @@ -168,7 +168,7 @@ function UploadModal({ return ( setFile(files[0])} + onDrop={(files) => setCurrentFile(files[0])} maxFiles={1} accept={IMAGE_MIME_TYPE} loading={uploading} @@ -198,7 +198,9 @@ function UploadModal({ }} /> - {file1 ? fileInfo(file1) : noFileIdle} + + {currentFile ? fileInfo(currentFile) : noFileIdle} + - @@ -354,31 +359,27 @@ export function DetailsImage(props: Readonly) { }; return ( - <> - - <> - - {permissions.hasChangeRole(props.appRole) && - hasOverlay && - hovered && ( - - - - )} - - - + + <> + + {permissions.hasChangeRole(props.appRole) && hasOverlay && hovered && ( + + + + )} + + ); } diff --git a/src/frontend/src/components/errors/GenericErrorPage.tsx b/src/frontend/src/components/errors/GenericErrorPage.tsx index 94405ba281..0e712e0bb0 100644 --- a/src/frontend/src/components/errors/GenericErrorPage.tsx +++ b/src/frontend/src/components/errors/GenericErrorPage.tsx @@ -1,7 +1,6 @@ import { Trans } from '@lingui/macro'; import { ActionIcon, - Alert, Button, Card, Center, diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index 7a41f1fa74..39890bacd5 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -1,15 +1,7 @@ import { t } from '@lingui/macro'; -import { - Alert, - FileInput, - NumberInput, - Stack, - Switch, - TextInput -} from '@mantine/core'; +import { Alert, FileInput, NumberInput, Stack, Switch } from '@mantine/core'; import { UseFormReturnType } from '@mantine/form'; import { useId } from '@mantine/hooks'; -import { IconX } from '@tabler/icons-react'; import { ReactNode, useCallback, useEffect, useMemo } from 'react'; import { Control, FieldValues, useController } from 'react-hook-form'; diff --git a/src/frontend/src/components/forms/fields/TableField.tsx b/src/frontend/src/components/forms/fields/TableField.tsx index e66af3ab60..c4eadc915b 100644 --- a/src/frontend/src/components/forms/fields/TableField.tsx +++ b/src/frontend/src/components/forms/fields/TableField.tsx @@ -1,5 +1,5 @@ import { Trans, t } from '@lingui/macro'; -import { Container, Flex, Group, Table } from '@mantine/core'; +import { Container, Group, Table } from '@mantine/core'; import { useEffect, useMemo } from 'react'; import { FieldValues, UseControllerReturn } from 'react-hook-form'; diff --git a/src/frontend/src/components/importer/ImporterImportProgress.tsx b/src/frontend/src/components/importer/ImporterImportProgress.tsx index e44bcee76e..dd98307fe1 100644 --- a/src/frontend/src/components/importer/ImporterImportProgress.tsx +++ b/src/frontend/src/components/importer/ImporterImportProgress.tsx @@ -29,18 +29,16 @@ export default function ImporterImportProgress({ }, []); return ( - <> -
- - - {t`Importing Records`} - - - {t`Imported rows`}: {session.sessionData.row_count} - - - -
- +
+ + + {t`Importing Records`} + + + {t`Imported rows`}: {session.sessionData.row_count} + + + +
); } diff --git a/src/frontend/src/components/items/GettingStartedCarousel.tsx b/src/frontend/src/components/items/GettingStartedCarousel.tsx index e317c3a817..b34e6093b4 100644 --- a/src/frontend/src/components/items/GettingStartedCarousel.tsx +++ b/src/frontend/src/components/items/GettingStartedCarousel.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/macro'; import { Carousel } from '@mantine/carousel'; -import { Anchor, Button, Paper, Text, Title, rem } from '@mantine/core'; +import { Anchor, Button, Paper, Text, Title } from '@mantine/core'; import { DocumentationLinkItem } from './DocumentationLinks'; import * as classes from './GettingStartedCarousel.css'; diff --git a/src/frontend/src/components/modals/QrCodeModal.tsx b/src/frontend/src/components/modals/QrCodeModal.tsx index b7907c8c82..5d656b5778 100644 --- a/src/frontend/src/components/modals/QrCodeModal.tsx +++ b/src/frontend/src/components/modals/QrCodeModal.tsx @@ -35,7 +35,7 @@ export function QrCodeModal({ key: 'camId', defaultValue: null }); - const [ScanningEnabled, setIsScanning] = useState(false); + const [scanningEnabled, setScanningEnabled] = useState(false); const [wasAutoPaused, setWasAutoPaused] = useState(false); const documentState = useDocumentVisibility(); @@ -48,7 +48,7 @@ export function QrCodeModal({ // Stop/star when leaving or reentering page useEffect(() => { - if (ScanningEnabled && documentState === 'hidden') { + if (scanningEnabled && documentState === 'hidden') { stopScanning(); setWasAutoPaused(true); } else if (wasAutoPaused && documentState === 'visible') { @@ -128,12 +128,12 @@ export function QrCodeModal({ icon: }); }); - setIsScanning(true); + setScanningEnabled(true); } } function stopScanning() { - if (qrCodeScanner && ScanningEnabled) { + if (qrCodeScanner && scanningEnabled) { qrCodeScanner.stop().catch((err: string) => { showNotification({ title: t`Error while stopping`, @@ -142,7 +142,7 @@ export function QrCodeModal({ icon: }); }); - setIsScanning(false); + setScanningEnabled(false); } } @@ -151,7 +151,7 @@ export function QrCodeModal({ {camId?.label} - {ScanningEnabled ? t`Scanning` : t`Not scanning`} + {scanningEnabled ? t`Scanning` : t`Not scanning`} {!camId ? ( @@ -164,14 +164,14 @@ export function QrCodeModal({ diff --git a/src/frontend/src/components/nav/NotificationDrawer.tsx b/src/frontend/src/components/nav/NotificationDrawer.tsx index 28464b4895..bc68fc0fa3 100644 --- a/src/frontend/src/components/nav/NotificationDrawer.tsx +++ b/src/frontend/src/components/nav/NotificationDrawer.tsx @@ -7,7 +7,6 @@ import { Drawer, Group, Loader, - LoadingOverlay, Space, Stack, Text, diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx index aa14af36d2..ab9cdd80e8 100644 --- a/src/frontend/src/components/render/Instance.tsx +++ b/src/frontend/src/components/render/Instance.tsx @@ -1,6 +1,6 @@ import { t } from '@lingui/macro'; import { Alert, Anchor, Group, Skeleton, Space, Text } from '@mantine/core'; -import { useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { ReactNode, useCallback } from 'react'; import { api } from '../../App'; diff --git a/src/frontend/src/components/render/Part.tsx b/src/frontend/src/components/render/Part.tsx index f303b89acb..877f2f385a 100644 --- a/src/frontend/src/components/render/Part.tsx +++ b/src/frontend/src/components/render/Part.tsx @@ -15,7 +15,7 @@ export function RenderPart( const { instance } = props; let badgeText = ''; - let badgeColor = 'green'; + let badgeColor = ''; let stock = instance.total_in_stock; diff --git a/src/frontend/src/forms/BuildForms.tsx b/src/frontend/src/forms/BuildForms.tsx index f819f3cc19..16d8e948f1 100644 --- a/src/frontend/src/forms/BuildForms.tsx +++ b/src/frontend/src/forms/BuildForms.tsx @@ -1,5 +1,5 @@ import { t } from '@lingui/macro'; -import { ActionIcon, Alert, Stack, Text } from '@mantine/core'; +import { Alert, Stack, Text } from '@mantine/core'; import { IconCalendar, IconLink, diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx index 8876fca1db..102818ddf6 100644 --- a/src/frontend/src/forms/PurchaseOrderForms.tsx +++ b/src/frontend/src/forms/PurchaseOrderForms.tsx @@ -33,10 +33,7 @@ import { ApiFormAdjustFilterType, ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; -import { - TableField, - TableFieldExtraRow -} from '../components/forms/fields/TableField'; +import { TableFieldExtraRow } from '../components/forms/fields/TableField'; import { Thumbnail } from '../components/images/Thumbnail'; import { ProgressBar } from '../components/items/ProgressBar'; import { StylishText } from '../components/items/StylishText'; diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx index 8d7df62f5a..4a937b98a6 100644 --- a/src/frontend/src/forms/StockForms.tsx +++ b/src/frontend/src/forms/StockForms.tsx @@ -7,13 +7,10 @@ import { Suspense, useCallback, useMemo, useState } from 'react'; import { api } from '../App'; import { ActionButton } from '../components/buttons/ActionButton'; -import { StandaloneField } from '../components/forms/StandaloneField'; import { ApiFormAdjustFilterType, - ApiFormField, ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; -import { ChoiceField } from '../components/forms/fields/ChoiceField'; import { TableFieldExtraRow } from '../components/forms/fields/TableField'; import { Thumbnail } from '../components/images/Thumbnail'; import { StylishText } from '../components/items/StylishText'; diff --git a/src/frontend/src/hooks/UseImportSession.tsx b/src/frontend/src/hooks/UseImportSession.tsx index 361206f5a7..bb5391eaeb 100644 --- a/src/frontend/src/hooks/UseImportSession.tsx +++ b/src/frontend/src/hooks/UseImportSession.tsx @@ -1,8 +1,6 @@ import { useCallback, useMemo } from 'react'; -import { api } from '../App'; import { ApiEndpoints } from '../enums/ApiEndpoints'; -import { apiUrl } from '../states/ApiState'; import { useInstance } from './UseInstance'; /* diff --git a/src/frontend/src/hooks/UseInstance.tsx b/src/frontend/src/hooks/UseInstance.tsx index d4cd94c18e..29713bd8e4 100644 --- a/src/frontend/src/hooks/UseInstance.tsx +++ b/src/frontend/src/hooks/UseInstance.tsx @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useState } from 'react'; import { api } from '../App'; import { ApiEndpoints } from '../enums/ApiEndpoints'; diff --git a/src/frontend/src/pages/Auth/Logged-In.tsx b/src/frontend/src/pages/Auth/Logged-In.tsx index ad3fdd1291..c4939dd30d 100644 --- a/src/frontend/src/pages/Auth/Logged-In.tsx +++ b/src/frontend/src/pages/Auth/Logged-In.tsx @@ -14,21 +14,19 @@ export default function Logged_In() { }, [navigate]); return ( - <> - - - - - - Checking if you are already logged in - - - - - - - - - + + + + + + Checking if you are already logged in + + + + + + + + ); } diff --git a/src/frontend/src/pages/Auth/Logout.tsx b/src/frontend/src/pages/Auth/Logout.tsx index 0270d1a797..c8c0944016 100644 --- a/src/frontend/src/pages/Auth/Logout.tsx +++ b/src/frontend/src/pages/Auth/Logout.tsx @@ -14,21 +14,19 @@ export default function Logout() { }, []); return ( - <> - - - - - - Logging out - - - - - - - - - + + + + + + Logging out + + + + + + + + ); } diff --git a/src/frontend/src/pages/Index/Playground.tsx b/src/frontend/src/pages/Index/Playground.tsx index ad8cb38e91..c7b9deb43d 100644 --- a/src/frontend/src/pages/Index/Playground.tsx +++ b/src/frontend/src/pages/Index/Playground.tsx @@ -146,16 +146,14 @@ function ApiFormsPlayground() { function StatusLabelPlayground() { const [status, setStatus] = useState('10'); return ( - <> - - Stock Status - setStatus(event.currentTarget.value)} - /> - - - + + Stock Status + setStatus(event.currentTarget.value)} + /> + + ); } @@ -202,14 +200,12 @@ function PlaygroundArea({ content: ReactNode; }) { return ( - <> - - - {title} - - {content} - - + + + {title} + + {content} + ); } diff --git a/src/frontend/src/pages/Index/Scan.tsx b/src/frontend/src/pages/Index/Scan.tsx index f05de24f6c..3b5cf56c4f 100644 --- a/src/frontend/src/pages/Index/Scan.tsx +++ b/src/frontend/src/pages/Index/Scan.tsx @@ -41,7 +41,7 @@ import { } from '@tabler/icons-react'; import { Html5Qrcode } from 'html5-qrcode'; import { CameraDevice } from 'html5-qrcode/camera/core'; -import { ReactNode, useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { api } from '../../App'; import { DocInfo } from '../../components/items/DocInfo'; @@ -553,7 +553,7 @@ function InputImageBarcode({ action }: Readonly) { }); const [cameras, setCameras] = useState([]); const [cameraValue, setCameraValue] = useState(null); - const [ScanningEnabled, setIsScanning] = useState(false); + const [scanningEnabled, setScanningEnabled] = useState(false); const [wasAutoPaused, setWasAutoPaused] = useState(false); const documentState = useDocumentVisibility(); @@ -580,7 +580,7 @@ function InputImageBarcode({ action }: Readonly) { // Stop/start when leaving or reentering page useEffect(() => { - if (ScanningEnabled && documentState === 'hidden') { + if (scanningEnabled && documentState === 'hidden') { btnStopScanning(); setWasAutoPaused(true); } else if (wasAutoPaused && documentState === 'visible') { @@ -642,7 +642,7 @@ function InputImageBarcode({ action }: Readonly) { } function btnStartScanning() { - if (camId && qrCodeScanner && !ScanningEnabled) { + if (camId && qrCodeScanner && !scanningEnabled) { qrCodeScanner .start( camId.id, @@ -662,12 +662,12 @@ function InputImageBarcode({ action }: Readonly) { icon: }); }); - setIsScanning(true); + setScanningEnabled(true); } } function btnStopScanning() { - if (qrCodeScanner && ScanningEnabled) { + if (qrCodeScanner && scanningEnabled) { qrCodeScanner.stop().catch((err: string) => { showNotification({ title: t`Error while stopping`, @@ -676,7 +676,7 @@ function InputImageBarcode({ action }: Readonly) { icon: }); }); - setIsScanning(false); + setScanningEnabled(false); } } @@ -690,7 +690,7 @@ function InputImageBarcode({ action }: Readonly) { const cam = cameras.find((cam) => cam.id === cameraValue); // stop scanning if cam changed while scanning - if (qrCodeScanner && ScanningEnabled) { + if (qrCodeScanner && scanningEnabled) { // stop scanning qrCodeScanner.stop().then(() => { // change ID @@ -723,7 +723,7 @@ function InputImageBarcode({ action }: Readonly) { })} size="sm" /> - {ScanningEnabled ? ( + {scanningEnabled ? ( ) { )} - - {ScanningEnabled ? t`Scanning` : t`Not scanning`} + + {scanningEnabled ? t`Scanning` : t`Not scanning`} diff --git a/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx b/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx index 16de9036a8..1af5aadc17 100644 --- a/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx +++ b/src/frontend/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx @@ -204,7 +204,7 @@ function EmailContent() { function SsoContent({ dataProvider }: { dataProvider: any | undefined }) { const [value, setValue] = useState(''); - const [currentProviders, setcurrentProviders] = useState<[]>(); + const [currentProviders, setCurrentProviders] = useState<[]>(); const { isLoading, data } = useQuery({ queryKey: ['sso-list'], queryFn: () => @@ -225,7 +225,7 @@ function SsoContent({ dataProvider }: { dataProvider: any | undefined }) { // remove providers that are used currently let newData = dataProvider.providers; newData = newData.filter(isAlreadyInUse); - setcurrentProviders(newData); + setCurrentProviders(newData); }, [dataProvider, data]); function removeProvider() { diff --git a/src/frontend/src/pages/Index/Settings/UserSettings.tsx b/src/frontend/src/pages/Index/Settings/UserSettings.tsx index 03c6b66e9f..614f84d493 100644 --- a/src/frontend/src/pages/Index/Settings/UserSettings.tsx +++ b/src/frontend/src/pages/Index/Settings/UserSettings.tsx @@ -120,18 +120,16 @@ export default function UserSettings() { } return ( - <> - - Switch to System Setting} - switch_condition={user?.is_staff || false} - /> - - - + + Switch to System Setting} + switch_condition={user?.is_staff || false} + /> + + ); } diff --git a/src/frontend/src/pages/Notifications.tsx b/src/frontend/src/pages/Notifications.tsx index 115865e391..b8962e20ee 100644 --- a/src/frontend/src/pages/Notifications.tsx +++ b/src/frontend/src/pages/Notifications.tsx @@ -147,11 +147,9 @@ export default function NotificationsPage() { }, [unreadTable, readTable]); return ( - <> - - - - - + + + + ); } diff --git a/src/frontend/src/pages/build/BuildIndex.tsx b/src/frontend/src/pages/build/BuildIndex.tsx index 557de69c87..a20c45a5b0 100644 --- a/src/frontend/src/pages/build/BuildIndex.tsx +++ b/src/frontend/src/pages/build/BuildIndex.tsx @@ -9,11 +9,9 @@ import { BuildOrderTable } from '../../tables/build/BuildOrderTable'; */ export default function BuildIndex() { return ( - <> - - - - - + + + + ); } diff --git a/src/frontend/src/pages/company/CompanyDetail.tsx b/src/frontend/src/pages/company/CompanyDetail.tsx index 3d542142bd..39070a0814 100644 --- a/src/frontend/src/pages/company/CompanyDetail.tsx +++ b/src/frontend/src/pages/company/CompanyDetail.tsx @@ -39,7 +39,6 @@ import { UserRoles } from '../../enums/Roles'; import { companyFields } from '../../forms/CompanyForms'; import { useEditApiFormModal } from '../../hooks/UseForm'; import { useInstance } from '../../hooks/UseInstance'; -import { apiUrl } from '../../states/ApiState'; import { useUserState } from '../../states/UserState'; import { AddressTable } from '../../tables/company/AddressTable'; import { ContactTable } from '../../tables/company/ContactTable'; diff --git a/src/frontend/src/pages/part/PartPricingPanel.tsx b/src/frontend/src/pages/part/PartPricingPanel.tsx index ce05c2c342..c0526d1551 100644 --- a/src/frontend/src/pages/part/PartPricingPanel.tsx +++ b/src/frontend/src/pages/part/PartPricingPanel.tsx @@ -31,11 +31,7 @@ export enum panelOptions { export default function PartPricingPanel({ part }: { part: any }) { const user = useUserState(); - const { - instance: pricing, - refreshInstance, - instanceQuery - } = useInstance({ + const { instance: pricing, instanceQuery } = useInstance({ pk: part?.pk, hasPrimaryKey: true, endpoint: ApiEndpoints.part_pricing_get, diff --git a/src/frontend/src/pages/part/pricing/BomPricingPanel.tsx b/src/frontend/src/pages/part/pricing/BomPricingPanel.tsx index 9ee05a7bf9..4584c394a6 100644 --- a/src/frontend/src/pages/part/pricing/BomPricingPanel.tsx +++ b/src/frontend/src/pages/part/pricing/BomPricingPanel.tsx @@ -12,11 +12,7 @@ import { ReactNode, useMemo, useState } from 'react'; import { CHART_COLORS } from '../../../components/charts/colors'; import { tooltipFormatter } from '../../../components/charts/tooltipFormatter'; -import { - formatCurrency, - formatDecimal, - formatPriceRange -} from '../../../defaults/formatters'; +import { formatDecimal, formatPriceRange } from '../../../defaults/formatters'; import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ModelType } from '../../../enums/ModelType'; import { useTable } from '../../../hooks/UseTable'; diff --git a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx index 2a47575ca5..408cf40a0a 100644 --- a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx +++ b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx @@ -47,11 +47,9 @@ export default function PurchasingIndex() { }, []); return ( - <> - - - - - + + + + ); } diff --git a/src/frontend/src/pages/sales/SalesIndex.tsx b/src/frontend/src/pages/sales/SalesIndex.tsx index db13d4b298..3de329ea7c 100644 --- a/src/frontend/src/pages/sales/SalesIndex.tsx +++ b/src/frontend/src/pages/sales/SalesIndex.tsx @@ -40,11 +40,9 @@ export default function PurchasingIndex() { }, []); return ( - <> - - - - - + + + + ); } diff --git a/src/frontend/src/tables/DownloadAction.tsx b/src/frontend/src/tables/DownloadAction.tsx index e2d5c1d9ed..ddcc83b206 100644 --- a/src/frontend/src/tables/DownloadAction.tsx +++ b/src/frontend/src/tables/DownloadAction.tsx @@ -1,5 +1,4 @@ import { t } from '@lingui/macro'; -import { ActionIcon, Menu, Tooltip } from '@mantine/core'; import { IconDownload, IconFileSpreadsheet, @@ -33,12 +32,10 @@ export function DownloadAction({ }, [formatOptions, downloadCallback]); return ( - <> - } - actions={actions} - /> - + } + actions={actions} + /> ); } diff --git a/src/frontend/src/tables/UploadAction.tsx b/src/frontend/src/tables/UploadAction.tsx index e958b26cd8..0230b975c7 100644 --- a/src/frontend/src/tables/UploadAction.tsx +++ b/src/frontend/src/tables/UploadAction.tsx @@ -4,9 +4,5 @@ import { IconUpload } from '@tabler/icons-react'; import { ActionButton } from '../components/buttons/ActionButton'; export function UploadAction({}) { - return ( - <> - } tooltip={t`Upload Data`} /> - - ); + return } tooltip={t`Upload Data`} />; } diff --git a/src/frontend/src/tables/general/AttachmentTable.tsx b/src/frontend/src/tables/general/AttachmentTable.tsx index d30ede40d0..9b20017e10 100644 --- a/src/frontend/src/tables/general/AttachmentTable.tsx +++ b/src/frontend/src/tables/general/AttachmentTable.tsx @@ -8,7 +8,7 @@ import { IconUpload, IconX } from '@tabler/icons-react'; -import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; +import { ReactNode, useCallback, useMemo, useState } from 'react'; import { api } from '../../App'; import { ActionButton } from '../../components/buttons/ActionButton'; @@ -28,7 +28,7 @@ import { useUserState } from '../../states/UserState'; import { TableColumn } from '../Column'; import { TableFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; -import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; +import { RowDeleteAction, RowEditAction } from '../RowActions'; /** * Define set of columns to display for the attachment table diff --git a/src/frontend/src/tables/part/PartThumbTable.tsx b/src/frontend/src/tables/part/PartThumbTable.tsx index 3862ab66a0..73ec8681e4 100644 --- a/src/frontend/src/tables/part/PartThumbTable.tsx +++ b/src/frontend/src/tables/part/PartThumbTable.tsx @@ -128,13 +128,13 @@ export function PartThumbTable({ pk, setImage }: ThumbTableProps) { - const [img, selectImage] = useState(null); + const [thumbImage, setThumbImage] = useState(null); const [filterInput, setFilterInput] = useState(''); - const [filterQuery, setFilter] = useState(search); + const [filterQuery, setFilterQuery] = useState(search); // Keep search filters from updating while user is typing useEffect(() => { - const timeoutId = setTimeout(() => setFilter(filterInput), 500); + const timeoutId = setTimeout(() => setFilterQuery(filterInput), 500); return () => clearTimeout(timeoutId); }, [filterInput]); @@ -160,30 +160,28 @@ export function PartThumbTable({ - <> - - {!thumbQuery.isFetching - ? thumbQuery.data?.data.map( - (data: ImageElement, index: number) => ( - - ) - ) - : [...Array(limit)].map((elem, idx) => ( - + {!thumbQuery.isFetching + ? thumbQuery.data?.data.map( + (data: ImageElement, index: number) => ( + - ))} - - + ) + ) + : [...Array(limit)].map((elem, idx) => ( + + ))} + @@ -197,8 +195,8 @@ export function PartThumbTable({ }} /> diff --git a/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx b/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx index 8083aafc90..5166469637 100644 --- a/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx +++ b/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx @@ -1,6 +1,5 @@ import { t } from '@lingui/macro'; import { Text } from '@mantine/core'; -import { Action } from '@mdxeditor/editor'; import { IconFileArrowLeft, IconSquareArrowRight } from '@tabler/icons-react'; import { useCallback, useMemo, useState } from 'react'; diff --git a/src/frontend/src/tables/settings/ImportSessionTable.tsx b/src/frontend/src/tables/settings/ImportSessionTable.tsx index 6c71f5251a..219f5246b2 100644 --- a/src/frontend/src/tables/settings/ImportSessionTable.tsx +++ b/src/frontend/src/tables/settings/ImportSessionTable.tsx @@ -25,7 +25,6 @@ import { RowAction, RowDeleteAction } from '../RowActions'; export default function ImportSesssionTable() { const table = useTable('importsession'); - const user = useUserState(); const [opened, setOpened] = useState(false); diff --git a/src/frontend/src/tables/stock/InstalledItemsTable.tsx b/src/frontend/src/tables/stock/InstalledItemsTable.tsx index 027b49fe75..a2e97723d7 100644 --- a/src/frontend/src/tables/stock/InstalledItemsTable.tsx +++ b/src/frontend/src/tables/stock/InstalledItemsTable.tsx @@ -50,20 +50,18 @@ export default function InstalledItemsTable({ }, [user]); return ( - <> - - + ); } diff --git a/src/frontend/tests/login.ts b/src/frontend/tests/login.ts index d4cef1d681..5529e24d8c 100644 --- a/src/frontend/tests/login.ts +++ b/src/frontend/tests/login.ts @@ -1,5 +1,5 @@ import { expect } from './baseFixtures.js'; -import { baseUrl, loginUrl, logoutUrl, user } from './defaults'; +import { baseUrl, logoutUrl, user } from './defaults'; /* * Perform form based login operation from the "login" URL diff --git a/src/frontend/tests/pui_basic.spec.ts b/src/frontend/tests/pui_basic.spec.ts index fa23b82279..38534fbb92 100644 --- a/src/frontend/tests/pui_basic.spec.ts +++ b/src/frontend/tests/pui_basic.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from './baseFixtures.js'; -import { baseUrl, loginUrl, user } from './defaults.js'; +import { baseUrl, user } from './defaults.js'; import { doLogin, doQuickLogin } from './login.js'; test('PUI - Basic Login Test', async ({ page }) => { diff --git a/src/frontend/tests/pui_general.spec.ts b/src/frontend/tests/pui_general.spec.ts index a62547aca3..5c891b339a 100644 --- a/src/frontend/tests/pui_general.spec.ts +++ b/src/frontend/tests/pui_general.spec.ts @@ -1,6 +1,6 @@ import { test } from './baseFixtures.js'; import { baseUrl } from './defaults.js'; -import { doLogout, doQuickLogin } from './login.js'; +import { doQuickLogin } from './login.js'; test('PUI - Parts', async ({ page }) => { await doQuickLogin(page); diff --git a/src/frontend/tests/pui_settings.spec.ts b/src/frontend/tests/pui_settings.spec.ts index 0b6399f312..ba5deef57d 100644 --- a/src/frontend/tests/pui_settings.spec.ts +++ b/src/frontend/tests/pui_settings.spec.ts @@ -1,6 +1,6 @@ import { test } from './baseFixtures.js'; import { baseUrl } from './defaults.js'; -import { doLogout, doQuickLogin } from './login.js'; +import { doQuickLogin } from './login.js'; test('PUI - Admin', async ({ page }) => { // Note here we login with admin access From d4cd7d4a7233b4a794cec79ac94598beaacc10bd Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 19 Jul 2024 16:54:55 +1000 Subject: [PATCH 4/4] [PUI] Tab permissions (#7692) * [PUI] Hide main nav tabs based on user roles * Add permission checks on top-level pages * Specify return type --- src/frontend/src/components/nav/Header.tsx | 41 ++++++++++++------- src/frontend/src/defaults/links.tsx | 16 +++++--- src/frontend/src/pages/build/BuildIndex.tsx | 9 ++++ .../src/pages/purchasing/PurchasingIndex.tsx | 9 ++++ src/frontend/src/pages/sales/SalesIndex.tsx | 9 ++++ 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/frontend/src/components/nav/Header.tsx b/src/frontend/src/components/nav/Header.tsx index 49426d599b..7ba9ef6f8b 100644 --- a/src/frontend/src/components/nav/Header.tsx +++ b/src/frontend/src/components/nav/Header.tsx @@ -2,7 +2,7 @@ import { ActionIcon, Container, Group, Indicator, Tabs } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { IconBell, IconSearch } from '@tabler/icons-react'; 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 { api } from '../../App'; @@ -132,10 +132,35 @@ export function Header() { } function NavTabs() { + const user = useUserState(); const navigate = useNavigate(); const match = useMatch(':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( + + navigateToLink(`/${tab.name}`, navigate, event) + } + > + {tab.text} + + ); + }); + + return _tabs; + }, [mainNavTabs, user]); + return ( - - {mainNavTabs.map((tab) => ( - - navigateToLink(`/${tab.name}`, navigate, event) - } - > - {tab.text} - - ))} - + {tabs.map((tab) => tab)} ); } diff --git a/src/frontend/src/defaults/links.tsx b/src/frontend/src/defaults/links.tsx index bc836c52ec..1646bab73e 100644 --- a/src/frontend/src/defaults/links.tsx +++ b/src/frontend/src/defaults/links.tsx @@ -3,6 +3,7 @@ import { openContextModal } from '@mantine/modals'; import { DocumentationLinkItem } from '../components/items/DocumentationLinks'; import { StylishText } from '../components/items/StylishText'; +import { UserRoles } from '../enums/Roles'; import { IS_DEV_OR_DEMO } from '../main'; export const footerLinks = [ @@ -25,12 +26,17 @@ export const footerLinks = [ export const navTabs = [ { text: Home, name: 'home' }, { text: Dashboard, name: 'dashboard' }, - { text: Parts, name: 'part' }, - { text: Stock, name: 'stock' }, - { text: Build, name: 'build' }, - { text: Purchasing, name: 'purchasing' }, - { text: Sales, name: 'sales' } + { text: Parts, name: 'part', role: UserRoles.part }, + { text: Stock, name: 'stock', role: UserRoles.stock }, + { text: Build, name: 'build', role: UserRoles.build }, + { + text: Purchasing, + name: 'purchasing', + role: UserRoles.purchase_order + }, + { text: Sales, name: 'sales', role: UserRoles.sales_order } ]; + if (IS_DEV_OR_DEMO) { navTabs.push({ text: Playground, name: 'playground' }); } diff --git a/src/frontend/src/pages/build/BuildIndex.tsx b/src/frontend/src/pages/build/BuildIndex.tsx index a20c45a5b0..aae18ff115 100644 --- a/src/frontend/src/pages/build/BuildIndex.tsx +++ b/src/frontend/src/pages/build/BuildIndex.tsx @@ -1,13 +1,22 @@ import { t } from '@lingui/macro'; import { Stack } from '@mantine/core'; +import PermissionDenied from '../../components/errors/PermissionDenied'; import { PageDetail } from '../../components/nav/PageDetail'; +import { UserRoles } from '../../enums/Roles'; +import { useUserState } from '../../states/UserState'; import { BuildOrderTable } from '../../tables/build/BuildOrderTable'; /** * Build Order index page */ export default function BuildIndex() { + const user = useUserState(); + + if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.build)) { + return ; + } + return ( diff --git a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx index 408cf40a0a..13c91771b7 100644 --- a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx +++ b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx @@ -7,12 +7,17 @@ import { } from '@tabler/icons-react'; import { useMemo } from 'react'; +import PermissionDenied from '../../components/errors/PermissionDenied'; import { PageDetail } from '../../components/nav/PageDetail'; import { PanelGroup } from '../../components/nav/PanelGroup'; +import { UserRoles } from '../../enums/Roles'; +import { useUserState } from '../../states/UserState'; import { CompanyTable } from '../../tables/company/CompanyTable'; import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable'; export default function PurchasingIndex() { + const user = useUserState(); + const panels = useMemo(() => { return [ { @@ -46,6 +51,10 @@ export default function PurchasingIndex() { ]; }, []); + if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.purchase_order)) { + return ; + } + return ( diff --git a/src/frontend/src/pages/sales/SalesIndex.tsx b/src/frontend/src/pages/sales/SalesIndex.tsx index 3de329ea7c..16a94174e5 100644 --- a/src/frontend/src/pages/sales/SalesIndex.tsx +++ b/src/frontend/src/pages/sales/SalesIndex.tsx @@ -7,13 +7,18 @@ import { } from '@tabler/icons-react'; import { useMemo } from 'react'; +import PermissionDenied from '../../components/errors/PermissionDenied'; import { PageDetail } from '../../components/nav/PageDetail'; import { PanelGroup } from '../../components/nav/PanelGroup'; +import { UserRoles } from '../../enums/Roles'; +import { useUserState } from '../../states/UserState'; import { CompanyTable } from '../../tables/company/CompanyTable'; import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable'; import { SalesOrderTable } from '../../tables/sales/SalesOrderTable'; export default function PurchasingIndex() { + const user = useUserState(); + const panels = useMemo(() => { return [ { @@ -39,6 +44,10 @@ export default function PurchasingIndex() { ]; }, []); + if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.sales_order)) { + return ; + } + return (