From f3223c6d7f068f88d1f1d95abd6636d3503b2c0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 May 2024 14:24:21 +1000 Subject: [PATCH] [PUI] Mantine tree (#7357) * Refactor part category tree - New "NavigationTree" using native mantine components - Make it generic, too * Replace existing component * Adjust API filtering for location tree endpoint * Added playwright tests * Update api filter classes * Fix for DetailsImage - Update to @mantine/core had changed the component * fix for identifierString function * Adjust playwright tests --- src/backend/InvenTree/InvenTree/filters.py | 2 + src/backend/InvenTree/part/api.py | 5 +- src/backend/InvenTree/stock/api.py | 6 +- src/frontend/package.json | 5 +- .../src/components/details/DetailsImage.tsx | 2 +- .../src/components/nav/BreadcrumbList.tsx | 7 +- .../src/components/nav/NavigationTree.tsx | 205 ++++++++++++++++++ .../src/components/nav/PanelGroup.tsx | 4 + .../src/components/nav/PartCategoryTree.tsx | 176 --------------- .../src/components/nav/StockLocationTree.tsx | 109 ---------- src/frontend/src/functions/conversion.tsx | 3 + .../src/pages/part/CategoryDetail.tsx | 9 +- src/frontend/src/pages/part/PartDetail.tsx | 10 +- .../src/pages/stock/LocationDetail.tsx | 9 +- src/frontend/src/pages/stock/StockDetail.tsx | 9 +- src/frontend/tests/pui_general.spec.ts | 2 +- src/frontend/tests/pui_stock.spec.ts | 17 ++ src/frontend/yarn.lock | 170 ++++++++------- 18 files changed, 361 insertions(+), 389 deletions(-) create mode 100644 src/frontend/src/components/nav/NavigationTree.tsx delete mode 100644 src/frontend/src/components/nav/PartCategoryTree.tsx delete mode 100644 src/frontend/src/components/nav/StockLocationTree.tsx diff --git a/src/backend/InvenTree/InvenTree/filters.py b/src/backend/InvenTree/InvenTree/filters.py index 52af9ba436a1..f3182d0931dc 100644 --- a/src/backend/InvenTree/InvenTree/filters.py +++ b/src/backend/InvenTree/InvenTree/filters.py @@ -166,3 +166,5 @@ def get_ordering(self, request, queryset, view): ] ORDER_FILTER = [rest_filters.DjangoFilterBackend, filters.OrderingFilter] + +ORDER_FILTER_ALIAS = [rest_filters.DjangoFilterBackend, InvenTreeOrderingFilter] diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 319122187935..0c3ba35818ec 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -26,6 +26,7 @@ ) from InvenTree.filters import ( ORDER_FILTER, + ORDER_FILTER_ALIAS, SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS, InvenTreeDateFilter, @@ -303,10 +304,12 @@ class CategoryTree(ListAPI): queryset = PartCategory.objects.all() serializer_class = part_serializers.CategoryTree - filter_backends = ORDER_FILTER + filter_backends = ORDER_FILTER_ALIAS ordering_fields = ['level', 'name', 'subcategories'] + ordering_field_aliases = {'level': ['level', 'name'], 'name': ['name', 'level']} + # Order by tree level (top levels first) and then name ordering = ['level', 'name'] diff --git a/src/backend/InvenTree/stock/api.py b/src/backend/InvenTree/stock/api.py index 0fdae2d475a4..60402584ba06 100644 --- a/src/backend/InvenTree/stock/api.py +++ b/src/backend/InvenTree/stock/api.py @@ -35,7 +35,7 @@ MetadataView, ) from InvenTree.filters import ( - ORDER_FILTER, + ORDER_FILTER_ALIAS, SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS, InvenTreeDateFilter, @@ -429,13 +429,15 @@ class StockLocationTree(ListAPI): queryset = StockLocation.objects.all() serializer_class = StockSerializers.LocationTreeSerializer - filter_backends = ORDER_FILTER + filter_backends = ORDER_FILTER_ALIAS ordering_fields = ['level', 'name', 'sublocations'] # Order by tree level (top levels first) and then name ordering = ['level', 'name'] + ordering_field_aliases = {'level': ['level', 'name'], 'name': ['name', 'level']} + def get_queryset(self, *args, **kwargs): """Return annotated queryset for the StockLocationTree endpoint.""" queryset = super().get_queryset(*args, **kwargs) diff --git a/src/frontend/package.json b/src/frontend/package.json index ccea297ca013..631c15b50d60 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -27,7 +27,7 @@ "@lingui/core": "^4.10.0", "@lingui/react": "^4.10.0", "@mantine/carousel": "^7.8.0", - "@mantine/core": "^7.8.0", + "@mantine/core": "^7.10.0", "@mantine/dates": "^7.8.0", "@mantine/dropzone": "^7.8.0", "@mantine/form": "^7.8.0", @@ -36,7 +36,6 @@ "@mantine/notifications": "^7.8.0", "@mantine/spotlight": "^7.8.0", "@mantine/vanilla-extract": "^7.8.0", - "@naisutech/react-tree": "^3.1.0", "@sentry/react": "^7.110.0", "@tabler/icons-react": "^3.2.0", "@tanstack/react-query": "^5.29.2", @@ -60,7 +59,7 @@ "react-router-dom": "^6.22.3", "react-select": "^5.8.0", "react-simplemde-editor": "^5.2.0", - "recharts": "^2.12.4", + "recharts": "2", "styled-components": "^6.1.8", "zustand": "^4.5.2" }, diff --git a/src/frontend/src/components/details/DetailsImage.tsx b/src/frontend/src/components/details/DetailsImage.tsx index 12d469ca65fa..fcc5a03ce580 100644 --- a/src/frontend/src/components/details/DetailsImage.tsx +++ b/src/frontend/src/components/details/DetailsImage.tsx @@ -355,7 +355,7 @@ export function DetailsImage(props: Readonly) { return ( <> - + <> {navCallback && ( @@ -59,6 +61,9 @@ export function BreadcrumbList({ return ( breadcrumb.url && navigateToLink(breadcrumb.url, navigate, event) diff --git a/src/frontend/src/components/nav/NavigationTree.tsx b/src/frontend/src/components/nav/NavigationTree.tsx new file mode 100644 index 000000000000..d3a102706b96 --- /dev/null +++ b/src/frontend/src/components/nav/NavigationTree.tsx @@ -0,0 +1,205 @@ +import { + ActionIcon, + Anchor, + Divider, + Drawer, + Group, + LoadingOverlay, + RenderTreeNodePayload, + Space, + Stack, + Tree, + TreeNodeData, + useTree +} from '@mantine/core'; +import { + IconChevronDown, + IconChevronRight, + IconPoint, + IconSitemap +} from '@tabler/icons-react'; +import { useQuery } from '@tanstack/react-query'; +import { useCallback, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { api } from '../../App'; +import { ApiEndpoints } from '../../enums/ApiEndpoints'; +import { ModelType } from '../../enums/ModelType'; +import { navigateToLink } from '../../functions/navigation'; +import { getDetailUrl } from '../../functions/urls'; +import { apiUrl } from '../../states/ApiState'; +import { StylishText } from '../items/StylishText'; + +/* + * A generic navigation tree component. + */ +export default function NavigationTree({ + title, + opened, + onClose, + selectedId, + modelType, + endpoint +}: { + title: string; + opened: boolean; + onClose: () => void; + selectedId?: number | null; + modelType: ModelType; + endpoint: ApiEndpoints; +}) { + const navigate = useNavigate(); + const treeState = useTree(); + + // Data query to fetch the tree data from server + const query = useQuery({ + enabled: opened, + queryKey: [modelType, opened], + queryFn: async () => + api + .get(apiUrl(endpoint), { + data: { + ordering: 'level' + } + }) + .then((response) => response.data ?? []) + .catch((error) => { + console.error(`Error fetching ${modelType} tree`); + return []; + }) + }); + + const follow = useCallback( + (node: TreeNodeData, event?: any) => { + const url = getDetailUrl(modelType, node.value); + if (event?.shiftKey || event?.ctrlKey) { + navigateToLink(url, navigate, event); + } else { + onClose(); + navigate(url); + } + }, + [modelType, navigate] + ); + + // Map returned query to a "tree" structure + const data: TreeNodeData[] = useMemo(() => { + /* + * Reconstruct the navigation tree from the provided data. + * It is required (and assumed) that the data is first sorted by level. + */ + + let nodes: Record = {}; + let tree: TreeNodeData[] = []; + + if (!query?.data?.length) { + return []; + } + + for (let ii = 0; ii < query.data.length; ii++) { + let node = { + ...query.data[ii], + children: [], + label: query.data[ii].name, + value: query.data[ii].pk.toString(), + selected: query.data[ii].pk === selectedId + }; + + const pk: number = node.pk; + const parent: number | null = node.parent; + + if (!parent) { + // This is a top level node + tree.push(node); + } else { + // This is *not* a top level node, so the parent *must* already exist + nodes[parent]?.children.push(node); + } + + // Finally, add this node + nodes[pk] = node; + + if (pk === selectedId) { + // Expand all parents + let parent = nodes[node.parent]; + while (parent) { + parent.expanded = true; + parent = nodes[parent.parent]; + } + } + } + + return tree; + }, [selectedId, query.data]); + + const renderNode = useCallback( + (payload: RenderTreeNodePayload) => { + return ( + { + if (payload.hasChildren) { + treeState.toggleExpanded(payload.node.value); + } + }} + > + + + {payload.hasChildren ? ( + payload.expanded ? ( + + ) : ( + + ) + ) : ( + + )} + + follow(payload.node, event)} + aria-label={`nav-tree-item-${payload.node.value}`} + > + {payload.node.label} + + + ); + }, + [treeState] + ); + + return ( + + + {title} + + } + > + + + + + + + ); +} diff --git a/src/frontend/src/components/nav/PanelGroup.tsx b/src/frontend/src/components/nav/PanelGroup.tsx index 5523de022c66..c7e880a64273 100644 --- a/src/frontend/src/components/nav/PanelGroup.tsx +++ b/src/frontend/src/components/nav/PanelGroup.tsx @@ -20,6 +20,7 @@ import { useParams } from 'react-router-dom'; +import { identifierString } from '../../functions/conversion'; import { navigateToLink } from '../../functions/navigation'; import { useLocalState } from '../../states/LocalState'; import { Boundary } from '../Boundary'; @@ -172,6 +173,9 @@ function BasePanelGroup({ void; - selectedCategory?: number | null; -}) { - const navigate = useNavigate(); - - const treeQuery = useQuery({ - enabled: opened, - queryKey: ['part_category_tree', opened], - queryFn: async () => - api - .get(apiUrl(ApiEndpoints.category_tree), {}) - .then((response) => - response.data.map((category: any) => { - return { - id: category.pk, - label: category.name, - parentId: category.parent, - children: category.subcategories - }; - }) - ) - .catch((error) => { - console.error('Error fetching part category tree:', error); - return []; - }), - refetchOnMount: true - }); - - function renderNode({ node }: { node: any }) { - return ( - { - onClose(); - navigate(`/part/category/${node.id}`); - }} - > - {node.label} - - ); - } - - function renderIcon({ node, open }: { node: any; open?: boolean }) { - if (node.children == 0) { - return undefined; - } - - return open ? : ; - } - - const { colorScheme } = useMantineColorScheme(); - - const themes: ThemeSettings = useMemo(() => { - const currentTheme = - colorScheme === 'dark' - ? vars.colors.defaultColor - : vars.colors.primaryColors; - - return { - dark: { - text: { - fontFamily: vars.fontFamily, - //fontSize: vars.fontSizes.md, - color: vars.colors.text - }, - nodes: { - height: '2.5rem', - folder: { - selectedBgColor: currentTheme[4], - hoverBgColor: currentTheme[6] - }, - leaf: { - selectedBgColor: currentTheme[4], - hoverBgColor: currentTheme[6] - }, - icons: { - folderColor: currentTheme[3], - leafColor: currentTheme[3] - } - } - }, - light: { - text: { - fontFamily: vars.fontFamily, - //fontSize: vars.fontSizes.md, - color: vars.colors.text - }, - nodes: { - height: '2.5rem', - folder: { - selectedBgColor: currentTheme[4], - hoverBgColor: currentTheme[2] - }, - leaf: { - selectedBgColor: currentTheme[4], - hoverBgColor: currentTheme[2] - }, - icons: { - folderColor: currentTheme[8], - leafColor: currentTheme[6] - } - } - } - }; - }, [theme]); - - return ( - - - {t`Part Categories`} - - } - > - - - - - - ); -} diff --git a/src/frontend/src/components/nav/StockLocationTree.tsx b/src/frontend/src/components/nav/StockLocationTree.tsx deleted file mode 100644 index 670183dc56df..000000000000 --- a/src/frontend/src/components/nav/StockLocationTree.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { t } from '@lingui/macro'; -import { Drawer, Group, LoadingOverlay, Stack, Text } from '@mantine/core'; -import { ReactTree } from '@naisutech/react-tree'; -import { - IconChevronDown, - IconChevronRight, - IconSitemap -} from '@tabler/icons-react'; -import { useQuery } from '@tanstack/react-query'; -import { useNavigate } from 'react-router-dom'; - -import { api } from '../../App'; -import { ApiEndpoints } from '../../enums/ApiEndpoints'; -import { apiUrl } from '../../states/ApiState'; -import { StylishText } from '../items/StylishText'; - -export function StockLocationTree({ - opened, - onClose, - selectedLocation -}: { - opened: boolean; - onClose: () => void; - selectedLocation?: number | null; -}) { - const navigate = useNavigate(); - - const treeQuery = useQuery({ - enabled: opened, - queryKey: ['stock_location_tree', opened], - queryFn: async () => - api - .get(apiUrl(ApiEndpoints.stock_location_tree), {}) - .then((response) => - response.data.map((location: any) => { - return { - id: location.pk, - label: location.name, - parentId: location.parent, - children: location.sublocations - }; - }) - ) - .catch((error) => { - console.error('Error fetching stock location tree:', error); - return []; - }), - refetchOnMount: true - }); - - function renderNode({ node }: { node: any }) { - return ( - { - onClose(); - navigate(`/stock/location/${node.id}`); - }} - > - {node.label} - - ); - } - - function renderIcon({ node, open }: { node: any; open?: boolean }) { - if (node.children == 0) { - return undefined; - } - - return open ? : ; - } - - return ( - - - {t`Stock Locations`} - - } - > - - - - - - ); -} diff --git a/src/frontend/src/functions/conversion.tsx b/src/frontend/src/functions/conversion.tsx index 1eed5db9e77e..3539a1da15b1 100644 --- a/src/frontend/src/functions/conversion.tsx +++ b/src/frontend/src/functions/conversion.tsx @@ -35,5 +35,8 @@ export function resolveItem(obj: any, path: string): any { export function identifierString(value: string): string { // Convert an input string e.g. "Hello World" into a string that can be used as an identifier, e.g. "hello-world" + + value = value || '-'; + return value.toLowerCase().replace(/[^a-z0-9]/g, '-'); } diff --git a/src/frontend/src/pages/part/CategoryDetail.tsx b/src/frontend/src/pages/part/CategoryDetail.tsx index 9ac93e71edb1..a94999e396bf 100644 --- a/src/frontend/src/pages/part/CategoryDetail.tsx +++ b/src/frontend/src/pages/part/CategoryDetail.tsx @@ -18,9 +18,9 @@ import { DeleteItemAction, EditItemAction } from '../../components/items/ActionDropdown'; +import NavigationTree from '../../components/nav/NavigationTree'; import { PageDetail } from '../../components/nav/PageDetail'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; -import { PartCategoryTree } from '../../components/nav/PartCategoryTree'; import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ModelType } from '../../enums/ModelType'; import { UserRoles } from '../../enums/Roles'; @@ -277,12 +277,15 @@ export default function CategoryDetail({}: {}) { {deleteCategory.modal} - { setTreeOpen(false); }} - selectedCategory={category?.pk} + selectedId={category?.pk} /> - { setTreeOpen(false); }} - selectedCategory={part?.category} + selectedId={part?.category} /> - setTreeOpen(false)} - selectedLocation={location?.pk} + selectedId={location?.pk} /> - setTreeOpen(false)} - selectedLocation={stockitem?.location} + selectedId={stockitem?.location} /> { await page.getByRole('menuitem', { name: 'Logout' }).click(); await page.getByRole('button', { name: 'Send me an email' }).click(); await page.getByRole('button').nth(3).click(); - await page.getByLabel('Select language').click(); + await page.getByLabel('Select language').first().click(); await page.getByRole('option', { name: 'German' }).click(); await page.waitForTimeout(200); diff --git a/src/frontend/tests/pui_stock.spec.ts b/src/frontend/tests/pui_stock.spec.ts index ce79e666ab9a..bcd08cdcdef5 100644 --- a/src/frontend/tests/pui_stock.spec.ts +++ b/src/frontend/tests/pui_stock.spec.ts @@ -95,3 +95,20 @@ test('PUI - Purchasing', async ({ page }) => { await page.getByRole('button', { name: 'Submit' }).click(); await page.getByRole('tab', { name: 'Details' }).waitFor(); }); + +test('PUI - Stock Location Tree', async ({ page }) => { + await doQuickLogin(page); + + await page.goto(`${baseUrl}/stock/location/index/`); + await page.waitForURL('**/platform/stock/location/**'); + await page.getByRole('tab', { name: 'Location Details' }).click(); + + await page.getByLabel('nav-breadcrumb-action').click(); + await page.getByLabel('nav-tree-toggle-1}').click(); + await page.getByLabel('nav-tree-item-2').click(); + + await page.getByLabel('breadcrumb-2-storage-room-a').waitFor(); + await page.getByLabel('breadcrumb-1-factory').click(); + + await page.getByRole('cell', { name: 'Factory' }).first().waitFor(); +}); diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 679e5afb178b..74b0aeb1ebc5 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -316,13 +316,20 @@ "@babel/plugin-transform-modules-commonjs" "^7.24.1" "@babel/plugin-transform-typescript" "^7.24.1" -"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.21.0": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.20.13", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.24.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.6.tgz#5b76eb89ad45e2e4a0a8db54c456251469a3358e" + integrity sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.24.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" @@ -524,13 +531,6 @@ dependencies: "@emotion/memoize" "^0.8.1" -"@emotion/is-prop-valid@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" - integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== - dependencies: - "@emotion/memoize" "^0.8.1" - "@emotion/memoize@^0.8.1": version "0.8.1" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" @@ -932,13 +932,21 @@ integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== "@floating-ui/core@^1.0.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" - integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== + version "1.6.2" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.2.tgz#d37f3e0ac1f1c756c7de45db13303a266226851a" + integrity sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg== + dependencies: + "@floating-ui/utils" "^0.2.0" + +"@floating-ui/dom@^1.0.0": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.5.tgz#323f065c003f1d3ecf0ff16d2c2c4d38979f4cb9" + integrity sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw== dependencies: - "@floating-ui/utils" "^0.2.1" + "@floating-ui/core" "^1.0.0" + "@floating-ui/utils" "^0.2.0" -"@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.6.1": +"@floating-ui/dom@^1.0.1": version "1.6.3" resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef" integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw== @@ -946,26 +954,26 @@ "@floating-ui/core" "^1.0.0" "@floating-ui/utils" "^0.2.0" -"@floating-ui/react-dom@^2.0.0": - version "2.0.8" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" - integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== +"@floating-ui/react-dom@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.0.tgz#4f0e5e9920137874b2405f7d6c862873baf4beff" + integrity sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA== dependencies: - "@floating-ui/dom" "^1.6.1" + "@floating-ui/dom" "^1.0.0" "@floating-ui/react@^0.26.9": - version "0.26.12" - resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.12.tgz#6908f774d8e3167d89b37fd83be975c7e5d8be99" - integrity sha512-D09o62HrWdIkstF2kGekIKAC0/N/Dl6wo3CQsnLcOmO3LkW6Ik8uIb3kw8JYkwxNCcg+uJ2bpWUiIijTBep05w== + version "0.26.16" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.16.tgz#3415a087f452165161c2d313d1d57e8142894679" + integrity sha512-HEf43zxZNAI/E781QIVpYSF3K2VH4TTYZpqecjdsFkjsaU1EbaWcM++kw0HXFffj7gDUcBFevX8s0rQGQpxkow== dependencies: - "@floating-ui/react-dom" "^2.0.0" + "@floating-ui/react-dom" "^2.1.0" "@floating-ui/utils" "^0.2.0" tabbable "^6.0.0" -"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" - integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== +"@floating-ui/utils@^0.2.0": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5" + integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw== "@fortawesome/fontawesome-common-types@6.5.2": version "6.5.2" @@ -1216,56 +1224,56 @@ resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-7.8.0.tgz#d49b3a57cebfc9c774467bd4c46df1005eb765f4" integrity sha512-nxuLtZ4N4KJaayab5KuaffYhiVi4UaIjywkgQiNfTxABlgFdERNfo5if9sSMyisL0r3RUPJBfLkyi8A4fEC8GQ== -"@mantine/core@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.8.0.tgz#b4bbd82ea2f1a25f5fb3d11ae5583cf80ecd8383" - integrity sha512-19RKuNdJ/s8pZjy2w2rvTsl4ybi/XM6vf+Kc0WY7kpLFCvdG+/UxNi1MuJF8t2Zs0QSFeb/H5yZQNe0XPbegHw== +"@mantine/core@^7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.10.0.tgz#bfaafc92cf2346e5a6cbb49289f577ce3f7c05f7" + integrity sha512-hNqhdn/+4x8+FDWzR5fu1eMgnG1Mw4fZHw4WjIYjKrSv0NeKHY263RiesZz8RwcUQ8r7LlD95/2tUOMnKVTV5Q== dependencies: "@floating-ui/react" "^0.26.9" - clsx "2.1.0" + clsx "^2.1.1" react-number-format "^5.3.1" react-remove-scroll "^2.5.7" react-textarea-autosize "8.5.3" type-fest "^4.12.0" "@mantine/dates@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-7.8.0.tgz#a8785030000487158e1bd23655ea26245bbf299a" - integrity sha512-9jjiYMwP3jQOpOLKkjhp9uf2BGhtEbOnOzyAlpLOS0CJJlYtB0tO6dJ3JaogrOZ/Yfee7ZUBgouCG5EkR4/qtQ== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-7.10.0.tgz#0c2a02883d5fb4a36b40a578b26ef5a697c333e5" + integrity sha512-LBBh1U/RzxFQKGA6sSYxbCwYEMoM5lNIhwofY6g8zOTAZuRQqo5FIWItmB9I9ltT+M2o75SADeP6ZBLi4ec8ZA== dependencies: - clsx "2.1.0" + clsx "^2.1.1" "@mantine/dropzone@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-7.8.0.tgz#f962c72adb585ddc7706dca680102728a52b2de7" - integrity sha512-rpNTR3NASvI3BnqhY5wg3BDhxkABT9UoZEGRrOGnS3YU7SYXg5rT9ch5Cm4iPwMNdwsyAIU6K2ii4wWk40dRpg== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-7.10.0.tgz#54283a22d1e848619a1659e38dd29852bff135e7" + integrity sha512-LFJjYvz0pSfKCSiVGLgAS94AazF2npK/ZYrr+Ax9/tdd1HgbxSd3B8SaPdGm1wOwZbpp8w0auyl3fZfqnDBG8w== dependencies: react-dropzone-esm "15.0.1" "@mantine/form@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/form/-/form-7.8.0.tgz#3f16b2e0124c65286892ed50181d192ae03d988b" - integrity sha512-Qn3/69zGt/p3wyMwGz2V0+FbmvqC2/PvXaeyO0a4CnwhROeE7ObyCKXDcBmgapOSBHr/7wFvMeTDMaTMfe3DXw== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/form/-/form-7.10.0.tgz#3e8e3fb836948becb13b89412c74016b50bac3d3" + integrity sha512-ChAtqdQCAZrnH6iiCivumyMuMsev+tFWIgsCCgAmbP2sOyMtjbNtypKrcwBwI/PzAH9N4jSJlsmJsnRdXNeEkQ== dependencies: fast-deep-equal "^3.1.3" klona "^2.0.6" "@mantine/hooks@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.8.0.tgz#fc32e07746689459c4b049dc581d1dbda5545686" - integrity sha512-+70fkgjhVJeJ+nJqnburIM3UAsfvxat1Low9HMPobLbv64FIdB4Nzu5ct3qojNQ58r5sK01tg5UoFIJYslaVrg== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-7.10.0.tgz#10a259e204a8af29df6aeeb24090c1e2c6debca0" + integrity sha512-fnalwYS2WQEFS4wmhmAetDZ/VdJPLNeUXPX9t+S21o3p/dRTX1xhU2mS7yWaQUKM0hPD1TcujqXGlP2M2g/A9A== "@mantine/modals@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-7.8.0.tgz#1960f34a7d0c45490465d61acf5da9a0c65610ca" - integrity sha512-/Kxquz8U7xau9PoqPi5Pjysfnq8b48VRAMp62B+SsPWNTH47R0F7dYRYpLQ2/0VU+OWGY0lOshxpgA61sZ3IPA== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-7.10.0.tgz#c08789491bfbfb1d432818e0fc4b2eac71fd480e" + integrity sha512-UVtmRpTBWDqcJjdv97IUYLduYcZBrqteyDwnspHT453iFZlvCglHUXYR+LvN5ExE+kxUe2IUXL/pEaIRTjwtKQ== "@mantine/notifications@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-7.8.0.tgz#90b97ca3191951bffea5da6a6ce9e607daf37bf5" - integrity sha512-O7BnaCcwVg38fh+gSZ6GEsTFPPgJAiOTrRkOMXG+7pNqJT9YNa9KDZhiPZzn3WV4wexncjyK32a8gGSVtf+kdg== + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-7.10.0.tgz#aa638b8bb6c3d6bfb34d518a49ef8a8b6ab499e4" + integrity sha512-3a0mmM9Kr3nPP+8VHsIuly507nda6ciu2aB/xSxb7gFIKHw3GqSu77pxXa+5l4Y6AQKKvP9360K4KjH6+rOBWw== dependencies: - "@mantine/store" "7.8.0" + "@mantine/store" "7.10.0" react-transition-group "4.4.5" "@mantine/spotlight@^7.8.0": @@ -1275,6 +1283,11 @@ dependencies: "@mantine/store" "7.8.0" +"@mantine/store@7.10.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@mantine/store/-/store-7.10.0.tgz#68368c6ca5b75cfb331220e06a3235be753df055" + integrity sha512-B6AyUX0cA97/hI9v0att7eJJnQTcUG7zBlTdWhOsptBV5UoDNrzdv3DDWIFxrA8h+nhNKGBh6Dif5HWh1+QLeA== + "@mantine/store@7.8.0": version "7.8.0" resolved "https://registry.yarnpkg.com/@mantine/store/-/store-7.8.0.tgz#d3ac70a96b71cbc0a4ef506bf751d8e290666d28" @@ -1292,15 +1305,6 @@ dependencies: moo "^0.5.1" -"@naisutech/react-tree@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@naisutech/react-tree/-/react-tree-3.1.0.tgz#a83820425b53a1ec7a39804ff8bd9024f0a953f4" - integrity sha512-6p1l3ZIaTmbgiAf/mpFELvqwl51LDhr+09f7L+C27DBLWjtleezCMoUuiSLhrJgpixCPNL13PuI3q2yn+0AGvA== - dependencies: - "@emotion/is-prop-valid" "^1.2.0" - nanoid "^4.0.0" - react-draggable "^4.4.5" - "@playwright/test@^1.43.1": version "1.43.1" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.43.1.tgz#16728a59eb8ce0f60472f98d8886d6cab0fa3e42" @@ -2114,16 +2118,21 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@2.1.0, clsx@^2.0.0, clsx@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" - integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== - clsx@^1.1.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +clsx@^2.0.0, clsx@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" + integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + codemirror-spell-checker@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" @@ -2361,9 +2370,9 @@ date-fns@^3.6.0: integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== dayjs@^1.11.10: - version "1.11.10" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" - integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + version "1.11.11" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" + integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: version "4.3.4" @@ -3315,11 +3324,6 @@ nanoid@^3.3.6, nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== -nanoid@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" - integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== - node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -3721,9 +3725,9 @@ react-remove-scroll-bar@^2.3.6: tslib "^2.0.0" react-remove-scroll@^2.5.7: - version "2.5.9" - resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.9.tgz#6a38e7d46043abc2c6b0fb39db650b9f2e38be3e" - integrity sha512-bvHCLBrFfM2OgcrpPY2YW84sPdS2o2HKWJUf1xGyGLnSoEnOTOBpahIarjRuYtN0ryahCeP242yf+5TrBX/pZA== + version "2.5.10" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.10.tgz#5fae456a23962af6d3c38ca1978bcfe0806c4061" + integrity sha512-m3zvBRANPBw3qxVVjEIPEQinkcwlFZ4qyomuWVpNJdv4c6MvHfXV0C3L9Jx5rr3HeBHKNRX+1jreB5QloDIJjA== dependencies: react-remove-scroll-bar "^2.3.6" react-style-singleton "^2.2.1" @@ -3843,10 +3847,10 @@ recharts-scale@^0.4.4: dependencies: decimal.js-light "^2.4.1" -recharts@^2.12.4: - version "2.12.5" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.5.tgz#b335eb66173317dccb3e126fce1d7ac5b3cee1e9" - integrity sha512-Cy+BkqrFIYTHJCyKHJEPvbHE2kVQEP6PKbOHJ8ztRGTAhvHuUnCwDaKVb13OwRFZ0QNUk1QvGTDdgWSMbuMtKw== +recharts@2: + version "2.12.7" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.12.7.tgz#c7f42f473a257ff88b43d88a92530930b5f9e773" + integrity sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ== dependencies: clsx "^2.0.0" eventemitter3 "^4.0.1" @@ -4276,9 +4280,9 @@ type-fest@^0.8.0: integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^4.12.0: - version "4.15.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.15.0.tgz#21da206b89c15774cc718c4f2d693e13a1a14a43" - integrity sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA== + version "4.18.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.18.3.tgz#5249f96e7c2c3f0f1561625f54050e343f1c8f68" + integrity sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ== typedarray-to-buffer@^3.1.5: version "3.1.5"