diff --git a/src/frontend/CHANGELOG.md b/src/frontend/CHANGELOG.md index 4e62d3cfc3..158082281c 100644 --- a/src/frontend/CHANGELOG.md +++ b/src/frontend/CHANGELOG.md @@ -2,7 +2,19 @@ This file contains historical changelog information for the InvenTree UI components library. -### 0.11.4 - Unreleased +### 1.4.0 - May 2026 + +#### Version Numbering + +This update brings the version numbering in-line with the core InvenTree server version, which is currently at `1.4.0`. This versioning scheme will be maintained going forward, with the UI components library version matching the core server version. + +Thus, version `1.4.x` of the UI components library will be compatible with version `1.4.x` of the InvenTree server, and so on. + +#### Mantine Library Update + +The underlying Mantine library has been updated from version `8.x` to version `9.x`. This update may introduce breaking changes for plugins that rely on the InvenTree UI components library, as the Mantine library is a core dependency. Plugin developers should test their plugins against this new version to ensure compatibility. + +#### New Components Adds additional functions in the plugin context related to form rendering and API invocation: - `useInstance` @@ -15,7 +27,6 @@ Exposes sub-components related to DetailDrawer rendering: - `DetailDrawerComponent` - `useLocalLibState` - ### 0.11.3 - April 2026 Exposes additional type definitions related to rendering drawers from tables: diff --git a/src/frontend/lib/components/RowActions.tsx b/src/frontend/lib/components/RowActions.tsx index 464744277c..ff2ad44c40 100644 --- a/src/frontend/lib/components/RowActions.tsx +++ b/src/frontend/lib/components/RowActions.tsx @@ -139,8 +139,8 @@ export function RowActions({ aria-label={`row-action-menu-${index ?? ''}`} onClick={openMenu} disabled={disabled} - variant='subtle' - color='gray' + variant='transparent' + size='sm' > diff --git a/src/frontend/lib/hooks/UseFilterSet.tsx b/src/frontend/lib/hooks/UseFilterSet.tsx index 80a7791f1e..52749f0c54 100644 --- a/src/frontend/lib/hooks/UseFilterSet.tsx +++ b/src/frontend/lib/hooks/UseFilterSet.tsx @@ -1,5 +1,5 @@ import { useLocalStorage } from '@mantine/hooks'; -import { useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import type { FilterSetState, TableFilter } from '../types/Filters'; export default function useFilterSet( @@ -16,15 +16,15 @@ export default function useFilterSet( getInitialValueInEffect: false }); - const activeFilters: TableFilter[] = useMemo(() => { + useEffect(() => { if (storedFilters == null) { - // If there are no stored filters, set initial values - const filters = initialFilters || []; - setStoredFilters(filters); - return filters; + setStoredFilters(initialFilters || []); } - return storedFilters || []; - }, [storedFilters]); + }, [storedFilters, initialFilters, setStoredFilters]); + + const activeFilters: TableFilter[] = useMemo(() => { + return storedFilters ?? initialFilters ?? []; + }, [storedFilters, initialFilters]); // Callback to clear all active filters from the table const clearActiveFilters = useCallback(() => { diff --git a/src/frontend/lib/types/Tables.tsx b/src/frontend/lib/types/Tables.tsx index aa8272f727..4b3d064f79 100644 --- a/src/frontend/lib/types/Tables.tsx +++ b/src/frontend/lib/types/Tables.tsx @@ -100,7 +100,7 @@ export type TableState = { */ export type TableColumnProps = { accessor?: string; - title?: string; + title?: string | ReactNode; ordering?: string; sortable?: boolean; switchable?: boolean; diff --git a/src/frontend/package.json b/src/frontend/package.json index 132cd11437..dd80683ac5 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -1,7 +1,7 @@ { "name": "@inventreedb/ui", "description": "UI components for the InvenTree project", - "version": "0.11.3", + "version": "1.4.0", "private": false, "type": "module", "license": "MIT", @@ -60,17 +60,17 @@ "@github/webauthn-json": "^2.1.1", "@lingui/core": "^5.9.2", "@lingui/react": "^5.9.2", - "@mantine/carousel": "^8.2.7", - "@mantine/charts": "^8.2.7", - "@mantine/core": "^8.2.7", - "@mantine/dates": "^8.2.7", - "@mantine/dropzone": "^8.2.7", - "@mantine/form": "^8.2.7", - "@mantine/hooks": "^8.2.7", - "@mantine/modals": "^8.2.7", - "@mantine/notifications": "^8.2.7", - "@mantine/spotlight": "^8.2.7", - "@mantine/vanilla-extract": "^8.2.7", + "@mantine/carousel": "^9.2.1", + "@mantine/charts": "^9.2.1", + "@mantine/core": "^9.2.1", + "@mantine/dates": "^9.2.1", + "@mantine/dropzone": "^9.2.1", + "@mantine/form": "^9.2.1", + "@mantine/hooks": "^9.2.1", + "@mantine/modals": "^9.2.1", + "@mantine/notifications": "^9.2.1", + "@mantine/spotlight": "^9.2.1", + "@mantine/vanilla-extract": "^9.2.1", "@messageformat/date-skeleton": "^1.1.0", "@sentry/react": "^10.43.0", "@tabler/icons-react": "^3.17.0", @@ -89,8 +89,8 @@ "embla-carousel-react": "^8.5.2", "fuse.js": "^7.0.0", "html5-qrcode": "^2.3.8", - "mantine-contextmenu": "^8.2.0", - "mantine-datatable": "^8.2.0", + "mantine-contextmenu": "^9.2.1", + "mantine-datatable": "^9.2.0", "qrcode": "^1.5.4", "react": "^19.2.4", "react-dom": "^19.2.4", diff --git a/src/frontend/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx b/src/frontend/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx index fa531ce69e..c1b28f20d0 100644 --- a/src/frontend/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx +++ b/src/frontend/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx @@ -1,7 +1,7 @@ -import { ActionIcon, Anchor, Group, Loader } from '@mantine/core'; +import { ActionIcon, Anchor, Group, RollingNumber } from '@mantine/core'; import { IconExclamationCircle } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; -import { type ReactNode, useCallback, useMemo } from 'react'; +import { type ReactNode, useCallback, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { StylishText } from '@lib/components/StylishText'; @@ -37,11 +37,15 @@ function QueryCountWidget({ const modelProperties = ModelInformationDict[modelType]; + const [count, setCount] = useState(0); + const query = useQuery({ queryKey: ['dashboard-query-count', modelType, params, visibility], enabled: user.hasViewPermission(modelType) && visibility === 'visible', + refetchOnWindowFocus: false, refetchOnMount: true, refetchInterval: 10 * 60 * 1000, // 10 minute refetch interval + staleTime: 5 * 60 * 1000, // 5 minute stale time queryFn: () => { if (visibility !== 'visible') { return null; @@ -54,7 +58,10 @@ function QueryCountWidget({ limit: 1 } }) - .then((res) => res.data); + .then((res) => { + setCount(res.data?.count ?? 0); + return res.data; + }); } }); @@ -81,18 +88,16 @@ function QueryCountWidget({ ); const result: ReactNode = useMemo(() => { - if (query.isFetching) { - return ; - } else if (query.isError) { + if (query.isError) { return ( ); } else { - return {query.data?.count ?? '-'}; + return ; } - }, [query.isFetching, query.isError, query.data]); + }, [query.isFetching, query.isError, count]); return ( diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index 32a506acdc..cd53a45f1d 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -81,10 +81,14 @@ export function ApiFormField({ ...fieldDefinition, autoFill: undefined, placeholderAutofill: undefined, + placeholderWarning: undefined, + placeholderWarningCompare: undefined, + singleFetchFunction: undefined, autoFillFilters: undefined, onValueChange: undefined, adjustFilters: undefined, adjustValue: undefined, + allow_blank: undefined, allow_null: undefined, read_only: undefined, children: undefined, diff --git a/src/frontend/src/components/forms/fields/RelatedModelField.tsx b/src/frontend/src/components/forms/fields/RelatedModelField.tsx index 259fab72f2..70e427549e 100644 --- a/src/frontend/src/components/forms/fields/RelatedModelField.tsx +++ b/src/frontend/src/components/forms/fields/RelatedModelField.tsx @@ -419,7 +419,13 @@ export function RelatedModelField({ modelRenderer: undefined, onValueChange: undefined, adjustFilters: undefined, + adjustValue: undefined, + placeholderAutofill: undefined, + placeholderWarning: undefined, + placeholderWarningCompare: undefined, + singleFetchFunction: undefined, exclude: undefined, + allow_blank: undefined, allow_null: undefined, read_only: undefined }; diff --git a/src/frontend/src/components/nav/Header.tsx b/src/frontend/src/components/nav/Header.tsx index 299feafb6f..8324da3e9a 100644 --- a/src/frontend/src/components/nav/Header.tsx +++ b/src/frontend/src/components/nav/Header.tsx @@ -114,7 +114,9 @@ export function Header() { }, // Refetch every minute, *if* the tab is visible refetchInterval: 60 * 1000, - refetchOnMount: true + refetchOnMount: true, + refetchOnWindowFocus: false, + staleTime: 30 * 1000 }); // Sync Navigation Drawer state with zustand diff --git a/src/frontend/src/components/nav/PageDetail.tsx b/src/frontend/src/components/nav/PageDetail.tsx index e91afa384a..d8cbb6b167 100644 --- a/src/frontend/src/components/nav/PageDetail.tsx +++ b/src/frontend/src/components/nav/PageDetail.tsx @@ -48,7 +48,10 @@ export function PageDetail({ useHotkeys([ [ 'mod+E', - () => { + (event) => { + if (event.repeat) { + return; + } if (editEnabled ?? true) { editAction?.(); } diff --git a/src/frontend/src/components/nav/SearchDrawer.tsx b/src/frontend/src/components/nav/SearchDrawer.tsx index 1d5874eb6f..cb2066a903 100644 --- a/src/frontend/src/components/nav/SearchDrawer.tsx +++ b/src/frontend/src/components/nav/SearchDrawer.tsx @@ -30,7 +30,7 @@ import { IconX } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; import { type NavigateFunction, useNavigate } from 'react-router-dom'; import { Boundary } from '@lib/components/Boundary'; @@ -165,7 +165,7 @@ function QueryResultGroup({ {query.results.results.map((result: any, index: number) => ( - <> + )} - + ))} diff --git a/src/frontend/src/components/panels/PanelGroup.tsx b/src/frontend/src/components/panels/PanelGroup.tsx index a5dcf701e5..c07249f303 100644 --- a/src/frontend/src/components/panels/PanelGroup.tsx +++ b/src/frontend/src/components/panels/PanelGroup.tsx @@ -370,6 +370,7 @@ function BasePanelGroup({ (panel) => !panel.hidden && ( diff --git a/src/frontend/src/hooks/UseForm.tsx b/src/frontend/src/hooks/UseForm.tsx index c92f321f6d..b832be4dae 100644 --- a/src/frontend/src/hooks/UseForm.tsx +++ b/src/frontend/src/hooks/UseForm.tsx @@ -62,14 +62,18 @@ export function useApiFormModal(props: ApiFormModalProps) { id: modalId, title: formProps.title, onOpen: () => { - setIsOpen(true); - modalState.setModalOpen(modalId, true); - formProps.onOpen?.(); + queueMicrotask(() => { + setIsOpen(true); + modalState.setModalOpen(modalId, true); + formProps.onOpen?.(); + }); }, onClose: () => { - setIsOpen(false); - modalState.setModalOpen(modalId, false); - formProps.onClose?.(); + queueMicrotask(() => { + setIsOpen(false); + modalState.setModalOpen(modalId, false); + formProps.onClose?.(); + }); }, closeOnClickOutside: formProps.closeOnClickOutside, size: props.size ?? 'xl', diff --git a/src/frontend/src/pages/Index/Settings/AccountSettings/UserPanel.tsx b/src/frontend/src/pages/Index/Settings/AccountSettings/UserPanel.tsx index 918418452c..8e1e2ce9eb 100644 --- a/src/frontend/src/pages/Index/Settings/AccountSettings/UserPanel.tsx +++ b/src/frontend/src/pages/Index/Settings/AccountSettings/UserPanel.tsx @@ -8,17 +8,15 @@ export function AccountContent() { const SECONDARY_COL_HEIGHT = PRIMARY_COL_HEIGHT / 2 - 8; return ( -
- - - - - - - - - - -
+ + + + + + + + + + ); } diff --git a/src/frontend/src/tables/ColumnRenderers.tsx b/src/frontend/src/tables/ColumnRenderers.tsx index a60642bb05..1c0bed0ede 100644 --- a/src/frontend/src/tables/ColumnRenderers.tsx +++ b/src/frontend/src/tables/ColumnRenderers.tsx @@ -330,7 +330,7 @@ export function PathColumn(props: TableColumnProps): TableColumn { {instance.name}} icon='sitemap' - title={props.title} + title={props.title?.toLocaleString() ?? t`Path`} extra={[{instance.pathstring}]} /> ); diff --git a/src/frontend/src/tables/InvenTreeTable.tsx b/src/frontend/src/tables/InvenTreeTable.tsx index c8b78770ba..714edf23ab 100644 --- a/src/frontend/src/tables/InvenTreeTable.tsx +++ b/src/frontend/src/tables/InvenTreeTable.tsx @@ -7,7 +7,6 @@ import { cancelEvent } from '@lib/functions/Events'; import { mapFields } from '@lib/functions/Forms'; import { getDetailUrl } from '@lib/functions/Navigation'; import { navigateToLink } from '@lib/functions/Navigation'; -import { hashString } from '@lib/functions/String'; import { useStoredTableState } from '@lib/states/StoredTableState'; import type { TableFilter } from '@lib/types/Filters'; import type { ApiFormFieldSet } from '@lib/types/Forms'; @@ -18,8 +17,8 @@ import type { } from '@lib/types/Tables'; import type { TableColumn } from '@lib/types/Tables'; import { t } from '@lingui/core/macro'; -import { Box, Stack } from '@mantine/core'; -import { IconArrowRight } from '@tabler/icons-react'; +import { ActionIcon, Box, Stack } from '@mantine/core'; +import { IconArrowRight, IconClick } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { type ContextMenuItemOptions, @@ -254,12 +253,6 @@ export function InvenTreeTableInternal>({ [tableState.setSelectedRecords] ); - // A hash of the current column configuration - // This is a workaround to fix an issue with mantine-datatable where - // the columns do not update correctly when they are changed dynamically - // Ref: https://github.com/icflorescu/mantine-datatable/issues/759 - const [columnHash, setColumnHash] = useState(''); - // Update column visibility when hiddenColumns change const dataColumns: any = useMemo(() => { let cols: TableColumn[] = columns.filter((col) => col?.hidden != true); @@ -326,7 +319,11 @@ export function InvenTreeTableInternal>({ if (tableProps.rowActions) { cols.push({ accessor: ACTIONS_COLUMN_ACCESSOR, - title: ' ', + title: ( + + + + ), hidden: false, resizable: false, switchable: false, @@ -350,13 +347,6 @@ export function InvenTreeTableInternal>({ tableState.selectedRecords ]); - useEffect(() => { - const columnNames: string = dataColumns - .map((col: any) => col.accessor) - .join(','); - setColumnHash(hashString(columnNames)); - }, [dataColumns]); - // Callback when column visibility is toggled const toggleColumn = useCallback( (columnName: string) => { @@ -378,19 +368,25 @@ export function InvenTreeTableInternal>({ [cacheKey, dataColumns] ); + // Generate an ordered list of column names, + // which we use to ensure the table is reloaded correctly when columns are added/removed/renamed + const tableColumnNames = useMemo( + () => dataColumns.map((col: any) => col.accessor).join(','), + [dataColumns] + ); + // Final state of the table columns const tableColumns = useDataTableColumns({ - key: `${cacheKey}-${columnHash}`, + key: cacheKey, columns: dataColumns, getInitialValueInEffect: false }); // Reset column ordering and custom widths when the component is mounted - // Ref: https://github.com/icflorescu/mantine-datatable/issues/759#issuecomment-4148942070 + // Ref: https://github.com/icflorescu/mantine-datatable/issues/759 useEffect(() => { - tableColumns.resetColumnsOrder(); - tableColumns.resetColumnsWidth(); - }, []); + tableColumns.setColumnsOrder(dataColumns.map((col: any) => col.accessor)); + }, [tableColumnNames]); // Reset the pagination state when the search term changes useEffect(() => { diff --git a/src/frontend/src/tables/build/BuildOutputTable.tsx b/src/frontend/src/tables/build/BuildOutputTable.tsx index 9b3f182a5e..2ecdcb2f76 100644 --- a/src/frontend/src/tables/build/BuildOutputTable.tsx +++ b/src/frontend/src/tables/build/BuildOutputTable.tsx @@ -122,6 +122,9 @@ function OutputAllocationDrawer({ opened={opened} onClose={close} withCloseButton + closeButtonProps={{ + 'aria-label': 'close-allocation-drawer' + }} closeOnEscape closeOnClickOutside styles={{ diff --git a/src/frontend/tests/login.ts b/src/frontend/tests/login.ts index ab19bddbba..4bb52d44f9 100644 --- a/src/frontend/tests/login.ts +++ b/src/frontend/tests/login.ts @@ -36,8 +36,8 @@ export const doLogin = async (page: Page, options?: LoginOptions) => { await page.waitForURL('**/web/login'); - await page.getByLabel('username').fill(username); - await page.getByLabel('password').fill(password); + await page.getByRole('textbox', { name: 'login-username' }).fill(username); + await page.getByRole('textbox', { name: 'login-password' }).fill(password); await page.waitForTimeout(100); diff --git a/src/frontend/tests/pages/pui_build.spec.ts b/src/frontend/tests/pages/pui_build.spec.ts index 0e01e57c99..bdc9cb34a9 100644 --- a/src/frontend/tests/pages/pui_build.spec.ts +++ b/src/frontend/tests/pages/pui_build.spec.ts @@ -225,6 +225,7 @@ test('Build Order - Build Outputs', async ({ browser }) => { await page.getByRole('cell', { name: 'BO0011' }).click(); await loadTab(page, 'Incomplete Outputs'); + await page.getByRole('cell', { name: 'BX-123' }).waitFor(); // Check the "printing" actions for the selected outputs await page.getByRole('checkbox', { name: 'Select all records' }).check(); @@ -523,6 +524,8 @@ test('Build Order - Consume Stock', async ({ browser }) => { // Consume the rest of the stock via line items await loadTab(page, 'Required Parts'); + await page.getByText('10K resistor in 0805 SMD').first().waitFor(); + await page.getByRole('checkbox', { name: 'Select all records' }).check(); await page .getByRole('button', { name: 'action-button-consume-stock' }) @@ -603,7 +606,7 @@ test('Build Order - Tracked Outputs', async ({ browser }) => { await allocationRow.getByText('1 / 1').waitFor(); // Close the allocation wizard - await page.getByRole('banner').getByRole('button').click(); + await page.getByRole('button', { name: 'close-allocation-drawer' }).click(); // Check that the output is now allocated as expected await row.getByText('1 / 6').waitFor(); diff --git a/src/frontend/tests/pages/pui_dashboard.spec.ts b/src/frontend/tests/pages/pui_dashboard.spec.ts index dd9ef7ea05..07af2a5a0b 100644 --- a/src/frontend/tests/pages/pui_dashboard.spec.ts +++ b/src/frontend/tests/pages/pui_dashboard.spec.ts @@ -1,6 +1,8 @@ import type { Page } from '@playwright/test'; import { expect } from '@playwright/test'; +import { createApi } from '../api.js'; import { test } from '../baseFixtures.js'; +import { allaccessuser } from '../defaults.js'; import { doCachedLogin } from '../login.js'; import { setPluginState } from '../settings.js'; @@ -96,9 +98,7 @@ test('Dashboard - Plugins', async ({ browser }) => { await page.getByText('Hello world! This is a sample').waitFor(); }); -test('Dashboard - Preserve widget sizes when adding new widget', async ({ - browser -}) => { +test('Dashboard - Preserve widget sizes', async ({ browser }) => { // Regression: addWidget previously snapped every existing widget back to // its minW/minH. Fix is in DashboardLayout.tsx::addWidget (overrideSize=false). const TARGET_W = 10; @@ -110,7 +110,11 @@ test('Dashboard - Preserve widget sizes when adding new widget', async ({ return raw ? (JSON.parse(raw)?.state?.layouts ?? {}) : {}; }); - const page = await doCachedLogin(browser); + const user = allaccessuser; + + const page = await doCachedLogin(browser, { + user: user + }); await resetDashboard(page); // Add widget A; this also persists to the backend user profile. @@ -120,7 +124,7 @@ test('Dashboard - Preserve widget sizes when adding new widget', async ({ await page.getByLabel('add-widget-ovr-so').click(); await page.getByRole('banner').getByRole('button').click(); await page.getByText('Overdue Sales Orders').waitFor(); - await page.waitForTimeout(500); + await page.waitForTimeout(100); // Inflate widget A on the backend profile and reload. The auth flow on // page load rehydrates layouts from the profile, not localStorage, so a @@ -132,26 +136,31 @@ test('Dashboard - Preserve widget sizes when adding new widget', async ({ it?.i === 'ovr-so' ? { ...it, w: TARGET_W, h: TARGET_H } : it ); } - await page.evaluate(async (layouts) => { - const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] ?? ''; - await fetch('/api/user/profile/', { - method: 'PATCH', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': csrf - }, - body: JSON.stringify({ widgets: { widgets: ['ovr-so'], layouts } }) - }); - }, inflated); + + const api = createApi({ + username: user.username, + password: user.testcred + }); + + (await api).patch('user/profile/', { + data: { + widgets: { + widgets: ['ovr-so'], + layouts: inflated + } + } + }); await page.reload(); await page.getByText('Overdue Sales Orders').waitFor(); - await page.waitForTimeout(500); + await page.waitForTimeout(100); // Sanity: profile rehydration produced the inflated values. for (const [bp, items] of Object.entries(await readLayouts(page))) { const entry = (items as any[]).find((i) => i?.i === 'ovr-so'); + + console.log('entry:', bp, entry); + expect(entry?.w, `${bp}: ovr-so missing or wrong w`).toBe(TARGET_W); expect(entry?.h, `${bp}: ovr-so missing or wrong h`).toBe(TARGET_H); } @@ -163,7 +172,7 @@ test('Dashboard - Preserve widget sizes when adding new widget', async ({ await page.getByLabel('add-widget-ovr-po').click(); await page.getByRole('banner').getByRole('button').click(); await page.getByText('Overdue Purchase Orders').waitFor(); - await page.waitForTimeout(800); + await page.waitForTimeout(100); for (const [bp, items] of Object.entries(await readLayouts(page))) { const entry = (items as any[]).find((i) => i?.i === 'ovr-so'); diff --git a/src/frontend/tests/pages/pui_part.spec.ts b/src/frontend/tests/pages/pui_part.spec.ts index ab3dd9952e..72726aa541 100644 --- a/src/frontend/tests/pages/pui_part.spec.ts +++ b/src/frontend/tests/pages/pui_part.spec.ts @@ -344,7 +344,9 @@ test('Parts - BOM Comparison', async ({ browser }) => { await page.getByText('Removed from BOM').first().waitFor(); // Change display mode - await page.getByRole('textbox', { name: 'bom-compare-display-mode' }).click(); + await page + .getByRole('combobox', { name: 'bom-compare-display-mode' }) + .click(); await page.getByRole('option', { name: 'Show different Parts' }).click(); // Use URL params to compare directly diff --git a/src/frontend/tests/pages/pui_purchasing.spec.ts b/src/frontend/tests/pages/pui_purchasing.spec.ts index 8c06c4cc13..6025e15ab2 100644 --- a/src/frontend/tests/pages/pui_purchasing.spec.ts +++ b/src/frontend/tests/pages/pui_purchasing.spec.ts @@ -162,7 +162,7 @@ test('Purchasing - Manufacturer Parts', async ({ browser }) => { await page.getByRole('button', { name: 'table-export-data' }).click(); await page.getByText('Select export plugin').waitFor(); await page - .getByRole('textbox', { name: 'choice-field-export_plugin' }) + .getByRole('combobox', { name: 'choice-field-export_plugin' }) .fill('CSV'); await page.getByRole('button', { name: 'Export', exact: true }).click(); await page.getByText('Process completed successfully').waitFor(); @@ -509,8 +509,9 @@ test('Purchase Orders - Receive Items', async ({ browser }) => { // Select all line items to receive await loadTab(page, 'Line Items'); + await page.getByRole('cell', { name: '002.02-PCB' }).waitFor(); await page.getByLabel('Select all records').click(); - await page.waitForTimeout(200); + await page.waitForTimeout(100); await page.getByLabel('action-button-receive-items').click(); // Check for display of individual locations @@ -606,6 +607,8 @@ test('Purchase Orders - Receive Virtual Items', async ({ browser }) => { // Receive the line item await loadTab(page, 'Line Items'); + await page.getByRole('cell', { name: 'Thumbnail CRM license' }).waitFor(); + await page.getByRole('checkbox', { name: 'Select all records' }).click(); await page .getByRole('button', { name: 'action-button-receive-items' }) diff --git a/src/frontend/tests/pages/pui_return.spec.ts b/src/frontend/tests/pages/pui_return.spec.ts index b3656a1c30..96962d0574 100644 --- a/src/frontend/tests/pages/pui_return.spec.ts +++ b/src/frontend/tests/pages/pui_return.spec.ts @@ -12,6 +12,8 @@ test('Return Orders - Receive Items', async ({ browser }) => { await loadTab(page, 'Attachments'); await loadTab(page, 'Line Items'); + await page.getByRole('cell', { name: 'WID-REV-A' }).first().waitFor(); + await page.getByRole('checkbox', { name: 'Select all records' }).click(); await page.getByRole('button', { name: 'action-button-receive-' }).click(); await page.getByRole('banner').getByText('Receive Items').waitFor(); diff --git a/src/frontend/tests/pages/pui_stock.spec.ts b/src/frontend/tests/pages/pui_stock.spec.ts index 0592576892..eef8ee935c 100644 --- a/src/frontend/tests/pages/pui_stock.spec.ts +++ b/src/frontend/tests/pages/pui_stock.spec.ts @@ -111,14 +111,14 @@ test('Stock - Location Delete', async ({ browser }) => { .click(); await page - .getByRole('textbox', { name: 'choice-field-delete_stock_items' }) + .getByRole('combobox', { name: 'choice-field-delete_stock_items' }) .click(); await page .getByRole('option', { name: 'Move items to parent location' }) .click(); await page - .getByRole('textbox', { name: 'choice-field-delete_sub_locations' }) + .getByRole('combobox', { name: 'choice-field-delete_sub_locations' }) .click(); await page.getByRole('option', { name: 'Delete items' }).click(); diff --git a/src/frontend/tests/pui_exporting.spec.ts b/src/frontend/tests/pui_exporting.spec.ts index 8f2dcbd253..acf9a38345 100644 --- a/src/frontend/tests/pui_exporting.spec.ts +++ b/src/frontend/tests/pui_exporting.spec.ts @@ -6,7 +6,8 @@ import { doCachedLogin } from './login'; // Helper function to open the export data dialog const openExportDialog = async (page) => { await page.waitForLoadState('networkidle'); - await page.getByLabel('table-export-data').click(); + + await page.getByRole('button', { name: 'table-export-data' }).click(); await page.getByText('Export Format *', { exact: true }).waitFor(); await page.getByText('Export Plugin *', { exact: true }).waitFor(); }; diff --git a/src/frontend/tests/pui_importing.spec.ts b/src/frontend/tests/pui_importing.spec.ts index 0d1233eadc..abd34cb201 100644 --- a/src/frontend/tests/pui_importing.spec.ts +++ b/src/frontend/tests/pui_importing.spec.ts @@ -26,7 +26,7 @@ test('Importing - Admin Center', async ({ browser }) => { await page.getByText('Errors exist for one or more').waitFor(); await page - .getByRole('textbox', { name: 'choice-field-model_type' }) + .getByRole('combobox', { name: 'choice-field-model_type' }) .fill('bom'); await page.getByRole('option', { name: 'BOM Item', exact: true }).click(); await page.getByRole('button', { name: 'Submit' }).click(); @@ -36,7 +36,7 @@ test('Importing - Admin Center', async ({ browser }) => { await page.getByText('Existing database identifier for the record').waitFor(); await page - .getByRole('textbox', { name: 'import-column-map-reference' }) + .getByRole('combobox', { name: 'import-column-map-reference' }) .click(); await page.getByRole('option', { name: 'Ignore this field' }).click(); @@ -195,7 +195,7 @@ test('Importing - Natural Keys', async ({ browser }) => { // Select different columns for data import // We will use the "SKU" field to map to the supplier part - await page.getByRole('textbox', { name: 'import-column-map-part' }).click(); + await page.getByRole('combobox', { name: 'import-column-map-part' }).click(); await page.getByRole('option', { name: 'SKU' }).click(); // Other import fields will be left as default diff --git a/src/frontend/tests/pui_machines.spec.ts b/src/frontend/tests/pui_machines.spec.ts index a764c8d105..0d5987b2ab 100644 --- a/src/frontend/tests/pui_machines.spec.ts +++ b/src/frontend/tests/pui_machines.spec.ts @@ -47,14 +47,17 @@ test('Machines - Activation', async ({ browser }) => { .getByRole('textbox', { name: 'text-field-name' }) .fill('my-dummy-machine'); await page - .getByRole('textbox', { name: 'choice-field-machine_type' }) + .getByRole('combobox', { name: 'choice-field-machine_type' }) .fill('label'); await page.getByRole('option', { name: 'Label Printer' }).click(); - await page.getByRole('textbox', { name: 'choice-field-driver' }).click(); + await page.getByRole('combobox', { name: 'choice-field-driver' }).click(); + await page.waitForTimeout(200); await page .getByRole('option', { name: 'Sample Label Printer Driver' }) .click(); + await page.waitForTimeout(200); + await page.getByRole('button', { name: 'Submit' }).click(); } else { // Machine already exists - just click on it to open the "machine drawer" @@ -64,10 +67,13 @@ test('Machines - Activation', async ({ browser }) => { // Creating the new machine opens the "machine drawer" // Check for "machine type" settings - await page.getByText('Scope the printer to a specific location').waitFor(); + await page + .getByText('Scope the printer to a specific location') + .first() + .waitFor(); // Check for "machine driver" settings - await page.getByText('Custom string for connecting').waitFor(); + await page.getByText('Custom string for connecting').first().waitFor(); // Edit the available setting await page.getByRole('button', { name: 'edit-setting-CONNECTION' }).click(); @@ -94,6 +100,7 @@ test('Machines - Activation', async ({ browser }) => { // Let's print something with the machine await navigate(page, 'stock/location/1/stock-items'); + await page.getByText('Blue plastic enclosure').first().waitFor(); await page.getByRole('checkbox', { name: 'Select all records' }).check(); await page @@ -110,7 +117,7 @@ test('Machines - Activation', async ({ browser }) => { await page.getByText('InvenTreeLabelMachine').click(); await page - .getByRole('textbox', { name: 'choice-field-machine' }) + .getByRole('combobox', { name: 'choice-field-machine' }) .fill('dummy'); await page.getByRole('option', { name: 'my-dummy-machine' }).click(); diff --git a/src/frontend/tests/pui_settings.spec.ts b/src/frontend/tests/pui_settings.spec.ts index 35f2936dbd..c594f003f6 100644 --- a/src/frontend/tests/pui_settings.spec.ts +++ b/src/frontend/tests/pui_settings.spec.ts @@ -45,9 +45,9 @@ test('Settings - User theme', async ({ browser }) => { await page.getByRole('menuitem', { name: 'User settings' }).click(); // loader - await page.getByRole('textbox', { name: 'Loader Type Selector' }).click(); + await page.getByRole('combobox', { name: 'Loader Type Selector' }).click(); await page.getByRole('option', { name: 'Oval' }).click(); - await page.getByRole('textbox', { name: 'Loader Type Selector' }).click(); + await page.getByRole('combobox', { name: 'Loader Type Selector' }).click(); await page.getByRole('option', { name: 'Bars' }).click(); // dark / light mode @@ -92,7 +92,7 @@ test('Settings - User', async ({ browser }) => { await page.getByText('Profile Details').waitFor(); // Language selection - await page.getByRole('textbox', { name: 'Select language' }).click(); + await page.getByRole('combobox', { name: 'Select language' }).click(); await page.getByRole('option', { name: 'العربية' }).waitFor(); await page.getByRole('option', { name: 'Deutsch' }).waitFor(); await page.getByRole('option', { name: 'English' }).waitFor(); @@ -321,8 +321,8 @@ test('Settings - Admin - Background Tasks', async ({ browser }) => { // Background worker should be running, and idle await page.getByText('Background worker running').waitFor(); - await page.getByText('Failed Tasks0').waitFor(); - await page.getByText('Pending Tasks0').waitFor(); + await page.getByText(/Failed Tasks\d+/).waitFor(); + await page.getByText(/Pending Tasks\d+/).waitFor(); // Expand the "scheduled tasks" view await page.getByRole('button', { name: 'Scheduled Tasks' }).click(); diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 4596ca15f4..ba2887a475 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -874,7 +874,7 @@ dependencies: "@floating-ui/dom" "^1.7.6" -"@floating-ui/react@^0.27.16": +"@floating-ui/react@^0.27.19": version "0.27.19" resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.27.19.tgz#d8d5d895b7cb97dac370bfbf55f3e630878fdf1f" integrity sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog== @@ -1169,84 +1169,84 @@ "@babel/runtime" "^7.20.13" "@lingui/core" "5.9.3" -"@mantine/carousel@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-8.3.18.tgz#55489c09de7a7ccb3b758d3386eef56db91cec4b" - integrity sha512-jrXqpoiL+/GTTgW4/UWLqvo5pWnUEvuwaUlvD/Yl8XC+iyBiZHgzyq0erEMIRGertVvpet4vsiZjye7ycPHlfA== +"@mantine/carousel@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-9.2.1.tgz#bc470ae1c2801d66b40de9d1e76eee869995fb1c" + integrity sha512-b0ZBDnKhzztEFWNWbbFpPMqaV/4k/lclX8KB0PfU+qhu3Fa6wjS1VIn4XLZu9N3vgkzPkNXwDzpcwFShA9Uvqw== -"@mantine/charts@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/charts/-/charts-8.3.18.tgz#329db5b50c12cbda2be3609d359a068ad8ac2f47" - integrity sha512-oudif3EUH7Nb9DPm0abAPxpFYDWWjR3k2S5ll0/CcB+pJzlhwaBG19QwpOJaRA6VAvAXDDKOXCO4mi9XCEN78g== +"@mantine/charts@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/charts/-/charts-9.2.1.tgz#64811e07c1094b2b9bc67f04230e5dcebfe76be1" + integrity sha512-AVP0VEfcsbWwLBeU8rbEsN2gz3GebQECTreRq5AJ0Z5V1eWmTO7XFkRP9C5C6oHnkY4Vppa1x8cRYgyTsc/YbQ== -"@mantine/core@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/core/-/core-8.3.18.tgz#25d206caef1110a50671139520b1434b581a62ca" - integrity sha512-9tph1lTVogKPjTx02eUxDUOdXacPzK62UuSqb4TdGliI54/Xgxftq0Dfqu6XuhCxn9J5MDJaNiLDvL/1KRkYqA== +"@mantine/core@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/core/-/core-9.2.1.tgz#6bed4beac0b8c5f385f8923e4f158eb7472b633d" + integrity sha512-CicPg9i2dM2pGp1jj+dMiR/63OFDsPjgJke4v5+0nbfJ+C7gn4C+7ltrp4RIETDMZHcj0fFuDRG0qtbiyBxvWA== dependencies: - "@floating-ui/react" "^0.27.16" + "@floating-ui/react" "^0.27.19" clsx "^2.1.1" - react-number-format "^5.4.4" - react-remove-scroll "^2.7.1" - react-textarea-autosize "8.5.9" - type-fest "^4.41.0" + react-number-format "^5.4.5" + react-remove-scroll "^2.7.2" + type-fest "^5.6.0" -"@mantine/dates@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-8.3.18.tgz#e73b1847c4903eba20b80907162dbf93c99e4956" - integrity sha512-FHx5teJOhupI0gO2o5evtVYQEdqOjayOkLRhEQfB5Nc5DvcysfPfmNILGkc1Nrp9ZQeQWKLT9qr+CkcCXwHOaw== +"@mantine/dates@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-9.2.1.tgz#47c9eb8a854a7f1e6fa3993e9966babb793e9e4a" + integrity sha512-cyRC8bnZ6W+SzQf/RM+/eDeWhZTZF148z+OcgqiERdkAujh0q88Ddybv/Hshv1EOf0rCe6oiHSZWxIxmUf7KAg== dependencies: clsx "^2.1.1" -"@mantine/dropzone@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-8.3.18.tgz#abc9e4b35fc4c18041ba6f6f3b574935a1d6e03f" - integrity sha512-GaYUUl/382R7hl1g6heTCZ5a6T5x6qYPg0oID6ik/J0j7e5+XMZyTH5ITpaqpsBQ09GKKsF5y3iNehpSby8Kew== +"@mantine/dropzone@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-9.2.1.tgz#3003d745da2f08246fc055137d250beb4f743283" + integrity sha512-rgebEz2bUubqA5jQpsh0SZ9/4DJFnUSF+a4p8uzAVlgNfo6aU/r+I4lEsD8gzLKuxrfN0TgkwR1qmAjLWIy0yQ== dependencies: react-dropzone "15.0.0" -"@mantine/form@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/form/-/form-8.3.18.tgz#c0e6ed7f564a69cbb157ed5d9925a5244057029c" - integrity sha512-r5OGLJWTkmIruFjRZRZy9oA7maNYlyt50jB4Pmd2X5360WOmJLd4KH8MFhHZQC7vN+z8/rmBl3t3XGAR2I8xig== +"@mantine/form@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/form/-/form-9.2.1.tgz#f75d82a16d82a1aa3105ff86328a032b6ff712bb" + integrity sha512-PV0dcbmsKhZkn3Ryztqp8Kb1N16v2nWXO71p4utTmN7E/lHWHO1ccj7Y72sIteWJo1YeNHzzkssaYRSnxgOvYA== dependencies: + "@standard-schema/spec" "^1.1.0" fast-deep-equal "^3.1.3" klona "^2.0.6" -"@mantine/hooks@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-8.3.18.tgz#7e5601c0683ed2411e3aee8fcb81a151e5341ad2" - integrity sha512-QoWr9+S8gg5050TQ06aTSxtlpGjYOpIllRbjYYXlRvZeTsUqiTbVfvQROLexu4rEaK+yy9Wwriwl9PMRgbLqPw== +"@mantine/hooks@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-9.2.1.tgz#8f81303b5eab68b10f4b3d7c99795b70932bc2db" + integrity sha512-IX/ztVG9eWmQTRsN7G8odyW4JckNvN8qv5A2ULzXyazjtAKLuaUpuMz0c6XhRp10J0g4bVfV3rhrTgWeImqxqg== -"@mantine/modals@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-8.3.18.tgz#e17a49253944bbb5de4142fd0d15cc944ca63fc2" - integrity sha512-JfPDS4549L314SxFPC1x6CbKwzh82OdnIzwgMxPCVNsWLKV2vEHHUH/fzUYj4Wli6IBrsW4cufjMj9BTj3hm3Q== +"@mantine/modals@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-9.2.1.tgz#257c09088372b38848fb08beeb1124ed3fbe63b3" + integrity sha512-YvZ85ZtMg6arFserkmmP18gJRD9ztLLT3vz8UrkwCdVwTGGr14X93hhS0UtR5X96ANXUzC8fU/S2ncQmNqw+NQ== -"@mantine/notifications@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-8.3.18.tgz#50b9463afab3af0ea3de375dd92cf2fa60aed964" - integrity sha512-IpQ0lmwbigTBbZCR6iSYWqIOKEx1tlcd7PcEJ5M5X1qeVSY/N3mmDQt1eJmObvcyDeL5cTJMbSA9UPqhRqo9jw== +"@mantine/notifications@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-9.2.1.tgz#de99ed4fc64e05024cb5a66e2d619a248ac2e042" + integrity sha512-H6lSsKUPdWPYcXFeOcqqcegUl72Iua9yD369s/gchfDvI+PrL4IM5UuWNHTeABJ1eb9FbTOw8B5RDSMZjTZNSA== dependencies: - "@mantine/store" "8.3.18" + "@mantine/store" "9.2.1" react-transition-group "4.4.5" -"@mantine/spotlight@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/spotlight/-/spotlight-8.3.18.tgz#1747a6afdd2b0aab3cf03c364fbc7b3ea3c4ae4b" - integrity sha512-yFoEYG0wKduxbnv6+1CUOXc91lmQ5DN4QvEShYO2ftDm0kXhxeOvJFtGOBYK80tpmSCsaT253p9E3J3DcaOt2w== +"@mantine/spotlight@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/spotlight/-/spotlight-9.2.1.tgz#4157cef5a9a1b9ac5f6025b57435a8dc484b58b9" + integrity sha512-D6/BJ8/ftUBwiSFGTtYUM/LqlBk40XZqZFlmEFRM8chDPzEId1O+5FU7mj8KapPR9zRgoAcdT4LMI6JaLp0c0A== dependencies: - "@mantine/store" "8.3.18" + "@mantine/store" "9.2.1" -"@mantine/store@8.3.18": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/store/-/store-8.3.18.tgz#fda5e84bb58d4fa4a86cf4e158e166904867caf6" - integrity sha512-i+QRTLmZzLldea0egtUVnGALd6UMIu8jd44nrNWBSNIXJU/8B6rMlC6gyX+l4szopZSuOaaNJIXkqRdC1gQsVg== +"@mantine/store@9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/store/-/store-9.2.1.tgz#27a3548c4cc1567baa2613490d7dcb9300b391ba" + integrity sha512-sBTHt9ilfSZAeXQlqFkm8nRm22RunhevxuOUtdSwS9HhuMuS8T27dRRgbdKH2oEFUbaccdQSy5bHbmGbEgVO8w== -"@mantine/vanilla-extract@^8.2.7": - version "8.3.18" - resolved "https://registry.yarnpkg.com/@mantine/vanilla-extract/-/vanilla-extract-8.3.18.tgz#ba7aaa0fd2ebf547821ef7138a8f12f4149b089d" - integrity sha512-W7YwNJMeYJKsW+m1ntq+D0bt/b2GmGDWdHUxD+REjVlrXPhsKcb7nFX59ot/sgl35ak4yT2SFM1aPkUvgOQMCg== +"@mantine/vanilla-extract@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@mantine/vanilla-extract/-/vanilla-extract-9.2.1.tgz#ba86032eaaf278153d3dd110c8e4327457cc0606" + integrity sha512-5cNesX5kdmClWCMFqxDIVZF2JRCne2OrIj5UE3tuyGJAY3IGkchBnAf/bEx3c5QDSXxq4+6y97hs5gQBgODePA== "@marijn/find-cluster-break@^1.0.0": version "1.0.2" @@ -1799,7 +1799,7 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.10.tgz#beefe675f1853f73676aecc915b2bd2ac98c4fc6" integrity sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA== -"@standard-schema/spec@^1.0.0": +"@standard-schema/spec@^1.0.0", "@standard-schema/spec@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== @@ -3811,15 +3811,15 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -mantine-contextmenu@^8.2.0: - version "8.3.13" - resolved "https://registry.yarnpkg.com/mantine-contextmenu/-/mantine-contextmenu-8.3.13.tgz#f9194d806f29dae76dc5d6c63ab50c1e6b50d038" - integrity sha512-Idbgaou23M18NxCnPfC1A5l6ShS43UbYwJ4u5z6N30HRXXzUPe479/v50H/UfTZQUbBsrl+qnaYjogIvU3boog== +mantine-contextmenu@^9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/mantine-contextmenu/-/mantine-contextmenu-9.2.1.tgz#d1d4dab0ca1eeaba7f1bba6cf2cad8cf31636709" + integrity sha512-oqFPT9qOQBPgf2eSuiujGQp38QgV0WsIIMxQkPfkjVc8FWAKcnXv7OGxGN1ctRrcMqUbsS34rjI0SvNdmFwG8A== -mantine-datatable@^8.2.0: - version "8.3.13" - resolved "https://registry.yarnpkg.com/mantine-datatable/-/mantine-datatable-8.3.13.tgz#7bbb2878a5ead7cb6e61996f0f03335718107d69" - integrity sha512-MQ7FNSyKCPeijiWHSeVmFU38m7MgHkomOm/VXm1XFpCAjVxdK8ZCVHGA2e5GK/dIkPX9Sdiwt812YDOhchPiHQ== +mantine-datatable@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/mantine-datatable/-/mantine-datatable-9.2.0.tgz#936f2307462d5420dc1ba7b520ae825dc6b2d97c" + integrity sha512-TK6SZ6dH/PQUedfhkJuSLMcd4P4m5L6kMJWfAF9cS4wBeoAtBWGpLs+n/E8yI6w1rYAtLsGQvFA6S9Xnfw0JFw== marked@^4.1.0: version "4.3.0" @@ -4367,7 +4367,7 @@ react-is@^19.2.4: resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.4.tgz#a080758243c572ccd4a63386537654298c99d135" integrity sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA== -react-number-format@^5.4.4: +react-number-format@^5.4.5: version "5.4.5" resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.4.5.tgz#5855f2ae4e4153e6231d3a36b635c38be6824c8a" integrity sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw== @@ -4393,7 +4393,7 @@ react-remove-scroll-bar@^2.3.7: react-style-singleton "^2.2.2" tslib "^2.0.0" -react-remove-scroll@^2.7.1: +react-remove-scroll@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz#6442da56791117661978ae99cd29be9026fecca0" integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q== @@ -4457,15 +4457,6 @@ react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: get-nonce "^1.0.0" tslib "^2.0.0" -react-textarea-autosize@8.5.9: - version "8.5.9" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz#ab8627b09aa04d8a2f45d5b5cd94c84d1d4a8893" - integrity sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A== - dependencies: - "@babel/runtime" "^7.20.13" - use-composed-ref "^1.3.0" - use-latest "^1.2.1" - react-transition-group@4.4.5, react-transition-group@^4.3.0: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" @@ -4928,6 +4919,11 @@ tabbable@^6.0.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.4.0.tgz#36eb7a06d80b3924a22095daf45740dea3bf5581" integrity sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg== +tagged-tag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tagged-tag/-/tagged-tag-1.0.0.tgz#a0b5917c2864cba54841495abfa3f6b13edcf4d6" + integrity sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng== + test-exclude@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-8.0.0.tgz#85891add3fa46bb822b1b1579c7f8c9a3d04ebd8" @@ -4991,10 +4987,12 @@ type-fest@^0.8.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^4.41.0: - version "4.41.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" - integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== +type-fest@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.6.0.tgz#502f7a003b7309e96a7e17052cc2ab2c7e5c7a31" + integrity sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA== + dependencies: + tagged-tag "^1.0.0" typedarray-to-buffer@^3.1.5: version "3.1.5" @@ -5066,23 +5064,11 @@ use-callback-ref@^1.3.3: dependencies: tslib "^2.0.0" -use-composed-ref@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.4.0.tgz#09e023bf798d005286ad85cd20674bdf5770653b" - integrity sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w== - -use-isomorphic-layout-effect@^1.1.1, use-isomorphic-layout-effect@^1.2.0: +use-isomorphic-layout-effect@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce" integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA== -use-latest@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.3.0.tgz#549b9b0d4c1761862072f0899c6f096eb379137a" - integrity sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ== - dependencies: - use-isomorphic-layout-effect "^1.1.1" - use-sidecar@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb"