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}