From 090f657f11f03344fada94d3fe56951684326ce9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 24 Jul 2025 08:17:08 +1000 Subject: [PATCH] Refactor BomValidationInfo into component (#10064) - Cleaner code - Don't fetch for non-assembly parts --- src/frontend/src/pages/part/PartDetail.tsx | 230 ++++++++++----------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx index b90713fef3..38e3f3aea7 100644 --- a/src/frontend/src/pages/part/PartDetail.tsx +++ b/src/frontend/src/pages/part/PartDetail.tsx @@ -153,6 +153,118 @@ function RevisionSelector({ ); } +/** + * A hover-over component which displays information about the BOM validation for a given part + */ +function BomValidationInformation({ + partId +}: { + partId: number; +}) { + const { instance: bomInformation, instanceQuery: bomInformationQuery } = + useInstance({ + endpoint: ApiEndpoints.bom_validate, + pk: partId, + hasPrimaryKey: true, + refetchOnMount: true + }); + + const validateBom = useApiFormModal({ + url: ApiEndpoints.bom_validate, + method: 'PUT', + fields: { + valid: { + hidden: true, + value: true + } + }, + title: t`Validate BOM`, + pk: partId, + preFormContent: ( + } title={t`Validate BOM`}> + {t`Do you want to validate the bill of materials for this assembly?`} + + ), + successMessage: t`BOM validated`, + onFormSuccess: () => { + bomInformationQuery.refetch(); + } + }); + + if (bomInformationQuery.isFetching) { + return ; + } + + let icon: ReactNode; + let color: MantineColor; + let title = ''; + let description = ''; + + if (bomInformation?.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) { + color = 'yellow'; + icon = ; + title = t`BOM Not Validated`; + description = t`The Bill of Materials for this part has previously been checked, but requires revalidation`; + } else { + color = 'red'; + icon = ; + title = t`BOM Not Validated`; + description = t`The Bill of Materials for this part has not yet been validated`; + } + + return ( + <> + {validateBom.modal} + + {!bomInformation.bom_validated && ( + } + color='green' + tooltip={t`Validate BOM`} + onClick={validateBom.open} + /> + )} + + + + {icon} + + + + + + {description} + {bomInformation?.bom_checked_date && ( + + {t`Validated On`}: {bomInformation.bom_checked_date} + + )} + {bomInformation?.bom_checked_by_detail && ( + + {t`Validated By`}: + + + )} + + + + + + + ); +} + /** * Detail view for a single Part instance */ @@ -189,14 +301,6 @@ export default function PartDetail() { refetchOnMount: true }); - const { instance: bomInformation, instanceQuery: bomInformationQuery } = - useInstance({ - endpoint: ApiEndpoints.bom_validate, - pk: id, - hasPrimaryKey: true, - refetchOnMount: true - }); - const { instance: partRequirements, instanceQuery: partRequirementsQuery } = useInstance({ endpoint: ApiEndpoints.part_requirements, @@ -675,101 +779,6 @@ export default function PartDetail() { partRequirements ]); - const validateBom = useApiFormModal({ - url: ApiEndpoints.bom_validate, - method: 'PUT', - fields: { - valid: { - hidden: true, - value: true - } - }, - title: t`Validate BOM`, - pk: id, - preFormContent: ( - } title={t`Validate BOM`}> - {t`Do you want to validate the bill of materials for this assembly?`} - - ), - successMessage: t`BOM validated`, - onFormSuccess: () => { - bomInformationQuery.refetch(); - } - }); - - // Display information about the "validation" state of the BOM for this assembly - const bomValidIcon: ReactNode = useMemo(() => { - if (bomInformationQuery.isFetching) { - return ; - } - - let icon: ReactNode; - let color: MantineColor; - let title = ''; - let description = ''; - - if (bomInformation?.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) { - color = 'yellow'; - icon = ; - title = t`BOM Not Validated`; - description = t`The Bill of Materials for this part has previously been checked, but requires revalidation`; - } else { - color = 'red'; - icon = ; - title = t`BOM Not Validated`; - description = t`The Bill of Materials for this part has not yet been validated`; - } - - return ( - - {!bomInformation.bom_validated && ( - } - color='green' - tooltip={t`Validate BOM`} - onClick={validateBom.open} - /> - )} - - - - {icon} - - - - - - {description} - {bomInformation?.bom_checked_date && ( - - {t`Validated On`}: {bomInformation.bom_checked_date} - - )} - {bomInformation?.bom_checked_by_detail && ( - - {t`Validated By`}: - - - )} - - - - - - ); - }, [bomInformation, bomInformationQuery.isFetching]); - // Part data panels (recalculate when part data changes) const partPanels: PanelType[] = useMemo(() => { return [ @@ -825,7 +834,7 @@ export default function PartDetail() { { name: 'bom', label: t`Bill of Materials`, - controls: bomValidIcon, + controls: , icon: , hidden: !part.assembly, content: part?.pk ? ( @@ -921,7 +930,7 @@ export default function PartDetail() { name: 'related_parts', label: t`Related Parts`, icon: , - content: + content: }, AttachmentPanel({ model_type: ModelType.part, @@ -932,15 +941,7 @@ export default function PartDetail() { model_id: part?.pk }) ]; - }, [ - id, - part, - user, - bomValidIcon, - globalSettings, - userSettings, - detailsPanel - ]); + }, [id, part, user, globalSettings, userSettings, detailsPanel]); const breadcrumbs = useMemo(() => { return [ @@ -1187,7 +1188,6 @@ export default function PartDetail() { <> {editPart.modal} {deletePart.modal} - {validateBom.modal} {duplicatePart.modal} {orderPartsWizard.wizard} {findBySerialNumber.modal}