diff --git a/src/frontend/src/tables/ColumnRenderers.tsx b/src/frontend/src/tables/ColumnRenderers.tsx
index 473dd59ba7..c2a157d315 100644
--- a/src/frontend/src/tables/ColumnRenderers.tsx
+++ b/src/frontend/src/tables/ColumnRenderers.tsx
@@ -21,7 +21,7 @@ import { formatCurrency, formatDate } from '../defaults/formatters';
import { resolveItem } from '../functions/conversion';
import { useGlobalSettingsState } from '../states/SettingsStates';
import type { TableColumn, TableColumnProps } from './Column';
-import { ProjectCodeHoverCard } from './TableHoverCard';
+import { ProjectCodeHoverCard, TableHoverCard } from './TableHoverCard';
// Render a Part instance within a table
export function PartColumn({
@@ -81,28 +81,57 @@ export function CompanyColumn({
);
}
-export function LocationColumn(props: TableColumnProps): TableColumn {
+/**
+ * Return a column which displays a tree path for a given record.
+ */
+export function PathColumn(props: TableColumnProps): TableColumn {
return {
+ ...props,
+ accessor: props.accessor ?? 'path',
+ render: (record: any) => {
+ const instance = resolveItem(record, props.accessor ?? '');
+
+ if (!instance || !instance.name) {
+ return '-';
+ }
+
+ const name = instance.name ?? '';
+ const pathstring = instance.pathstring || name;
+
+ if (name == pathstring) {
+ return {name};
+ }
+
+ return (
+ {instance.name}}
+ icon='sitemap'
+ title={props.title}
+ extra={[{instance.pathstring}]}
+ />
+ );
+ }
+ };
+}
+
+export function LocationColumn(props: TableColumnProps): TableColumn {
+ return PathColumn({
accessor: 'location',
title: t`Location`,
sortable: true,
ordering: 'location',
- render: (record: any) => {
- const location = resolveItem(record, props.accessor ?? '');
-
- if (!location) {
- return (
- {t`No location set`}
- );
- }
-
- return {location.pathstring};
- },
...props
- };
+ });
+}
+
+export function CategoryColumn(props: TableColumnProps): TableColumn {
+ return PathColumn({
+ accessor: 'category',
+ title: t`Category`,
+ sortable: true,
+ ordering: 'category',
+ ...props
+ });
}
export function BooleanColumn(props: TableColumn): TableColumn {
diff --git a/src/frontend/src/tables/TableHoverCard.tsx b/src/frontend/src/tables/TableHoverCard.tsx
index 44ef6e822f..31351e29d5 100644
--- a/src/frontend/src/tables/TableHoverCard.tsx
+++ b/src/frontend/src/tables/TableHoverCard.tsx
@@ -1,6 +1,5 @@
import { t } from '@lingui/core/macro';
import { Divider, Group, HoverCard, Stack, Text } from '@mantine/core';
-import { IconInfoCircle } from '@tabler/icons-react';
import { type ReactNode, useMemo } from 'react';
import type { InvenTreeIconType } from '@lib/types/Icons';
@@ -61,7 +60,10 @@ export function TableHoverCard({
-
+
{title}
diff --git a/src/frontend/src/tables/part/PartTable.tsx b/src/frontend/src/tables/part/PartTable.tsx
index f4cebf32d1..d221bb0514 100644
--- a/src/frontend/src/tables/part/PartTable.tsx
+++ b/src/frontend/src/tables/part/PartTable.tsx
@@ -22,7 +22,12 @@ import {
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import type { TableColumn } from '../Column';
-import { DescriptionColumn, LinkColumn, PartColumn } from '../ColumnRenderers';
+import {
+ CategoryColumn,
+ DescriptionColumn,
+ LinkColumn,
+ PartColumn
+} from '../ColumnRenderers';
import { InvenTreeTable, type InvenTreeTableProps } from '../InvenTreeTable';
import { type RowAction, RowEditAction } from '../RowActions';
import { TableHoverCard } from '../TableHoverCard';
@@ -53,11 +58,9 @@ function partTableColumns(): TableColumn[] {
sortable: true
},
DescriptionColumn({}),
- {
- accessor: 'category',
- sortable: true,
- render: (record: any) => record.category_detail?.pathstring
- },
+ CategoryColumn({
+ accessor: 'category_detail'
+ }),
{
accessor: 'default_location',
sortable: true,
diff --git a/src/frontend/src/tables/stock/StockItemTable.tsx b/src/frontend/src/tables/stock/StockItemTable.tsx
index 301f767318..3a5168eef7 100644
--- a/src/frontend/src/tables/stock/StockItemTable.tsx
+++ b/src/frontend/src/tables/stock/StockItemTable.tsx
@@ -32,8 +32,8 @@ import type { TableColumn } from '../Column';
import {
DateColumn,
DescriptionColumn,
- LocationColumn,
PartColumn,
+ PathColumn,
StatusColumn
} from '../ColumnRenderers';
import { StatusFilterOptions } from '../Filter';
@@ -222,9 +222,10 @@ function stockItemTableColumns({
accessor: 'batch',
sortable: true
},
- LocationColumn({
- hidden: !showLocation,
- accessor: 'location_detail'
+ PathColumn({
+ accessor: 'location_detail',
+ title: t`Location`,
+ hidden: !showLocation
}),
{
accessor: 'purchase_order',
diff --git a/src/frontend/tests/pages/pui_build.spec.ts b/src/frontend/tests/pages/pui_build.spec.ts
index 17f7e2a687..b9efd6b433 100644
--- a/src/frontend/tests/pages/pui_build.spec.ts
+++ b/src/frontend/tests/pages/pui_build.spec.ts
@@ -80,7 +80,7 @@ test('Build Order - Basic Tests', async ({ browser }) => {
await page.getByText('Quantity: 25').waitFor();
await page.getByText('Continuity Checks').waitFor();
await page
- .getByRole('row', { name: 'Quantity: 16 No location set' })
+ .getByRole('row', { name: 'Quantity: 16' })
.getByRole('button')
.hover();
await page.getByText('Add Test Result').waitFor();
@@ -241,9 +241,7 @@ test('Build Order - Allocation', async ({ browser }) => {
// Expand this row
await cell.click();
await page.getByRole('cell', { name: '2022-4-27', exact: true }).waitFor();
- await page
- .getByRole('cell', { name: 'Electronics Lab/Reel Storage', exact: true })
- .waitFor();
+ await page.getByRole('cell', { name: 'Reel Storage', exact: true }).waitFor();
// Navigate to the "Incomplete Outputs" tab
await loadTab(page, 'Incomplete Outputs');
diff --git a/src/frontend/tests/pages/pui_part.spec.ts b/src/frontend/tests/pages/pui_part.spec.ts
index 97c32f2825..fa81010734 100644
--- a/src/frontend/tests/pages/pui_part.spec.ts
+++ b/src/frontend/tests/pages/pui_part.spec.ts
@@ -225,9 +225,7 @@ test('Parts - Allocations', async ({ browser }) => {
// Expand allocations against BO0001
await build_order_cell.click();
await page.getByRole('cell', { name: '# 3', exact: true }).waitFor();
- await page
- .getByRole('cell', { name: 'Factory/Office Block/Room 101', exact: true })
- .waitFor();
+ await page.getByRole('cell', { name: 'Room 101', exact: true }).waitFor();
await build_order_cell.click();
// Check row options for BO0001