mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	[PUI] Dashboard refactor (#8278)
* Refactor plugin components into <RemoteComponent /> * Clean up footer * Allow BuildOrder list to be sorted by 'outstanding' * Fix model name * Update BuildOrderTable filter * Add StockItemTable column * Working towards new dashboard * Cleanup unused imports * Updates: Now rendering some custom widgets * Define icons for model types * Add icon * Cleanup / refactor / delete - Complete transfer of files into new structure * Follow link for query count widgets * Add some more widgets to the library * Remove old dashboard link in header * Remove feedback widget * Bump API version * Remove test widget * Rename "Home" -> "Dashboard" * Add some more widgets * Pass 'editable' property through to widgets * Cleanup * Add drawer for selecting new widgets * Allow different layouts per user on the same machine * Fixes * Add ability to *remove* widgets * Add helpful button * Add a keyboard shortcut * Refactoring * Add backend code for serving custom dashboard items * Load dashboard items from plugins * Tweak for dashboard item API query - Refetch if user changes - Tweak "loaded" value - Prevent refetchOnMount * Add message if no dashboard widgets are displayed * Refactoring main navigation menu - Group into sections - Cleanup / consolidation - General refactoring * Remove playground * Add backend field for storing dashboard layout * Add extra type definitions for UseInstance * Manual labels for builtin dashboard items - Otherwise they will change with translation locale * Shorten labels for more plugins * Adjust DashboardMenu * Reduce stored data * Add widget filter by text * Remove back-end settings * Update playwright tests for dashboard * Updated tests * Refactor backend API for fetching plugin features * Further fixes for back-end code * More back-end fixes * Refactor frontend: - Custom panels - Custom dashboard items * Further backend fixes * Yet more backend fixes - Improve error handling * Fix for custom plugin settings rendering * Enable plugin panels for part index and stock index pages * Cleanup * Fix nav menu * Update typing * Helper func to return all plugin settings as a dict * Update API version date * Fix for UseInstancea * typing fix * Tweak layout callbacks * Pass query parameters through to navigation functions * Improve custom query display * Add "news" widget * Ensure links are prepended with base URL on receipt * Update NewsWidget * Bug fix * Refactor template editor tests * Refactor unit testing for test_ui_panels * Unit test for dashboard item API endpoint * Update comment * Adjust playwright tests * More playwright fixes * Hide barcode scanning options if disabled * Tweak dashboard widget * Fix custom panel title * Update documentation around UIMixin class * Cleanup * Additional docs * Add icon def for 'error' ModelType * Add error boundary to TemplateEditor component * Fix so that it works with template editors and previews again * Tweak error messages * API unit test fixes * Unit test fix * More unit test fixes * Playwright test tweaks * Adjust error messages
This commit is contained in:
		| @@ -33,9 +33,8 @@ export const doQuickLogin = async ( | ||||
|  | ||||
|   await page.goto(`${url}/login/?login=${username}&password=${password}`); | ||||
|   await page.waitForURL('**/platform/home'); | ||||
|   await page | ||||
|     .getByRole('heading', { name: 'Welcome to your Dashboard,' }) | ||||
|     .waitFor(); | ||||
|  | ||||
|   await page.getByText(/InvenTree Demo Server/).waitFor(); | ||||
| }; | ||||
|  | ||||
| export const doLogout = async (page) => { | ||||
|   | ||||
| @@ -52,12 +52,12 @@ test('Modals as admin', async ({ page }) => { | ||||
|  | ||||
|   await page.goto('./platform/'); | ||||
|  | ||||
|   // qr code modal | ||||
|   await page.getByRole('button', { name: 'Open QR code scanner' }).click(); | ||||
|   // Barcode scanning window | ||||
|   await page.getByRole('button', { name: 'Open Barcode Scanner' }).click(); | ||||
|   await page.getByRole('banner').getByRole('button').click(); | ||||
|   await page.getByRole('button', { name: 'Open QR code scanner' }).click(); | ||||
|   await page.getByRole('button', { name: 'Open Barcode Scanner' }).click(); | ||||
|   await page.getByRole('button', { name: 'Close modal' }).click(); | ||||
|   await page.getByRole('button', { name: 'Open QR code scanner' }).click(); | ||||
|   await page.getByRole('button', { name: 'Open Barcode Scanner' }).click(); | ||||
|   await page.waitForTimeout(500); | ||||
|   await page.getByRole('banner').getByRole('button').click(); | ||||
| }); | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/frontend/tests/pages/pui_dashboard.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/frontend/tests/pages/pui_dashboard.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| import { test } from '../baseFixtures.js'; | ||||
| import { doQuickLogin } from '../login.js'; | ||||
| import { setPluginState } from '../settings.js'; | ||||
|  | ||||
| test('Pages - Dashboard - Basic', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.getByText('Use the menu to add widgets').waitFor(); | ||||
|  | ||||
|   // Let's add some widgets | ||||
|   await page.getByLabel('dashboard-menu').click(); | ||||
|   await page.getByRole('menuitem', { name: 'Add Widget' }).click(); | ||||
|   await page.getByLabel('dashboard-widgets-filter-input').fill('overdue order'); | ||||
|  | ||||
|   await page.getByLabel('add-widget-ovr-so').click(); | ||||
|   await page.getByLabel('add-widget-ovr-po').click(); | ||||
|  | ||||
|   await page.getByLabel('dashboard-widgets-filter-clear').click(); | ||||
|  | ||||
|   // Close the widget | ||||
|   await page.getByRole('banner').getByRole('button').click(); | ||||
|  | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   // Check that the widgets are visible | ||||
|   await page.getByText('Overdue Sales Orders').waitFor(); | ||||
|   await page.getByText('Overdue Purchase Orders').waitFor(); | ||||
|  | ||||
|   // Let's remove one of the widgets | ||||
|   await page.getByLabel('dashboard-menu').click(); | ||||
|   await page.getByRole('menuitem', { name: 'Remove Widgets' }).click(); | ||||
|   await page.getByLabel('remove-dashboard-item-ovr-so').click(); | ||||
|  | ||||
|   // Accept the layout | ||||
|   await page.getByLabel('dashboard-accept-layout').click(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Dashboard - Plugins', async ({ page, request }) => { | ||||
|   // Ensure that the "SampleUI" plugin is enabled | ||||
|   await setPluginState({ | ||||
|     request, | ||||
|     plugin: 'sampleui', | ||||
|     state: true | ||||
|   }); | ||||
|  | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Add a dashboard widget from the SampleUI plugin | ||||
|   await page.getByLabel('dashboard-menu').click(); | ||||
|   await page.getByRole('menuitem', { name: 'Add Widget' }).click(); | ||||
|   await page.getByLabel('dashboard-widgets-filter-input').fill('sample'); | ||||
|  | ||||
|   // Add the widget | ||||
|   await page.getByLabel(/add-widget-p-sampleui-sample-/).click(); | ||||
|  | ||||
|   // Close the widget | ||||
|   await page.getByRole('banner').getByRole('button').click(); | ||||
|  | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   // Check that the widget is visible | ||||
|   await page.getByRole('heading', { name: 'Sample Dashboard Item' }).waitFor(); | ||||
|   await page.getByText('Hello world! This is a sample').waitFor(); | ||||
| }); | ||||
| @@ -1,13 +0,0 @@ | ||||
| import { test } from '../baseFixtures.js'; | ||||
| import { doQuickLogin } from '../login.js'; | ||||
|  | ||||
| test('Pages - Index - Dashboard', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Dashboard auto update | ||||
|   await page.getByRole('tab', { name: 'Dashboard' }).click(); | ||||
|   await page.getByText('Autoupdate').click(); | ||||
|   await page.waitForTimeout(500); | ||||
|   await page.getByText('Autoupdate').click(); | ||||
|   await page.getByText('This page is a replacement').waitFor(); | ||||
| }); | ||||
| @@ -2,7 +2,76 @@ import { test } from '../baseFixtures'; | ||||
| import { baseUrl } from '../defaults'; | ||||
| import { doQuickLogin } from '../login'; | ||||
|  | ||||
| test('Pages - Part - Locking', async ({ page }) => { | ||||
| /** | ||||
|  * CHeck each panel tab for the "Parts" page | ||||
|  */ | ||||
| test('Parts - Tabs', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/home`); | ||||
|   await page.getByRole('tab', { name: 'Parts' }).click(); | ||||
|  | ||||
|   await page.waitForURL('**/platform/part/category/index/details'); | ||||
|   await page.goto(`${baseUrl}/part/category/index/parts`); | ||||
|   await page.getByText('1551ABK').click(); | ||||
|   await page.getByRole('tab', { name: 'Allocations' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Used In' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Manufacturers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Purchase Orders' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Scheduling' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Stock History' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Attachments' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Notes' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Related Parts' }).click(); | ||||
|  | ||||
|   // Related Parts | ||||
|   await page.getByText('1551ACLR').click(); | ||||
|   await page.getByRole('tab', { name: 'Part Details' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Parameters' }).click(); | ||||
|   await page | ||||
|     .getByRole('tab', { name: 'Part Details' }) | ||||
|     .locator('xpath=..') | ||||
|     .getByRole('tab', { name: 'Stock', exact: true }) | ||||
|     .click(); | ||||
|   await page.getByRole('tab', { name: 'Allocations' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Used In' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/category/index/parts`); | ||||
|   await page.getByText('Blue Chair').click(); | ||||
|   await page.getByRole('tab', { name: 'Bill of Materials' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Build Orders' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Parts - Manufacturer Parts', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/84/manufacturers`); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Manufacturers' }).click(); | ||||
|   await page.getByText('Hammond Manufacturing').click(); | ||||
|   await page.getByRole('tab', { name: 'Parameters' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Attachments' }).click(); | ||||
|   await page.getByText('1551ACLR - 1551ACLR').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Parts - Supplier Parts', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/15/suppliers`); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('cell', { name: 'DIG-84670-SJI' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Received Stock' }).click(); // | ||||
|   await page.getByRole('tab', { name: 'Purchase Orders' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|   await page.getByText('DIG-84670-SJI - R_550R_0805_1%').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Parts - Locking', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Navigate to a known assembly which is *not* locked | ||||
| @@ -28,7 +97,7 @@ test('Pages - Part - Locking', async ({ page }) => { | ||||
|   await page.getByText('Part parameters cannot be').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Allocations', async ({ page }) => { | ||||
| test('Parts - Allocations', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Let's look at the allocations for a single stock item | ||||
| @@ -57,7 +126,7 @@ test('Pages - Part - Allocations', async ({ page }) => { | ||||
|   await page.getByRole('tab', { name: 'Build Details' }).waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Pricing (Nothing, BOM)', async ({ page }) => { | ||||
| test('Parts - Pricing (Nothing, BOM)', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Part with no history | ||||
| @@ -106,7 +175,7 @@ test('Pages - Part - Pricing (Nothing, BOM)', async ({ page }) => { | ||||
|   await page.waitForURL('**/part/98/**'); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Pricing (Supplier)', async ({ page }) => { | ||||
| test('Parts - Pricing (Supplier)', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Part | ||||
| @@ -132,7 +201,7 @@ test('Pages - Part - Pricing (Supplier)', async ({ page }) => { | ||||
|   // await page.waitForURL('**/purchasing/supplier-part/697/'); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Pricing (Variant)', async ({ page }) => { | ||||
| test('Parts - Pricing (Variant)', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Part | ||||
| @@ -158,7 +227,7 @@ test('Pages - Part - Pricing (Variant)', async ({ page }) => { | ||||
|   await page.waitForURL('**/part/109/**'); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Pricing (Internal)', async ({ page }) => { | ||||
| test('Parts - Pricing (Internal)', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Part | ||||
| @@ -183,7 +252,7 @@ test('Pages - Part - Pricing (Internal)', async ({ page }) => { | ||||
|   await page.getByText('Part *M2x4 SHCSSocket head').click(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Pricing (Purchase)', async ({ page }) => { | ||||
| test('Parts - Pricing (Purchase)', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Part | ||||
| @@ -205,7 +274,7 @@ test('Pages - Part - Pricing (Purchase)', async ({ page }) => { | ||||
|   await page.getByText('2022-04-29').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Attachments', async ({ page }) => { | ||||
| test('Parts - Attachments', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/69/attachments`); | ||||
| @@ -227,7 +296,7 @@ test('Pages - Part - Attachments', async ({ page }) => { | ||||
|   await page.getByRole('button', { name: 'Cancel' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Parameters', async ({ page }) => { | ||||
| test('Parts - Parameters', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/69/parameters`); | ||||
| @@ -254,7 +323,7 @@ test('Pages - Part - Parameters', async ({ page }) => { | ||||
|   await page.getByRole('button', { name: 'Cancel' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Notes', async ({ page }) => { | ||||
| test('Parts - Notes', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/69/notes`); | ||||
| @@ -276,7 +345,7 @@ test('Pages - Part - Notes', async ({ page }) => { | ||||
|   await page.getByLabel('Close Editor').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - 404', async ({ page }) => { | ||||
| test('Parts - 404', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/99999/`); | ||||
| @@ -286,7 +355,7 @@ test('Pages - Part - 404', async ({ page }) => { | ||||
|   await page.evaluate(() => console.clear()); | ||||
| }); | ||||
|  | ||||
| test('Pages - Part - Revision', async ({ page }) => { | ||||
| test('Parts - Revision', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/906/details`); | ||||
|   | ||||
| @@ -14,9 +14,7 @@ test('Basic Login Test', async ({ page }) => { | ||||
|   await page.goto(baseUrl); | ||||
|   await page.waitForURL('**/platform'); | ||||
|  | ||||
|   await page | ||||
|     .getByRole('heading', { name: `Welcome to your Dashboard, ${user.name}` }) | ||||
|     .click(); | ||||
|   await page.getByText('InvenTree Demo Server').waitFor(); | ||||
|  | ||||
|   // Check that the username is provided | ||||
|   await page.getByText(user.username); | ||||
| @@ -47,9 +45,7 @@ test('Quick Login Test', async ({ page }) => { | ||||
|   await page.goto(baseUrl); | ||||
|   await page.waitForURL('**/platform'); | ||||
|  | ||||
|   await page | ||||
|     .getByRole('heading', { name: `Welcome to your Dashboard, ${user.name}` }) | ||||
|     .click(); | ||||
|   await page.getByText('InvenTree Demo Server').waitFor(); | ||||
|  | ||||
|   // Logout (via URL) | ||||
|   await page.goto(`${baseUrl}/logout/`); | ||||
|   | ||||
| @@ -1,34 +1,16 @@ | ||||
| import { systemKey, test } from './baseFixtures.js'; | ||||
| import { baseUrl } from './defaults.js'; | ||||
| import { doQuickLogin } from './login.js'; | ||||
|  | ||||
| test('Quick Command', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   // Open Spotlight with Keyboard Shortcut | ||||
|   await page.locator('body').press(`${systemKey}+k`); | ||||
|   await page.waitForTimeout(200); | ||||
|   await page | ||||
|     .getByRole('button', { name: 'Go to the InvenTree dashboard' }) | ||||
|     .click(); | ||||
|   await page.locator('p').filter({ hasText: 'Dashboard' }).waitFor(); | ||||
|   await page.waitForURL('**/platform/dashboard'); | ||||
|  | ||||
|   // Open Spotlight with Button | ||||
|   await page.getByLabel('open-spotlight').click(); | ||||
|   await page.getByRole('button', { name: 'Home Go to the home page' }).click(); | ||||
|   await page | ||||
|     .getByRole('heading', { name: 'Welcome to your Dashboard,' }) | ||||
|     .click(); | ||||
|   await page.waitForURL('**/platform'); | ||||
|  | ||||
|   // Open Spotlight with Keyboard Shortcut and Search | ||||
|   await page.locator('body').press(`${systemKey}+k`); | ||||
|   await page.waitForTimeout(200); | ||||
|   await page.getByPlaceholder('Search...').fill('Dashboard'); | ||||
|   await page.getByPlaceholder('Search...').press('Tab'); | ||||
|   await page.getByPlaceholder('Search...').press('Enter'); | ||||
|   await page.waitForURL('**/platform/dashboard'); | ||||
|   await page.waitForURL('**/platform/home'); | ||||
| }); | ||||
|  | ||||
| test('Quick Command - No Keys', async ({ page }) => { | ||||
| @@ -36,23 +18,31 @@ test('Quick Command - No Keys', async ({ page }) => { | ||||
|  | ||||
|   // Open Spotlight with Button | ||||
|   await page.getByLabel('open-spotlight').click(); | ||||
|   await page.getByRole('button', { name: 'Home Go to the home page' }).click(); | ||||
|   await page | ||||
|     .getByRole('heading', { name: 'Welcome to your Dashboard,' }) | ||||
|     .getByRole('button', { name: 'Dashboard Go to the InvenTree' }) | ||||
|     .click(); | ||||
|   await page.waitForURL('**/platform'); | ||||
|  | ||||
|   await page.getByText('InvenTree Demo Server').waitFor(); | ||||
|   await page.waitForURL('**/platform/home'); | ||||
|  | ||||
|   // Use navigation menu | ||||
|   await page.getByLabel('open-spotlight').click(); | ||||
|   await page | ||||
|     .getByRole('button', { name: 'Open Navigation Open the main' }) | ||||
|     .click(); | ||||
|   // assert the nav headers are visible | ||||
|   await page.getByRole('heading', { name: 'Navigation' }).waitFor(); | ||||
|   await page.getByRole('heading', { name: 'Pages' }).waitFor(); | ||||
|   await page.getByRole('heading', { name: 'Documentation' }).waitFor(); | ||||
|   await page.getByRole('heading', { name: 'About' }).waitFor(); | ||||
|  | ||||
|   await page.waitForTimeout(1000); | ||||
|  | ||||
|   // assert the nav headers are visible | ||||
|   await page.getByText('Navigation').waitFor(); | ||||
|   await page.getByText('Documentation').waitFor(); | ||||
|   await page.getByText('About').first().waitFor(); | ||||
|   await page | ||||
|     .getByRole('button', { name: 'Notifications', exact: true }) | ||||
|     .waitFor(); | ||||
|   await page.getByRole('button', { name: 'Dashboard', exact: true }).waitFor(); | ||||
|  | ||||
|   // close the nav | ||||
|   await page.keyboard.press('Escape'); | ||||
|  | ||||
|   // use server info | ||||
| @@ -65,7 +55,7 @@ test('Quick Command - No Keys', async ({ page }) => { | ||||
|   await page.getByRole('cell', { name: 'Instance Name' }).waitFor(); | ||||
|   await page.getByRole('button', { name: 'Dismiss' }).click(); | ||||
|  | ||||
|   await page.waitForURL('**/platform'); | ||||
|   await page.waitForURL('**/platform/home'); | ||||
|  | ||||
|   // use license info | ||||
|   await page.getByLabel('open-spotlight').click(); | ||||
|   | ||||
| @@ -2,72 +2,6 @@ import { test } from './baseFixtures.js'; | ||||
| import { baseUrl } from './defaults.js'; | ||||
| import { doQuickLogin } from './login.js'; | ||||
|  | ||||
| test('Parts', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/home`); | ||||
|   await page.getByRole('tab', { name: 'Parts' }).click(); | ||||
|  | ||||
|   await page.waitForURL('**/platform/part/category/index/details'); | ||||
|   await page.goto(`${baseUrl}/part/category/index/parts`); | ||||
|   await page.getByText('1551ABK').click(); | ||||
|   await page.getByRole('tab', { name: 'Allocations' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Used In' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Manufacturers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Purchase Orders' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Scheduling' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Stock History' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Attachments' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Notes' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Related Parts' }).click(); | ||||
|  | ||||
|   // Related Parts | ||||
|   await page.getByText('1551ACLR').click(); | ||||
|   await page.getByRole('tab', { name: 'Part Details' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Parameters' }).click(); | ||||
|   await page | ||||
|     .getByRole('tab', { name: 'Part Details' }) | ||||
|     .locator('xpath=..') | ||||
|     .getByRole('tab', { name: 'Stock', exact: true }) | ||||
|     .click(); | ||||
|   await page.getByRole('tab', { name: 'Allocations' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Used In' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/category/index/parts`); | ||||
|   await page.getByText('Blue Chair').click(); | ||||
|   await page.getByRole('tab', { name: 'Bill of Materials' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Build Orders' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Parts - Manufacturer Parts', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/84/manufacturers`); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Manufacturers' }).click(); | ||||
|   await page.getByText('Hammond Manufacturing').click(); | ||||
|   await page.getByRole('tab', { name: 'Parameters' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Attachments' }).click(); | ||||
|   await page.getByText('1551ACLR - 1551ACLR').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Parts - Supplier Parts', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.goto(`${baseUrl}/part/15/suppliers`); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Suppliers' }).click(); | ||||
|   await page.getByRole('cell', { name: 'DIG-84670-SJI' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Received Stock' }).click(); // | ||||
|   await page.getByRole('tab', { name: 'Purchase Orders' }).click(); | ||||
|   await page.getByRole('tab', { name: 'Pricing' }).click(); | ||||
|   await page.getByText('DIG-84670-SJI - R_550R_0805_1%').waitFor(); | ||||
| }); | ||||
|  | ||||
| test('Sales', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
| @@ -122,13 +56,13 @@ test('Sales', async ({ page }) => { | ||||
| test('Scanning', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.getByLabel('Homenav').click(); | ||||
|   await page.getByLabel('navigation-menu').click(); | ||||
|   await page.getByRole('button', { name: 'System Information' }).click(); | ||||
|   await page.locator('button').filter({ hasText: 'Dismiss' }).click(); | ||||
|   await page.getByRole('link', { name: 'Scanning' }).click(); | ||||
|   await page.waitForTimeout(200); | ||||
|  | ||||
|   await page.locator('.mantine-Overlay-root').click(); | ||||
|   await page.getByLabel('navigation-menu').click(); | ||||
|   await page.getByRole('button', { name: 'Scan Barcode' }).click(); | ||||
|  | ||||
|   await page.getByPlaceholder('Select input method').click(); | ||||
|   await page.getByRole('option', { name: 'Manual input' }).click(); | ||||
|   await page.getByPlaceholder('Enter item serial or data').click(); | ||||
| @@ -140,40 +74,6 @@ test('Scanning', async ({ page }) => { | ||||
|   await page.getByRole('option', { name: 'Manual input' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Language / Color', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Ally Access' }).click(); | ||||
|   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').first().click(); | ||||
|   await page.getByRole('option', { name: 'German' }).click(); | ||||
|   await page.waitForTimeout(200); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Benutzername und Passwort' }).click(); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').click(); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').fill('admin'); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').press('Tab'); | ||||
|   await page.getByPlaceholder('Dein Passwort').fill('inventree'); | ||||
|   await page.getByRole('button', { name: 'Anmelden' }).click(); | ||||
|   await page.waitForTimeout(200); | ||||
|  | ||||
|   await page | ||||
|     .locator('span') | ||||
|     .filter({ hasText: 'AnzeigeneinstellungenFarbmodusSprache' }) | ||||
|     .getByRole('button') | ||||
|     .click(); | ||||
|   await page | ||||
|     .locator('span') | ||||
|     .filter({ hasText: 'AnzeigeneinstellungenFarbmodusSprache' }) | ||||
|     .getByRole('button') | ||||
|     .click(); | ||||
|   await page.getByRole('button', { name: "InvenTree's Logo" }).first().click(); | ||||
|   await page.getByRole('tab', { name: 'Dashboard' }).click(); | ||||
|   await page.waitForURL('**/platform/dashboard'); | ||||
| }); | ||||
|  | ||||
| test('Company', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   | ||||
| @@ -14,6 +14,8 @@ test('Plugins - Panels', async ({ page, request }) => { | ||||
|     value: true | ||||
|   }); | ||||
|  | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   // Ensure that the SampleUI plugin is enabled | ||||
|   await setPluginState({ | ||||
|     request, | ||||
| @@ -21,28 +23,34 @@ test('Plugins - Panels', async ({ page, request }) => { | ||||
|     state: true | ||||
|   }); | ||||
|  | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   // Navigate to the "part" page | ||||
|   await page.goto(`${baseUrl}/part/69/`); | ||||
|  | ||||
|   // Ensure basic part tab is available | ||||
|   await page.getByRole('tab', { name: 'Part Details' }).waitFor(); | ||||
|  | ||||
|   // Allow time for the plugin panels to load (they are loaded asynchronously) | ||||
|   await page.waitForTimeout(1000); | ||||
|  | ||||
|   // Check out each of the plugin panels | ||||
|   await page.getByRole('tab', { name: 'Sample Panel' }).click(); | ||||
|   await page | ||||
|     .getByText('This is a sample panel which appears on every page') | ||||
|     .waitFor(); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Broken Panel' }).click(); | ||||
|   await page.getByText('Error Loading Plugin').waitFor(); | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Dynamic Part Panel' }).click(); | ||||
|   await page.getByText('Error occurred while loading plugin content').waitFor(); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Dynamic Panel' }).click(); | ||||
|   await page.waitForTimeout(500); | ||||
|  | ||||
|   await page.getByText('Instance ID: 69'); | ||||
|   await page | ||||
|     .getByText('This panel has been dynamically rendered by the plugin system') | ||||
|     .waitFor(); | ||||
|   await page.getByText('Instance ID: 69'); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Part Panel', exact: true }).click(); | ||||
|   await page.waitForTimeout(500); | ||||
|   await page.getByText('This content has been rendered by a custom plugin'); | ||||
|  | ||||
|   // Disable the plugin, and ensure it is no longer visible | ||||
|   | ||||
| @@ -3,7 +3,45 @@ import { apiUrl, baseUrl } from './defaults.js'; | ||||
| import { doQuickLogin } from './login.js'; | ||||
| import { setSettingState } from './settings.js'; | ||||
|  | ||||
| test('Admin', async ({ page }) => { | ||||
| /** | ||||
|  * Adjust language and color settings | ||||
|  */ | ||||
| test('Settings - Language / Color', async ({ page }) => { | ||||
|   await doQuickLogin(page); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Ally Access' }).click(); | ||||
|   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').first().click(); | ||||
|   await page.getByRole('option', { name: 'German' }).click(); | ||||
|   await page.waitForTimeout(200); | ||||
|  | ||||
|   await page.getByRole('button', { name: 'Benutzername und Passwort' }).click(); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').click(); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').fill('admin'); | ||||
|   await page.getByPlaceholder('Ihr Benutzername').press('Tab'); | ||||
|   await page.getByPlaceholder('Dein Passwort').fill('inventree'); | ||||
|   await page.getByRole('button', { name: 'Anmelden' }).click(); | ||||
|   await page.waitForTimeout(200); | ||||
|  | ||||
|   // Note: changes to the dashboard have invalidated these tests (for now) | ||||
|   // await page | ||||
|   //   .locator('span') | ||||
|   //   .filter({ hasText: 'AnzeigeneinstellungenFarbmodusSprache' }) | ||||
|   //   .getByRole('button') | ||||
|   //   .click(); | ||||
|   // await page | ||||
|   //   .locator('span') | ||||
|   //   .filter({ hasText: 'AnzeigeneinstellungenFarbmodusSprache' }) | ||||
|   //   .getByRole('button') | ||||
|   //   .click(); | ||||
|  | ||||
|   await page.getByRole('tab', { name: 'Dashboard' }).click(); | ||||
|   await page.waitForURL('**/platform/home'); | ||||
| }); | ||||
|  | ||||
| test('Settings - Admin', async ({ page }) => { | ||||
|   // Note here we login with admin access | ||||
|   await doQuickLogin(page, 'admin', 'inventree'); | ||||
|  | ||||
| @@ -86,7 +124,7 @@ test('Admin', async ({ page }) => { | ||||
|   await page.getByRole('button', { name: 'Submit' }).click(); | ||||
| }); | ||||
|  | ||||
| test('Admin - Barcode History', async ({ page, request }) => { | ||||
| test('Settings - Admin - Barcode History', async ({ page, request }) => { | ||||
|   // Login with admin credentials | ||||
|   await doQuickLogin(page, 'admin', 'inventree'); | ||||
|  | ||||
| @@ -123,7 +161,7 @@ test('Admin - Barcode History', async ({ page, request }) => { | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| test('Admin - Unauthorized', async ({ page }) => { | ||||
| test('Settings - Admin - Unauthorized', async ({ page }) => { | ||||
|   // Try to access "admin" page with a non-staff user | ||||
|   await doQuickLogin(page, 'allaccess', 'nolimits'); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user