diff --git a/src/backend/InvenTree/config_template.yaml b/src/backend/InvenTree/config_template.yaml
index fa597167a1..934fa05d69 100644
--- a/src/backend/InvenTree/config_template.yaml
+++ b/src/backend/InvenTree/config_template.yaml
@@ -28,6 +28,10 @@ database:
# Set debug to False to run in production mode, or use the environment variable INVENTREE_DEBUG
debug: True
+# Additional debug options
+debug_querycount: False
+debug_shell: False
+
# Set to False to disable the admin interface, or use the environment variable INVENTREE_ADMIN_ENABLED
#admin_enabled: True
@@ -114,10 +118,10 @@ use_x_forwarded_host: false
# Override with the environment variable INVENTREE_USE_X_FORWARDED_PORT
use_x_forwarded_port: false
-# Cookie settings
-cookie:
- secure: false
- samesite: false
+# Cookie settings (nominally the default settings should be fine)
+#cookie:
+# secure: false
+# samesite: false
# Cross Origin Resource Sharing (CORS) settings (see https://github.com/adamchainz/django-cors-headers)
cors:
diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py
index f9e52c3f9e..2f8845c5ec 100644
--- a/src/backend/InvenTree/part/api.py
+++ b/src/backend/InvenTree/part/api.py
@@ -1886,6 +1886,7 @@ class BomList(BomMixin, DataExportViewMixin, ListCreateDestroyAPIView):
'inherited',
'optional',
'consumable',
+ 'reference',
'validated',
'pricing_min',
'pricing_max',
diff --git a/src/frontend/src/components/modals/AboutInvenTreeModal.tsx b/src/frontend/src/components/modals/AboutInvenTreeModal.tsx
index 8581506fac..dc8e7300fd 100644
--- a/src/frontend/src/components/modals/AboutInvenTreeModal.tsx
+++ b/src/frontend/src/components/modals/AboutInvenTreeModal.tsx
@@ -20,6 +20,7 @@ import { apiUrl, useServerApiState } from '../../states/ApiState';
import { useLocalState } from '../../states/LocalState';
import { useUserState } from '../../states/UserState';
import { CopyButton } from '../buttons/CopyButton';
+import { StylishText } from '../items/StylishText';
type AboutLookupRef = {
ref: string;
@@ -56,9 +57,9 @@ export function AboutInvenTreeModal({
alwaysLink: boolean = false
) {
return lookup.map((map: AboutLookupRef, idx) => (
-
- {map.title}
-
+
+ {map.title}
+
{alwaysLink ? (
@@ -73,8 +74,8 @@ export function AboutInvenTreeModal({
)}
{map.copy && }
-
-
+
+
));
}
/* renderer */
@@ -95,13 +96,10 @@ export function AboutInvenTreeModal({
return (
-
- Version Information
-
-
-
- Your InvenTree version status is
-
+
+
+ Version Information
+
{data.dev ? (
Development Version
@@ -116,8 +114,8 @@ export function AboutInvenTreeModal({
)}
-
-
+
+
{fillTable(
[
{
@@ -144,9 +142,14 @@ export function AboutInvenTreeModal({
{
ref: 'api',
title: API Version ,
- link: `${host}api-doc/`
+ link: `${host}api-doc/`,
+ copy: true
+ },
+ {
+ ref: 'python',
+ title: Python Version ,
+ copy: true
},
- { ref: 'python', title: Python Version },
{
ref: 'django',
title: Django Version ,
@@ -156,17 +159,18 @@ export function AboutInvenTreeModal({
],
data.version
)}
-
+
-
+
+
Links
-
-
-
+
+
+
{fillTable(
[
- { ref: 'doc', title: InvenTree Documentation },
- { ref: 'code', title: View Code on GitHub },
+ { ref: 'doc', title: Documentation },
+ { ref: 'code', title: Source Code },
{ ref: 'credit', title: Credits },
{ ref: 'app', title: Mobile App },
{ ref: 'bug', title: Submit Bug Report }
@@ -174,19 +178,18 @@ export function AboutInvenTreeModal({
data.links,
true
)}
-
+
{
context.closeModal(id);
}}
>
- Dismiss
+ Close
diff --git a/src/frontend/src/components/modals/LicenseModal.tsx b/src/frontend/src/components/modals/LicenseModal.tsx
index f3d85d9588..7a9e8c8527 100644
--- a/src/frontend/src/components/modals/LicenseModal.tsx
+++ b/src/frontend/src/components/modals/LicenseModal.tsx
@@ -11,6 +11,7 @@ import {
Text
} from '@mantine/core';
import { useQuery } from '@tanstack/react-query';
+import { useEffect, useMemo, useState } from 'react';
import { api } from '../../App';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
@@ -53,6 +54,7 @@ export function LicenceView(entries: any[]) {
export function LicenseModal() {
const { data, isFetching, isError } = useQuery({
queryKey: ['license'],
+ refetchOnMount: true,
queryFn: () =>
api
.get(apiUrl(ApiEndpoints.license))
@@ -60,7 +62,17 @@ export function LicenseModal() {
.catch(() => {})
});
- const rspdata = !data ? [] : Object.keys(data ?? {});
+ const packageKeys = useMemo(() => {
+ return !!data ? Object.keys(data ?? {}) : [];
+ }, [data]);
+
+ const [selectedKey, setSelectedKey] = useState('');
+
+ useEffect(() => {
+ if (packageKeys.length > 0) {
+ setSelectedKey(packageKeys[0]);
+ }
+ }, [packageKeys]);
return (
@@ -78,16 +90,20 @@ export function LicenseModal() {
) : (
-
+
- {rspdata.map((key) => (
+ {packageKeys.map((key) => (
{key} Packages
))}
- {rspdata.map((key) => (
+ {packageKeys.map((key) => (
{LicenceView(data[key] ?? [])}
diff --git a/src/frontend/src/components/modals/ServerInfoModal.tsx b/src/frontend/src/components/modals/ServerInfoModal.tsx
index 84dd8cf17c..528c6f2844 100644
--- a/src/frontend/src/components/modals/ServerInfoModal.tsx
+++ b/src/frontend/src/components/modals/ServerInfoModal.tsx
@@ -12,6 +12,7 @@ import { ContextModalProps } from '@mantine/modals';
import { useServerApiState } from '../../states/ApiState';
import { OnlyStaff } from '../items/OnlyStaff';
+import { StylishText } from '../items/StylishText';
export function ServerInfoModal({
context,
@@ -22,10 +23,10 @@ export function ServerInfoModal({
return (
-
+
Server
-
-
+
+
@@ -33,6 +34,18 @@ export function ServerInfoModal({
{server.instance}
+
+
+ Server Version
+
+ {server.version}
+
+
+
+ API Version
+
+ {server.apiVersion}
+
Database
@@ -117,34 +130,14 @@ export function ServerInfoModal({
)}
-
- Version
-
-
-
-
-
- Server Version
-
- {server.version}
-
-
-
- API Version
-
- {server.apiVersion}
-
-
-
{
context.closeModal(id);
}}
>
- Dismiss
+ Close
diff --git a/src/frontend/tests/modals.spec.ts b/src/frontend/tests/modals.spec.ts
index 5977fd20f2..b9809ce538 100644
--- a/src/frontend/tests/modals.spec.ts
+++ b/src/frontend/tests/modals.spec.ts
@@ -12,7 +12,7 @@ test('Modals as admin', async ({ page }) => {
})
.click();
await page.getByRole('cell', { name: 'Instance Name' }).waitFor();
- await page.getByRole('button', { name: 'Dismiss' }).click();
+ await page.getByRole('button', { name: 'Close' }).click();
await page.waitForURL('**/platform/home');
diff --git a/src/frontend/tests/pages/pui_scan.spec.ts b/src/frontend/tests/pages/pui_scan.spec.ts
index 85d2a6c4a5..7459660da5 100644
--- a/src/frontend/tests/pages/pui_scan.spec.ts
+++ b/src/frontend/tests/pages/pui_scan.spec.ts
@@ -24,7 +24,28 @@ async function defaultScanTest(page, search_text) {
await page.getByRole('button', { name: 'Lookup part' }).click();
}
-test('Pages - Index - Scan (Part)', async ({ page }) => {
+test('Scanning', async ({ page }) => {
+ await doQuickLogin(page);
+
+ await page.getByLabel('navigation-menu').click();
+ await page.getByRole('button', { name: 'System Information' }).click();
+ await page.locator('button').filter({ hasText: 'Close' }).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();
+ await page.getByPlaceholder('Enter item serial or data').fill('123');
+ await page.getByPlaceholder('Enter item serial or data').press('Enter');
+ await page.getByRole('cell', { name: 'manually' }).click();
+ await page.getByRole('button', { name: 'Lookup part' }).click();
+ await page.getByPlaceholder('Select input method').click();
+ await page.getByRole('option', { name: 'Manual input' }).click();
+});
+
+test('Scanning (Part)', async ({ page }) => {
await defaultScanTest(page, '{"part": 1}');
// part: 1
@@ -33,7 +54,7 @@ test('Pages - Index - Scan (Part)', async ({ page }) => {
await page.getByRole('cell', { name: 'part' }).waitFor();
});
-test('Pages - Index - Scan (Stockitem)', async ({ page }) => {
+test('Scanning (Stockitem)', async ({ page }) => {
await defaultScanTest(page, '{"stockitem": 408}');
// stockitem: 408
@@ -42,7 +63,7 @@ test('Pages - Index - Scan (Stockitem)', async ({ page }) => {
await page.getByRole('cell', { name: 'Quantity: 100' }).waitFor();
});
-test('Pages - Index - Scan (StockLocation)', async ({ page }) => {
+test('Scanning (StockLocation)', async ({ page }) => {
await defaultScanTest(page, '{"stocklocation": 3}');
// stocklocation: 3
@@ -51,7 +72,7 @@ test('Pages - Index - Scan (StockLocation)', async ({ page }) => {
await page.getByRole('cell', { name: 'stocklocation' }).waitFor();
});
-test('Pages - Index - Scan (SupplierPart)', async ({ page }) => {
+test('Scanning (SupplierPart)', async ({ page }) => {
await defaultScanTest(page, '{"supplierpart": 204}');
// supplierpart: 204
@@ -60,7 +81,7 @@ test('Pages - Index - Scan (SupplierPart)', async ({ page }) => {
await page.getByRole('cell', { name: 'supplierpart' }).waitFor();
});
-test('Pages - Index - Scan (PurchaseOrder)', async ({ page }) => {
+test('Scanning (PurchaseOrder)', async ({ page }) => {
await defaultScanTest(page, '{"purchaseorder": 12}');
// purchaseorder: 12
@@ -69,7 +90,7 @@ test('Pages - Index - Scan (PurchaseOrder)', async ({ page }) => {
await page.getByRole('cell', { name: 'purchaseorder' }).waitFor();
});
-test('Pages - Index - Scan (SalesOrder)', async ({ page }) => {
+test('Scanning (SalesOrder)', async ({ page }) => {
await defaultScanTest(page, '{"salesorder": 6}');
// salesorder: 6
@@ -78,7 +99,7 @@ test('Pages - Index - Scan (SalesOrder)', async ({ page }) => {
await page.getByRole('cell', { name: 'salesorder' }).waitFor();
});
-test('Pages - Index - Scan (Build)', async ({ page }) => {
+test('Scanning (Build)', async ({ page }) => {
await defaultScanTest(page, '{"build": 8}');
// build: 8
@@ -87,7 +108,7 @@ test('Pages - Index - Scan (Build)', async ({ page }) => {
await page.getByRole('cell', { name: 'build', exact: true }).waitFor();
});
-test('Pages - Index - Scan (General)', async ({ page }) => {
+test('Scanning (General)', async ({ page }) => {
await defaultScanTest(page, '{"unknown": 312}');
await page.getByText('"unknown": 312').waitFor();
diff --git a/src/frontend/tests/pui_command.spec.ts b/src/frontend/tests/pui_command.spec.ts
index 8f5d8d15e5..3b53c7bffa 100644
--- a/src/frontend/tests/pui_command.spec.ts
+++ b/src/frontend/tests/pui_command.spec.ts
@@ -53,7 +53,7 @@ test('Quick Command - No Keys', async ({ page }) => {
})
.click();
await page.getByRole('cell', { name: 'Instance Name' }).waitFor();
- await page.getByRole('button', { name: 'Dismiss' }).click();
+ await page.getByRole('button', { name: 'Close' }).click();
await page.waitForURL('**/platform/home');
@@ -66,8 +66,9 @@ test('Quick Command - No Keys', async ({ page }) => {
.click();
await page.getByText('License Information').first().waitFor();
await page.getByRole('tab', { name: 'backend Packages' }).waitFor();
+ await page.getByRole('button', { name: 'Django BSD License' }).click();
- await page.getByLabel('License Information').getByRole('button').click();
+ await page.keyboard.press('Escape');
// use about
await page.getByLabel('open-spotlight').click();
diff --git a/src/frontend/tests/pui_general.spec.ts b/src/frontend/tests/pui_general.spec.ts
index 3709470102..2575e714c7 100644
--- a/src/frontend/tests/pui_general.spec.ts
+++ b/src/frontend/tests/pui_general.spec.ts
@@ -53,27 +53,6 @@ test('Sales', async ({ page }) => {
await page.getByRole('tab', { name: 'Notes' }).click();
});
-test('Scanning', async ({ page }) => {
- await doQuickLogin(page);
-
- await page.getByLabel('navigation-menu').click();
- await page.getByRole('button', { name: 'System Information' }).click();
- await page.locator('button').filter({ hasText: 'Dismiss' }).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();
- await page.getByPlaceholder('Enter item serial or data').fill('123');
- await page.getByPlaceholder('Enter item serial or data').press('Enter');
- await page.getByRole('cell', { name: 'manually' }).click();
- await page.getByRole('button', { name: 'Lookup part' }).click();
- await page.getByPlaceholder('Select input method').click();
- await page.getByRole('option', { name: 'Manual input' }).click();
-});
-
test('Company', async ({ page }) => {
await doQuickLogin(page);
diff --git a/tasks.py b/tasks.py
index b70badcda0..12fd763e65 100644
--- a/tasks.py
+++ b/tasks.py
@@ -1443,14 +1443,14 @@ def docs_server(c, address='localhost:8080', compile_schema=False):
def clear_generated(c):
"""Clear generated files from `invoke update`."""
# pyc/pyo files
- run(c, 'find . -name "*.pyc" -exec rm -f {} +')
- run(c, 'find . -name "*.pyo" -exec rm -f {} +')
+ run(c, 'find src -name "*.pyc" -exec rm -f {} +')
+ run(c, 'find src -name "*.pyo" -exec rm -f {} +')
# cache folders
- run(c, 'find . -name "__pycache__" -exec rm -rf {} +')
+ run(c, 'find src -name "__pycache__" -exec rm -rf {} +')
# Generated translations
- run(c, 'find . -name "django.mo" -exec rm -f {} +')
- run(c, 'find . -name "messages.mo" -exec rm -f {} +')
+ run(c, 'find src -name "django.mo" -exec rm -f {} +')
+ run(c, 'find src -name "messages.mo" -exec rm -f {} +')
# Collection sorting