diff --git a/src/frontend/src/pages/build/BuildDetail.tsx b/src/frontend/src/pages/build/BuildDetail.tsx
index 8f8bf0e60e..eb3b84117e 100644
--- a/src/frontend/src/pages/build/BuildDetail.tsx
+++ b/src/frontend/src/pages/build/BuildDetail.tsx
@@ -5,6 +5,7 @@ import {
IconCircleCheck,
IconClipboardCheck,
IconClipboardList,
+ IconExclamationCircle,
IconInfoCircle,
IconList,
IconListCheck,
@@ -88,6 +89,13 @@ function BuildLinesPanel({
isLoading: boolean;
hasItems: boolean;
}>) {
+ const bomInformation = useInstance({
+ endpoint: ApiEndpoints.bom_validate,
+ pk: build?.part,
+ hasPrimaryKey: true,
+ refetchOnMount: true
+ });
+
const buildLocation = useInstance({
endpoint: ApiEndpoints.stock_location_list,
pk: build?.take_from,
@@ -105,6 +113,16 @@ function BuildLinesPanel({
return (
+ {bomInformation?.isLoaded &&
+ bomInformation?.instance?.bom_validated == false && (
+ }
+ title={t`BOM Not Validated`}
+ >
+ {t`The Bill of Materials for this assembly has not been validated.`}
+
+ )}
{buildLocation.instance.pk && (
} title={t`Source Location`}>
diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx
index afc8e133be..2dfc6e1784 100644
--- a/src/frontend/src/pages/part/PartDetail.tsx
+++ b/src/frontend/src/pages/part/PartDetail.tsx
@@ -89,7 +89,7 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
-import { useInstance } from '../../hooks/UseInstance';
+import { type UseInstanceResult, useInstance } from '../../hooks/UseInstance';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';
import {
useGlobalSettingsState,
@@ -158,18 +158,12 @@ function RevisionSelector({
* A hover-over component which displays information about the BOM validation for a given part
*/
function BomValidationInformation({
+ bomInformation,
partId
}: {
+ bomInformation: UseInstanceResult;
partId: number;
}) {
- const { instance: bomInformation, instanceQuery: bomInformationQuery } =
- useInstance({
- endpoint: ApiEndpoints.bom_validate,
- pk: partId,
- hasPrimaryKey: true,
- refetchOnMount: true
- });
-
const [taskId, setTaskId] = useState('');
useBackgroundTask({
@@ -177,7 +171,7 @@ function BomValidationInformation({
message: t`Validating BOM`,
successMessage: t`BOM validated`,
onComplete: () => {
- bomInformationQuery.refetch();
+ bomInformation.instanceQuery.refetch();
}
});
@@ -203,12 +197,12 @@ function BomValidationInformation({
if (response.task_id) {
setTaskId(response.task_id);
} else {
- bomInformationQuery.refetch();
+ bomInformation.instanceQuery.refetch();
}
}
});
- if (bomInformationQuery.isFetching) {
+ if (bomInformation.instanceQuery.isFetching) {
return ;
}
@@ -217,12 +211,12 @@ function BomValidationInformation({
let title = '';
let description = '';
- if (bomInformation?.bom_validated) {
+ if (bomInformation.instance?.bom_validated) {
color = 'green';
icon = ;
title = t`BOM Validated`;
description = t`The Bill of Materials for this part has been validated`;
- } else if (bomInformation?.bom_checked_date) {
+ } else if (bomInformation.instance?.bom_checked_date) {
color = 'yellow';
icon = ;
title = t`BOM Not Validated`;
@@ -238,7 +232,7 @@ function BomValidationInformation({
<>
{validateBom.modal}
- {!bomInformation.bom_validated && (
+ {!bomInformation.instance?.bom_validated && (
}
color='green'
@@ -260,16 +254,17 @@ function BomValidationInformation({
{description}
- {bomInformation?.bom_checked_date && (
+ {bomInformation.instance?.bom_checked_date && (
- {t`Validated On`}: {bomInformation.bom_checked_date}
+ {t`Validated On`}:{' '}
+ {bomInformation.instance.bom_checked_date}
)}
- {bomInformation?.bom_checked_by_detail && (
+ {bomInformation.instance?.bom_checked_by_detail && (
{t`Validated By`}:
)}
@@ -297,6 +292,13 @@ export default function PartDetail() {
const globalSettings = useGlobalSettingsState();
const userSettings = useUserSettingsState();
+ const bomInformation = useInstance({
+ endpoint: ApiEndpoints.bom_validate,
+ pk: id,
+ hasPrimaryKey: true,
+ refetchOnMount: true
+ });
+
const { instance: serials } = useInstance({
endpoint: ApiEndpoints.part_serial_numbers,
pk: id,
@@ -802,11 +804,31 @@ export default function PartDetail() {
{
name: 'bom',
label: t`Bill of Materials`,
- controls: ,
+ controls: (
+
+ ),
icon: ,
hidden: !part.assembly,
content: part?.pk ? (
-
+
+ {bomInformation.isLoaded &&
+ bomInformation.instance?.bom_validated === false && (
+ }
+ title={t`BOM Not Validated`}
+ >
+ {t`The Bill of Materials for this assembly has not been validated.`}
+
+ )}
+
+
) : (
)
@@ -950,7 +972,15 @@ export default function PartDetail() {
has_note: !!part?.notes
})
];
- }, [id, part, user, globalSettings, userSettings, detailsPanel]);
+ }, [
+ id,
+ part,
+ user,
+ globalSettings,
+ userSettings,
+ detailsPanel,
+ bomInformation
+ ]);
const breadcrumbs = useMemo(() => {
return [
diff --git a/src/frontend/src/tables/bom/BomSubassemblyTable.tsx b/src/frontend/src/tables/bom/BomSubassemblyTable.tsx
index 71373e599d..5e3bc9ea3f 100644
--- a/src/frontend/src/tables/bom/BomSubassemblyTable.tsx
+++ b/src/frontend/src/tables/bom/BomSubassemblyTable.tsx
@@ -77,9 +77,12 @@ export default function BomSubassemblyTable({
IPNColumn({
accessor: 'sub_part_detail.IPN'
}),
- ReferenceColumn({}),
+ ReferenceColumn({
+ width: 400
+ }),
{
- accessor: 'quantity'
+ accessor: 'quantity',
+ width: 250
}
];
}, [table.isRowExpanded, userSettings]);