mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-30 16:41:35 +00:00
Refactor BomValidationInfo into component (#10064)
- Cleaner code - Don't fetch for non-assembly parts
This commit is contained in:
@@ -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: (
|
||||||
|
<Alert color='green' icon={<IconCircleCheck />} title={t`Validate BOM`}>
|
||||||
|
<Text>{t`Do you want to validate the bill of materials for this assembly?`}</Text>
|
||||||
|
</Alert>
|
||||||
|
),
|
||||||
|
successMessage: t`BOM validated`,
|
||||||
|
onFormSuccess: () => {
|
||||||
|
bomInformationQuery.refetch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bomInformationQuery.isFetching) {
|
||||||
|
return <Loader size='sm' />;
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon: ReactNode;
|
||||||
|
let color: MantineColor;
|
||||||
|
let title = '';
|
||||||
|
let description = '';
|
||||||
|
|
||||||
|
if (bomInformation?.bom_validated) {
|
||||||
|
color = 'green';
|
||||||
|
icon = <IconListCheck />;
|
||||||
|
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 = <IconExclamationCircle />;
|
||||||
|
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 = <IconExclamationCircle />;
|
||||||
|
title = t`BOM Not Validated`;
|
||||||
|
description = t`The Bill of Materials for this part has not yet been validated`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{validateBom.modal}
|
||||||
|
<Group gap='xs' justify='flex-end'>
|
||||||
|
{!bomInformation.bom_validated && (
|
||||||
|
<ActionButton
|
||||||
|
icon={<IconCircleCheck />}
|
||||||
|
color='green'
|
||||||
|
tooltip={t`Validate BOM`}
|
||||||
|
onClick={validateBom.open}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<HoverCard position='bottom-end'>
|
||||||
|
<HoverCard.Target>
|
||||||
|
<ActionIcon
|
||||||
|
color={color}
|
||||||
|
variant='transparent'
|
||||||
|
aria-label='bom-validation-info'
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
</ActionIcon>
|
||||||
|
</HoverCard.Target>
|
||||||
|
<HoverCard.Dropdown>
|
||||||
|
<Alert color={color} icon={icon} title={title}>
|
||||||
|
<Stack gap='xs'>
|
||||||
|
<Text size='sm'>{description}</Text>
|
||||||
|
{bomInformation?.bom_checked_date && (
|
||||||
|
<Text size='sm'>
|
||||||
|
{t`Validated On`}: {bomInformation.bom_checked_date}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{bomInformation?.bom_checked_by_detail && (
|
||||||
|
<Group gap='xs'>
|
||||||
|
<Text size='sm'>{t`Validated By`}: </Text>
|
||||||
|
<RenderUser
|
||||||
|
instance={bomInformation.bom_checked_by_detail}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Alert>
|
||||||
|
</HoverCard.Dropdown>
|
||||||
|
</HoverCard>
|
||||||
|
</Group>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detail view for a single Part instance
|
* Detail view for a single Part instance
|
||||||
*/
|
*/
|
||||||
@@ -189,14 +301,6 @@ export default function PartDetail() {
|
|||||||
refetchOnMount: true
|
refetchOnMount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const { instance: bomInformation, instanceQuery: bomInformationQuery } =
|
|
||||||
useInstance({
|
|
||||||
endpoint: ApiEndpoints.bom_validate,
|
|
||||||
pk: id,
|
|
||||||
hasPrimaryKey: true,
|
|
||||||
refetchOnMount: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const { instance: partRequirements, instanceQuery: partRequirementsQuery } =
|
const { instance: partRequirements, instanceQuery: partRequirementsQuery } =
|
||||||
useInstance({
|
useInstance({
|
||||||
endpoint: ApiEndpoints.part_requirements,
|
endpoint: ApiEndpoints.part_requirements,
|
||||||
@@ -675,101 +779,6 @@ export default function PartDetail() {
|
|||||||
partRequirements
|
partRequirements
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const validateBom = useApiFormModal({
|
|
||||||
url: ApiEndpoints.bom_validate,
|
|
||||||
method: 'PUT',
|
|
||||||
fields: {
|
|
||||||
valid: {
|
|
||||||
hidden: true,
|
|
||||||
value: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: t`Validate BOM`,
|
|
||||||
pk: id,
|
|
||||||
preFormContent: (
|
|
||||||
<Alert color='green' icon={<IconCircleCheck />} title={t`Validate BOM`}>
|
|
||||||
<Text>{t`Do you want to validate the bill of materials for this assembly?`}</Text>
|
|
||||||
</Alert>
|
|
||||||
),
|
|
||||||
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 <Loader size='sm' />;
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon: ReactNode;
|
|
||||||
let color: MantineColor;
|
|
||||||
let title = '';
|
|
||||||
let description = '';
|
|
||||||
|
|
||||||
if (bomInformation?.bom_validated) {
|
|
||||||
color = 'green';
|
|
||||||
icon = <IconListCheck />;
|
|
||||||
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 = <IconExclamationCircle />;
|
|
||||||
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 = <IconExclamationCircle />;
|
|
||||||
title = t`BOM Not Validated`;
|
|
||||||
description = t`The Bill of Materials for this part has not yet been validated`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Group gap='xs' justify='flex-end'>
|
|
||||||
{!bomInformation.bom_validated && (
|
|
||||||
<ActionButton
|
|
||||||
icon={<IconCircleCheck />}
|
|
||||||
color='green'
|
|
||||||
tooltip={t`Validate BOM`}
|
|
||||||
onClick={validateBom.open}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<HoverCard position='bottom-end'>
|
|
||||||
<HoverCard.Target>
|
|
||||||
<ActionIcon
|
|
||||||
color={color}
|
|
||||||
variant='transparent'
|
|
||||||
aria-label='bom-validation-info'
|
|
||||||
>
|
|
||||||
{icon}
|
|
||||||
</ActionIcon>
|
|
||||||
</HoverCard.Target>
|
|
||||||
<HoverCard.Dropdown>
|
|
||||||
<Alert color={color} icon={icon} title={title}>
|
|
||||||
<Stack gap='xs'>
|
|
||||||
<Text size='sm'>{description}</Text>
|
|
||||||
{bomInformation?.bom_checked_date && (
|
|
||||||
<Text size='sm'>
|
|
||||||
{t`Validated On`}: {bomInformation.bom_checked_date}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{bomInformation?.bom_checked_by_detail && (
|
|
||||||
<Group gap='xs'>
|
|
||||||
<Text size='sm'>{t`Validated By`}: </Text>
|
|
||||||
<RenderUser
|
|
||||||
instance={bomInformation.bom_checked_by_detail}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</Alert>
|
|
||||||
</HoverCard.Dropdown>
|
|
||||||
</HoverCard>
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
}, [bomInformation, bomInformationQuery.isFetching]);
|
|
||||||
|
|
||||||
// Part data panels (recalculate when part data changes)
|
// Part data panels (recalculate when part data changes)
|
||||||
const partPanels: PanelType[] = useMemo(() => {
|
const partPanels: PanelType[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@@ -825,7 +834,7 @@ export default function PartDetail() {
|
|||||||
{
|
{
|
||||||
name: 'bom',
|
name: 'bom',
|
||||||
label: t`Bill of Materials`,
|
label: t`Bill of Materials`,
|
||||||
controls: bomValidIcon,
|
controls: <BomValidationInformation partId={part.pk ?? -1} />,
|
||||||
icon: <IconListTree />,
|
icon: <IconListTree />,
|
||||||
hidden: !part.assembly,
|
hidden: !part.assembly,
|
||||||
content: part?.pk ? (
|
content: part?.pk ? (
|
||||||
@@ -921,7 +930,7 @@ export default function PartDetail() {
|
|||||||
name: 'related_parts',
|
name: 'related_parts',
|
||||||
label: t`Related Parts`,
|
label: t`Related Parts`,
|
||||||
icon: <IconLayersLinked />,
|
icon: <IconLayersLinked />,
|
||||||
content: <RelatedPartTable partId={part.pk ?? -1} />
|
content: <RelatedPartTable partId={part.pk} />
|
||||||
},
|
},
|
||||||
AttachmentPanel({
|
AttachmentPanel({
|
||||||
model_type: ModelType.part,
|
model_type: ModelType.part,
|
||||||
@@ -932,15 +941,7 @@ export default function PartDetail() {
|
|||||||
model_id: part?.pk
|
model_id: part?.pk
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}, [
|
}, [id, part, user, globalSettings, userSettings, detailsPanel]);
|
||||||
id,
|
|
||||||
part,
|
|
||||||
user,
|
|
||||||
bomValidIcon,
|
|
||||||
globalSettings,
|
|
||||||
userSettings,
|
|
||||||
detailsPanel
|
|
||||||
]);
|
|
||||||
|
|
||||||
const breadcrumbs = useMemo(() => {
|
const breadcrumbs = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@@ -1187,7 +1188,6 @@ export default function PartDetail() {
|
|||||||
<>
|
<>
|
||||||
{editPart.modal}
|
{editPart.modal}
|
||||||
{deletePart.modal}
|
{deletePart.modal}
|
||||||
{validateBom.modal}
|
|
||||||
{duplicatePart.modal}
|
{duplicatePart.modal}
|
||||||
{orderPartsWizard.wizard}
|
{orderPartsWizard.wizard}
|
||||||
{findBySerialNumber.modal}
|
{findBySerialNumber.modal}
|
||||||
|
Reference in New Issue
Block a user