2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-03 15:52:51 +00:00

[UI] Part test result table (#10368)

* Add generic test result table for part

* Adjust table identifier

* Additional table filters

* Update permissions

* Consolidate naming

* Tweak playwright tests
This commit is contained in:
Oliver
2025-09-21 12:34:14 +10:00
committed by GitHub
parent 2f357587bc
commit a18771bcba
7 changed files with 69 additions and 14 deletions

View File

@@ -59,8 +59,8 @@ import { useUserState } from '../../states/UserState';
import BuildAllocatedStockTable from '../../tables/build/BuildAllocatedStockTable'; import BuildAllocatedStockTable from '../../tables/build/BuildAllocatedStockTable';
import BuildLineTable from '../../tables/build/BuildLineTable'; import BuildLineTable from '../../tables/build/BuildLineTable';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable'; import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
import BuildOrderTestTable from '../../tables/build/BuildOrderTestTable';
import BuildOutputTable from '../../tables/build/BuildOutputTable'; import BuildOutputTable from '../../tables/build/BuildOutputTable';
import PartTestResultTable from '../../tables/part/PartTestResultTable';
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable'; import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
import { StockItemTable } from '../../tables/stock/StockItemTable'; import { StockItemTable } from '../../tables/stock/StockItemTable';
@@ -525,7 +525,7 @@ export default function BuildDetail() {
icon: <IconChecklist />, icon: <IconChecklist />,
hidden: !build.part_detail?.testable, hidden: !build.part_detail?.testable,
content: build.pk ? ( content: build.pk ? (
<BuildOrderTestTable buildId={build.pk} partId={build.part} /> <PartTestResultTable buildId={build.pk} partId={build.part} />
) : ( ) : (
<Skeleton /> <Skeleton />
) )

View File

@@ -15,6 +15,7 @@ import {
import { import {
IconBookmarks, IconBookmarks,
IconBuilding, IconBuilding,
IconChecklist,
IconCircleCheck, IconCircleCheck,
IconClipboardList, IconClipboardList,
IconCurrencyDollar, IconCurrencyDollar,
@@ -101,6 +102,7 @@ import { UsedInTable } from '../../tables/bom/UsedInTable';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable'; import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
import { PartParameterTable } from '../../tables/part/PartParameterTable'; import { PartParameterTable } from '../../tables/part/PartParameterTable';
import PartPurchaseOrdersTable from '../../tables/part/PartPurchaseOrdersTable'; import PartPurchaseOrdersTable from '../../tables/part/PartPurchaseOrdersTable';
import PartTestResultTable from '../../tables/part/PartTestResultTable';
import PartTestTemplateTable from '../../tables/part/PartTestTemplateTable'; import PartTestTemplateTable from '../../tables/part/PartTestTemplateTable';
import { PartVariantTable } from '../../tables/part/PartVariantTable'; import { PartVariantTable } from '../../tables/part/PartVariantTable';
import { RelatedPartTable } from '../../tables/part/RelatedPartTable'; import { RelatedPartTable } from '../../tables/part/RelatedPartTable';
@@ -933,6 +935,17 @@ export default function PartDetail() {
<Skeleton /> <Skeleton />
) )
}, },
{
name: 'test_results',
label: t`Test Results`,
icon: <IconChecklist />,
hidden: !part.testable || !user.hasViewRole(UserRoles.stock),
content: part?.pk ? (
<PartTestResultTable partId={part.pk} />
) : (
<Skeleton />
)
},
{ {
name: 'related_parts', name: 'related_parts',
label: t`Related Parts`, label: t`Related Parts`,

View File

@@ -575,8 +575,8 @@ export default function StockDetail() {
) )
}, },
{ {
name: 'testdata', name: 'test-results',
label: t`Test Data`, label: t`Test Results`,
icon: <IconChecklist />, icon: <IconChecklist />,
hidden: !stockitem?.part_detail?.testable, hidden: !stockitem?.part_detail?.testable,
content: stockitem?.pk ? ( content: stockitem?.pk ? (

View File

@@ -86,6 +86,14 @@ export function BatchFilter(): TableFilter {
}; };
} }
export function InStockFilter(): TableFilter {
return {
name: 'in_stock',
label: t`In Stock`,
description: t`Show items which are in stock`
};
}
export function IsSerializedFilter(): TableFilter { export function IsSerializedFilter(): TableFilter {
return { return {
name: 'serialized', name: 'serialized',

View File

@@ -27,20 +27,38 @@ import { useTestResultFields } from '../../forms/StockForms';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { LocationColumn } from '../ColumnRenderers'; import { LocationColumn } from '../ColumnRenderers';
import {
BatchFilter,
HasBatchCodeFilter,
InStockFilter,
IsSerializedFilter,
SerialFilter,
SerialGTEFilter,
SerialLTEFilter,
StatusFilterOptions
} from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { TableHoverCard } from '../TableHoverCard'; import { TableHoverCard } from '../TableHoverCard';
/** /**
* A table which displays all "test results" for the outputs generated by a build order. * A table which displays all "test results" for the outputs generated by a build order.
*/ */
export default function BuildOrderTestTable({ export default function PartTestResultTable({
buildId, buildId,
partId partId
}: Readonly<{ }: Readonly<{
buildId: number; buildId?: number;
partId: number; partId: number;
}>) { }>) {
const table = useTable('build-tests'); const tableName = useMemo(() => {
if (buildId) {
return 'build-test-results';
} else {
return 'part-test-results';
}
}, [buildId]);
const table = useTable(tableName);
const api = useApi(); const api = useApi();
// Fetch the test templates required for this build order // Fetch the test templates required for this build order
@@ -227,7 +245,7 @@ export default function BuildOrderTestTable({
const columns: TableColumn[] = [ const columns: TableColumn[] = [
{ {
accessor: 'stock', accessor: 'stock',
title: t`Build Output`, title: t`Stock Item`,
sortable: true, sortable: true,
switchable: false, switchable: false,
render: (record: any) => { render: (record: any) => {
@@ -258,6 +276,12 @@ export default function BuildOrderTestTable({
} }
} }
}, },
{
accessor: 'batch',
title: t`Batch Code`,
sortable: true,
switchable: true
},
LocationColumn({ LocationColumn({
accessor: 'location_detail' accessor: 'location_detail'
}) })
@@ -272,6 +296,19 @@ export default function BuildOrderTestTable({
name: 'is_building', name: 'is_building',
label: t`In Production`, label: t`In Production`,
description: t`Show build outputs currently in production` description: t`Show build outputs currently in production`
},
InStockFilter(),
SerialFilter(),
SerialGTEFilter(),
SerialLTEFilter(),
HasBatchCodeFilter(),
BatchFilter(),
IsSerializedFilter(),
{
name: 'status',
label: t`Status`,
description: t`Filter by stock status`,
choiceFunction: StatusFilterOptions(ModelType.stockitem)
} }
]; ];
}, []); }, []);

View File

@@ -38,6 +38,7 @@ import {
import { import {
BatchFilter, BatchFilter,
HasBatchCodeFilter, HasBatchCodeFilter,
InStockFilter,
IncludeVariantsFilter, IncludeVariantsFilter,
IsSerializedFilter, IsSerializedFilter,
ManufacturerFilter, ManufacturerFilter,
@@ -354,11 +355,7 @@ function stockItemTableFilters({
label: t`Depleted`, label: t`Depleted`,
description: t`Show depleted stock items` description: t`Show depleted stock items`
}, },
{ InStockFilter(),
name: 'in_stock',
label: t`In Stock`,
description: t`Show items which are in stock`
},
{ {
name: 'is_building', name: 'is_building',
label: t`In Production`, label: t`In Production`,

View File

@@ -33,7 +33,7 @@ test('Stock - Basic Tests', async ({ browser }) => {
await page.getByText('D.123 | Doohickey').waitFor(); await page.getByText('D.123 | Doohickey').waitFor();
await page.getByText('Batch Code: BX-123-2024-2-7').waitFor(); await page.getByText('Batch Code: BX-123-2024-2-7').waitFor();
await loadTab(page, 'Stock Tracking'); await loadTab(page, 'Stock Tracking');
await loadTab(page, 'Test Data'); await loadTab(page, 'Test Results');
await page.getByText('395c6d5586e5fb656901d047be27e1f7').waitFor(); await page.getByText('395c6d5586e5fb656901d047be27e1f7').waitFor();
await loadTab(page, 'Installed Items'); await loadTab(page, 'Installed Items');
}); });