2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-05-17 23:08:28 +00:00

[UI] Mantine 9 (#11947)

* Update mantine deps

* Get it to compile

* Update QueryCount widgets

- use new RollingNumber component

* Table updates

- Remove "hack" for column ordering

* "Fix" the column pinning bug (maybe?)

* Fix ColumnRenderers.tsx

* Fix login code for playwright

* Remove hashing requirement

* Fix build tests

* More fixes

* More test fixes

* Fix playwright test for dashboard item

* Update frontend version

* Update changelog

* Reduce query repeats

* More playwright fixes

* Further playwright fixes

* Fix for useFilterSet hook

* Fix unique key error

* Fix rendering issues when opening edit forms

* reduce console errors

* Fix unique key issues in search drawer

* Update frontend CHANGELOG.md

* More form tweaks

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
Oliver
2026-05-17 19:26:37 +10:00
committed by GitHub
parent 582013e51c
commit 9f78e994c2
29 changed files with 261 additions and 215 deletions
+4 -1
View File
@@ -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();
+28 -19
View File
@@ -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');
+3 -1
View File
@@ -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
@@ -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' })
@@ -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();
+2 -2
View File
@@ -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();