diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx
index aa78ec2d42..b12dc97cee 100644
--- a/src/frontend/src/components/forms/fields/ApiFormField.tsx
+++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx
@@ -1,5 +1,12 @@
import { t } from '@lingui/macro';
-import { Alert, FileInput, NumberInput, Stack, Switch } from '@mantine/core';
+import {
+ Alert,
+ FileInput,
+ type MantineStyleProp,
+ NumberInput,
+ Stack,
+ Switch
+} from '@mantine/core';
import type { UseFormReturnType } from '@mantine/form';
import { useId } from '@mantine/hooks';
import { type ReactNode, useCallback, useEffect, useMemo } from 'react';
@@ -28,6 +35,12 @@ export type ApiFormFieldChoice = {
display_name: string;
};
+// Define individual headers in a table field
+export type ApiFormFieldHeader = {
+ title: string;
+ style?: MantineStyleProp;
+};
+
/** Definition of the ApiForm field component.
* - The 'name' attribute *must* be provided
* - All other attributes are optional, and may be provided by the API
@@ -103,7 +116,7 @@ export type ApiFormFieldType = {
onValueChange?: (value: any, record?: any) => void;
adjustFilters?: (value: ApiFormAdjustFilterType) => any;
addRow?: () => any;
- headers?: string[];
+ headers?: ApiFormFieldHeader[];
depends_on?: string[];
};
diff --git a/src/frontend/src/components/forms/fields/TableField.tsx b/src/frontend/src/components/forms/fields/TableField.tsx
index 6f395f78b9..a49a13c35a 100644
--- a/src/frontend/src/components/forms/fields/TableField.tsx
+++ b/src/frontend/src/components/forms/fields/TableField.tsx
@@ -132,15 +132,21 @@ export function TableField({
);
return (
-
+
{definition.headers?.map((header, index) => {
return (
- {header}
+ {header.title}
);
})}
diff --git a/src/frontend/src/components/render/Stock.tsx b/src/frontend/src/components/render/Stock.tsx
index a45395e3ed..4365e137b1 100644
--- a/src/frontend/src/components/render/Stock.tsx
+++ b/src/frontend/src/components/render/Stock.tsx
@@ -63,10 +63,17 @@ export function RenderStockItem(
quantity_string = `${t`Quantity`}: ${instance.quantity}`;
}
+ let batch_string = '';
+
+ if (!!instance.batch) {
+ batch_string = `${t`Batch`}: ${instance.batch}`;
+ }
+
return (
{quantity_string}}
image={instance.part_detail?.thumbnail || instance.part_detail?.image}
url={
diff --git a/src/frontend/src/forms/BuildForms.tsx b/src/frontend/src/forms/BuildForms.tsx
index 787cb2a16b..87cde86203 100644
--- a/src/frontend/src/forms/BuildForms.tsx
+++ b/src/frontend/src/forms/BuildForms.tsx
@@ -276,7 +276,13 @@ export function useCompleteBuildOutputsForm({
);
},
- headers: [t`Part`, t`Build Output`, t`Batch`, t`Status`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Build Output` },
+ { title: t`Batch` },
+ { title: t`Status` },
+ { title: '', style: { width: '50px' } }
+ ]
},
status_custom_key: {},
location: {
@@ -344,7 +350,13 @@ export function useScrapBuildOutputsForm({
);
},
- headers: [t`Part`, t`Stock Item`, t`Batch`, t`Status`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Stock Item` },
+ { title: t`Batch` },
+ { title: t`Status` },
+ { title: '', style: { width: '50px' } }
+ ]
},
location: {
value: location,
@@ -392,7 +404,13 @@ export function useCancelBuildOutputsForm({
);
},
- headers: [t`Part`, t`Stock Item`, t`Batch`, t`Status`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Stock Item` },
+ { title: t`Batch` },
+ { title: t`Status` },
+ { title: '', style: { width: '50px' } }
+ ]
}
};
}, [outputs]);
@@ -522,7 +540,13 @@ export function useAllocateStockToBuildForm({
items: {
field_type: 'table',
value: [],
- headers: [t`Part`, t`Allocated`, t`Stock Item`, t`Quantity`],
+ headers: [
+ { title: t`Part`, style: { minWidth: '175px' } },
+ { title: t`Allocated`, style: { minWidth: '175px' } },
+ { title: t`Stock Item`, style: { width: '100%' } },
+ { title: t`Quantity`, style: { minWidth: '175px' } },
+ { title: '', style: { width: '50px' } }
+ ],
modelRenderer: (row: TableFieldRowProps) => {
// Find the matching record from the passed 'lineItems'
const record =
diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx
index caea7ddb90..5812578a7b 100644
--- a/src/frontend/src/forms/PurchaseOrderForms.tsx
+++ b/src/frontend/src/forms/PurchaseOrderForms.tsx
@@ -523,9 +523,11 @@ function LineItemFormRow({
onClick={() => open()}
/>
)}
- props.removeFn(props.idx)} />
+
+ props.removeFn(props.idx)} />
+
{locationOpen && (
@@ -745,7 +747,14 @@ export function useReceiveLineItems(props: LineItemsForm) {
/>
);
},
- headers: [t`Part`, t`SKU`, t`Received`, t`Quantity`, t`Actions`]
+ headers: [
+ { title: t`Part`, style: { minWidth: '200px' } },
+ { title: t`SKU`, style: { minWidth: '200px' } },
+ { title: t`Received`, style: { minWidth: '200px' } },
+ { title: t`Quantity`, style: { width: '200px' } },
+ { title: t`Actions` },
+ { title: '', style: { width: '50px' } }
+ ]
},
location: {
filters: {
diff --git a/src/frontend/src/forms/ReturnOrderForms.tsx b/src/frontend/src/forms/ReturnOrderForms.tsx
index f4e2776e54..df9d88e47d 100644
--- a/src/frontend/src/forms/ReturnOrderForms.tsx
+++ b/src/frontend/src/forms/ReturnOrderForms.tsx
@@ -234,7 +234,12 @@ export function useReceiveReturnOrderLineItems(
/>
);
},
- headers: [t`Part`, t`Quantity`, t`Status`]
+ headers: [
+ { title: t`Part`, style: { minWidth: '250px' } },
+ { title: t`Quantity`, style: { minWidth: '250px' } },
+ { title: t`Status`, style: { minWidth: '250px' } },
+ { title: '', style: { width: '50px' } }
+ ]
},
location: {
filters: {
diff --git a/src/frontend/src/forms/SalesOrderForms.tsx b/src/frontend/src/forms/SalesOrderForms.tsx
index c30f9ea0db..b1d893d34e 100644
--- a/src/frontend/src/forms/SalesOrderForms.tsx
+++ b/src/frontend/src/forms/SalesOrderForms.tsx
@@ -262,7 +262,12 @@ export function useAllocateToSalesOrderForm({
items: {
field_type: 'table',
value: [],
- headers: [t`Part`, t`Allocated`, t`Stock Item`, t`Quantity`],
+ headers: [
+ { title: t`Part`, style: { minWidth: '200px' } },
+ { title: t`Allocated`, style: { minWidth: '200px' } },
+ { title: t`Stock Item`, style: { width: '100%' } },
+ { title: t`Quantity`, style: { width: '200px' } }
+ ],
modelRenderer: (row: TableFieldRowProps) => {
const record =
lineItems.find((item) => item.pk == row.item.line_item) ?? {};
diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx
index eb6facefc0..a2bc692674 100644
--- a/src/frontend/src/forms/StockForms.tsx
+++ b/src/frontend/src/forms/StockForms.tsx
@@ -549,6 +549,7 @@ function StockOperationsRow({
{record.location ? record.location_detail?.pathstring : '-'}
+ {record.batch ? record.batch : '-'}
{stockString}
@@ -697,7 +698,14 @@ function stockTransferFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`Stock`, t`Move`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`Stock` },
+ { title: t`Move`, style: { width: '200px' } },
+ { title: t`Actions` }
+ ]
},
location: {
filters: {
@@ -734,7 +742,14 @@ function stockRemoveFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Remove`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: t`Remove`, style: { width: '200px' } },
+ { title: t`Actions` }
+ ]
},
notes: {}
};
@@ -766,7 +781,14 @@ function stockAddFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Add`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: t`Add`, style: { width: '200px' } },
+ { title: t`Actions` }
+ ]
},
notes: {}
};
@@ -795,7 +817,14 @@ function stockCountFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Count`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: t`Count`, style: { width: '200px' } },
+ { title: t`Actions` }
+ ]
},
notes: {}
};
@@ -826,7 +855,13 @@ function stockChangeStatusFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: '', style: { width: '50px' } }
+ ]
},
status: {},
note: {}
@@ -862,7 +897,13 @@ function stockMergeFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: t`Actions` }
+ ]
},
location: {
default: items[0]?.part_detail.default_location,
@@ -904,7 +945,13 @@ function stockAssignFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: '', style: { width: '50px' } }
+ ]
},
customer: {
filters: {
@@ -942,7 +989,13 @@ function stockDeleteFields(items: any[]): ApiFormFieldSet {
/>
);
},
- headers: [t`Part`, t`Location`, t`In Stock`, t`Actions`]
+ headers: [
+ { title: t`Part` },
+ { title: t`Location` },
+ { title: t`Batch` },
+ { title: t`In Stock` },
+ { title: '', style: { width: '50px' } }
+ ]
}
};
diff --git a/src/frontend/src/forms/selectionListFields.tsx b/src/frontend/src/forms/selectionListFields.tsx
index f13de38161..f08c5a9b0d 100644
--- a/src/frontend/src/forms/selectionListFields.tsx
+++ b/src/frontend/src/forms/selectionListFields.tsx
@@ -100,7 +100,12 @@ export function selectionListFields(): ApiFormFieldSet {
description: t`List of entries to choose from`,
field_type: 'table',
value: [],
- headers: [t`Value`, t`Label`, t`Description`, t`Active`],
+ headers: [
+ { title: t`Value` },
+ { title: t`Label` },
+ { title: t`Description` },
+ { title: t`Active` }
+ ],
modelRenderer: (row: TableFieldRowProps) => (
),