diff --git a/src/frontend/src/components/nav/PageDetail.tsx b/src/frontend/src/components/nav/PageDetail.tsx
index 77948320d6..d61f4c6586 100644
--- a/src/frontend/src/components/nav/PageDetail.tsx
+++ b/src/frontend/src/components/nav/PageDetail.tsx
@@ -5,6 +5,7 @@ import { Fragment, type ReactNode } from 'react';
import { ApiImage } from '../images/ApiImage';
import { StylishText } from '../items/StylishText';
import { type Breadcrumb, BreadcrumbList } from './BreadcrumbList';
+import PageTitle from './PageTitle';
interface PageDetailInterface {
title?: string;
@@ -51,50 +52,53 @@ export function PageDetail({
]);
return (
-
- {breadcrumbs && breadcrumbs.length > 0 && (
-
- )}
-
-
-
-
- {imageUrl && (
-
- )}
-
- {title && {title}}
- {subtitle && (
-
- {icon}
-
- {subtitle}
-
-
+ <>
+
+
+ {breadcrumbs && breadcrumbs.length > 0 && (
+
+ )}
+
+
+
+
+ {imageUrl && (
+
)}
-
-
-
- {detail}
-
- {badges?.map((badge, idx) => (
- {badge}
- ))}
-
-
- {actions && (
-
- {actions.map((action, idx) => (
- {action}
+
+ {title && {title}}
+ {subtitle && (
+
+ {icon}
+
+ {subtitle}
+
+
+ )}
+
+
+
+ {detail}
+
+ {badges?.map((badge, idx) => (
+ {badge}
))}
- )}
-
-
-
-
+
+ {actions && (
+
+ {actions.map((action, idx) => (
+ {action}
+ ))}
+
+ )}
+
+
+
+
+ >
);
}
diff --git a/src/frontend/src/components/nav/PageTitle.tsx b/src/frontend/src/components/nav/PageTitle.tsx
new file mode 100644
index 0000000000..030a417e92
--- /dev/null
+++ b/src/frontend/src/components/nav/PageTitle.tsx
@@ -0,0 +1,53 @@
+import { useEffect, useMemo } from 'react';
+import { useGlobalSettingsState } from '../../states/SettingsState';
+
+/**
+ * Component to set the page title
+ */
+export default function PageTitle({
+ title,
+ subtitle
+}: {
+ title?: string;
+ subtitle?: string;
+}) {
+ const globalSettings = useGlobalSettingsState();
+
+ const pageTitle = useMemo(() => {
+ const instanceName = globalSettings.getSetting(
+ 'INVENTREE_INSTANCE',
+ 'InvenTree'
+ );
+ const useInstanceName = globalSettings.isSet(
+ 'INVENTREE_INSTANCE_TITLE',
+ false
+ );
+
+ let data = '';
+
+ if (title) {
+ data += title;
+ }
+
+ if (subtitle) {
+ data += ` - ${subtitle}`;
+ }
+
+ if (useInstanceName) {
+ data = `${instanceName} | ${data}`;
+ }
+
+ if (!data) {
+ // Backup: No title provided
+ data = instanceName;
+ }
+
+ return data;
+ }, [title, subtitle, globalSettings]);
+
+ useEffect(() => {
+ document.title = pageTitle;
+ }, [pageTitle]);
+
+ return
{pageTitle};
+}
diff --git a/src/frontend/src/pages/Index/Home.tsx b/src/frontend/src/pages/Index/Home.tsx
index 2c1ff4ba2f..1dd5c4754a 100644
--- a/src/frontend/src/pages/Index/Home.tsx
+++ b/src/frontend/src/pages/Index/Home.tsx
@@ -1,8 +1,11 @@
+import { t } from '@lingui/macro';
import DashboardLayout from '../../components/dashboard/DashboardLayout';
+import PageTitle from '../../components/nav/PageTitle';
export default function Home() {
return (
<>
+
>
);
diff --git a/src/frontend/src/pages/Index/Scan.tsx b/src/frontend/src/pages/Index/Scan.tsx
index 99d15b0ebc..70719e3ca1 100644
--- a/src/frontend/src/pages/Index/Scan.tsx
+++ b/src/frontend/src/pages/Index/Scan.tsx
@@ -47,6 +47,7 @@ import { api } from '../../App';
import { DocInfo } from '../../components/items/DocInfo';
import { StylishText } from '../../components/items/StylishText';
import { TitleWithDoc } from '../../components/items/TitleWithDoc';
+import PageTitle from '../../components/nav/PageTitle';
import { RenderInstance } from '../../components/render/Instance';
import { ModelInformationDict } from '../../components/render/ModelType';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
@@ -290,6 +291,7 @@ export default function Scan() {
// rendering
return (
<>
+
diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
index 1fd1e900f0..2b3fe2a7cc 100644
--- a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
+++ b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
@@ -30,6 +30,7 @@ import { lazy, useMemo } from 'react';
import PermissionDenied from '../../../../components/errors/PermissionDenied';
import { PlaceholderPill } from '../../../../components/items/Placeholder';
+import PageTitle from '../../../../components/nav/PageTitle';
import { SettingsHeader } from '../../../../components/nav/SettingsHeader';
import type { PanelType } from '../../../../components/panels/Panel';
import { PanelGroup } from '../../../../components/panels/PanelGroup';
@@ -244,6 +245,7 @@ export default function AdminCenter() {
return (
<>
+
{user.isStaff() ? (
+
{user.isStaff() ? (
-
-
-
+ <>
+
+
+
+
+
+ >
);
}
diff --git a/src/frontend/src/pages/build/BuildDetail.tsx b/src/frontend/src/pages/build/BuildDetail.tsx
index d307424942..1324fea172 100644
--- a/src/frontend/src/pages/build/BuildDetail.tsx
+++ b/src/frontend/src/pages/build/BuildDetail.tsx
@@ -528,7 +528,7 @@ export default function BuildDetail() {
{
diff --git a/src/frontend/tests/pages/pui_part.spec.ts b/src/frontend/tests/pages/pui_part.spec.ts
index 21affbabab..9ad4f5c6ed 100644
--- a/src/frontend/tests/pages/pui_part.spec.ts
+++ b/src/frontend/tests/pages/pui_part.spec.ts
@@ -100,14 +100,12 @@ test('Parts - Allocations', async ({ page }) => {
await doQuickLogin(page);
// Let's look at the allocations for a single stock item
+ await page.goto(`${baseUrl}/stock/item/324/`);
+ await page.getByRole('tab', { name: 'Allocations' }).click();
- // TODO: Un-comment these lines!
- // await page.goto(`${baseUrl}/stock/item/324/`);
- // await page.getByRole('tab', { name: 'Allocations' }).click();
-
- // await page.getByRole('button', { name: 'Build Order Allocations' }).waitFor();
- // await page.getByRole('cell', { name: 'Making some blue chairs' }).waitFor();
- // await page.getByRole('cell', { name: 'Making tables for SO 0003' }).waitFor();
+ await page.getByRole('button', { name: 'Build Order Allocations' }).waitFor();
+ await page.getByRole('cell', { name: 'Making some blue chairs' }).waitFor();
+ await page.getByRole('cell', { name: 'Making tables for SO 0003' }).waitFor();
// Let's look at the allocations for an entire part
await page.goto(`${baseUrl}/part/74/details`);
@@ -172,7 +170,8 @@ test('Parts - Pricing (Nothing, BOM)', async ({ page }) => {
// Part with no history
await page.goto(`${baseUrl}/part/82/pricing`);
- await page.getByText('1551ABK').waitFor();
+
+ await page.getByText('Small plastic enclosure, black').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
@@ -183,7 +182,7 @@ test('Parts - Pricing (Nothing, BOM)', async ({ page }) => {
// Part with history
await page.goto(`${baseUrl}/part/108/pricing`);
- await page.getByText('Part: Blue Chair').waitFor();
+ await page.getByText('A chair - with blue paint').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
@@ -221,7 +220,7 @@ test('Parts - Pricing (Supplier)', async ({ page }) => {
// Part
await page.goto(`${baseUrl}/part/55/pricing`);
- await page.getByText('Part: C_100nF_0603').waitFor();
+ await page.getByText('Ceramic capacitor, 100nF in').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
@@ -247,7 +246,7 @@ test('Parts - Pricing (Variant)', async ({ page }) => {
// Part
await page.goto(`${baseUrl}/part/106/pricing`);
- await page.getByText('Part: Chair').waitFor();
+ await page.getByText('A chair - available in multiple colors').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
@@ -273,7 +272,7 @@ test('Parts - Pricing (Internal)', async ({ page }) => {
// Part
await page.goto(`${baseUrl}/part/65/pricing`);
- await page.getByText('Part: M2x4 SHCS').waitFor();
+ await page.getByText('Socket head cap screw, M2').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
@@ -298,7 +297,7 @@ test('Parts - Pricing (Purchase)', async ({ page }) => {
// Part
await page.goto(`${baseUrl}/part/69/pricing`);
- await page.getByText('Part: 530470210').waitFor();
+ await page.getByText('1.25mm Pitch, PicoBlade PCB').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
diff --git a/src/frontend/tests/pages/pui_sales_order.spec.ts b/src/frontend/tests/pages/pui_sales_order.spec.ts
index 7a26bab19a..dbe71e1090 100644
--- a/src/frontend/tests/pages/pui_sales_order.spec.ts
+++ b/src/frontend/tests/pages/pui_sales_order.spec.ts
@@ -18,7 +18,7 @@ test('Sales Orders', async ({ page }) => {
await page.getByRole('cell', { name: 'SO0003' }).click();
// Order is "on hold". We will "issue" it and then place on hold again
- await page.getByText('Sales Order: SO0003').waitFor();
+ await page.getByText('Selling stuff').first().waitFor();
await page.getByText('On Hold').first().waitFor();
await page.getByRole('button', { name: 'Issue Order' }).click();
await page.getByRole('button', { name: 'Submit' }).click();
diff --git a/src/frontend/tests/pui_basic.spec.ts b/src/frontend/tests/pui_basic.spec.ts
index e28e76bb18..c1639caa36 100644
--- a/src/frontend/tests/pui_basic.spec.ts
+++ b/src/frontend/tests/pui_basic.spec.ts
@@ -14,7 +14,7 @@ test('Basic Login Test', async ({ page }) => {
await page.goto(baseUrl);
await page.waitForURL('**/platform');
- await page.getByText('InvenTree Demo Server').waitFor();
+ await page.getByText('InvenTree Demo Server -').waitFor();
// Check that the username is provided
await page.getByText(user.username);
@@ -45,7 +45,7 @@ test('Quick Login Test', async ({ page }) => {
await page.goto(baseUrl);
await page.waitForURL('**/platform');
- await page.getByText('InvenTree Demo Server').waitFor();
+ await page.getByText('InvenTree Demo Server - ').waitFor();
// Logout (via URL)
await page.goto(`${baseUrl}/logout/`);
diff --git a/src/frontend/tests/pui_command.spec.ts b/src/frontend/tests/pui_command.spec.ts
index 3b53c7bffa..8e2e2f7a98 100644
--- a/src/frontend/tests/pui_command.spec.ts
+++ b/src/frontend/tests/pui_command.spec.ts
@@ -22,7 +22,7 @@ test('Quick Command - No Keys', async ({ page }) => {
.getByRole('button', { name: 'Dashboard Go to the InvenTree' })
.click();
- await page.getByText('InvenTree Demo Server').waitFor();
+ await page.getByText('InvenTree Demo Server - ').waitFor();
await page.waitForURL('**/platform/home');
// Use navigation menu
diff --git a/src/frontend/tests/pui_forms.spec.ts b/src/frontend/tests/pui_forms.spec.ts
index 222b19ef4d..68d29df3ef 100644
--- a/src/frontend/tests/pui_forms.spec.ts
+++ b/src/frontend/tests/pui_forms.spec.ts
@@ -107,7 +107,7 @@ test('Forms - Supplier Validation', async ({ page, request }) => {
await page.getByLabel('text-field-name').fill(supplierName);
await page.getByRole('button', { name: 'Submit' }).click();
- await page.getByText(supplierName).waitFor();
+ await page.getByText('A description').first().waitFor();
await page
.getByRole('link', { name: 'https://www.test-website.co.uk' })
.waitFor();