2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-30 20:55:42 +00:00

[UI] Duplicate part fixes (#10709)

* Refactor part duplication

- Move duplication items into the form definition

* Expand to part variants table
This commit is contained in:
Oliver
2025-10-29 14:28:22 +11:00
committed by GitHub
parent c7593d983f
commit 51babacec0
4 changed files with 50 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { IconPackages } from '@tabler/icons-react'; import { IconBuildingStore, IconCopy, IconPackages } from '@tabler/icons-react';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints'; import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
@@ -12,8 +12,10 @@ import { useGlobalSettingsState } from '../states/SettingsStates';
* Construct a set of fields for creating / editing a Part instance * Construct a set of fields for creating / editing a Part instance
*/ */
export function usePartFields({ export function usePartFields({
create = false create = false,
duplicatePartInstance
}: { }: {
duplicatePartInstance?: any;
create?: boolean; create?: boolean;
}): ApiFormFieldSet { }): ApiFormFieldSet {
const settings = useGlobalSettingsState(); const settings = useGlobalSettingsState();
@@ -89,6 +91,7 @@ export function usePartFields({
}; };
fields.initial_supplier = { fields.initial_supplier = {
icon: <IconBuildingStore />,
children: { children: {
supplier: { supplier: {
filters: { filters: {
@@ -106,6 +109,36 @@ export function usePartFields({
}; };
} }
// Additional fields for part duplication
if (create && duplicatePartInstance?.pk) {
fields.duplicate = {
icon: <IconCopy />,
children: {
part: {
value: duplicatePartInstance?.pk,
hidden: true
},
copy_image: {
value: true
},
copy_bom: {
value: settings.isSet('PART_COPY_BOM'),
hidden: !duplicatePartInstance?.assembly
},
copy_notes: {
value: true
},
copy_parameters: {
value: settings.isSet('PART_COPY_PARAMETERS')
},
copy_tests: {
value: true,
hidden: !duplicatePartInstance?.testable
}
}
};
}
if (settings.isSet('PART_REVISION_ASSEMBLY_ONLY')) { if (settings.isSet('PART_REVISION_ASSEMBLY_ONLY')) {
fields.revision_of.filters['assembly'] = true; fields.revision_of.filters['assembly'] = true;
} }
@@ -126,7 +159,7 @@ export function usePartFields({
} }
return fields; return fields;
}, [create, settings]); }, [create, duplicatePartInstance, settings]);
} }
/** /**

View File

@@ -47,7 +47,7 @@ import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api'; import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import { ActionButton } from '@lib/index'; import { ActionButton } from '@lib/index';
import type { ApiFormFieldSet, StockOperationProps } from '@lib/types/Forms'; import type { StockOperationProps } from '@lib/types/Forms';
import AdminButton from '../../components/buttons/AdminButton'; import AdminButton from '../../components/buttons/AdminButton';
import { PrintingActions } from '../../components/buttons/PrintingActions'; import { PrintingActions } from '../../components/buttons/PrintingActions';
import StarredToggleButton from '../../components/buttons/StarredToggleButton'; import StarredToggleButton from '../../components/buttons/StarredToggleButton';
@@ -1048,38 +1048,10 @@ export default function PartDetail() {
onFormSuccess: refreshInstance onFormSuccess: refreshInstance
}); });
const createPartFields = usePartFields({ create: true }); const duplicatePartFields = usePartFields({
create: true,
const duplicatePartFields: ApiFormFieldSet = useMemo(() => { duplicatePartInstance: part
return { });
...createPartFields,
duplicate: {
children: {
part: {
value: part.pk,
hidden: true
},
copy_image: {
value: true
},
copy_bom: {
value: part.assembly && globalSettings.isSet('PART_COPY_BOM'),
hidden: !part.assembly
},
copy_notes: {
value: true
},
copy_parameters: {
value: globalSettings.isSet('PART_COPY_PARAMETERS')
},
copy_tests: {
value: part.testable,
hidden: !part.testable
}
}
}
};
}, [createPartFields, globalSettings, part]);
const duplicatePart = useCreateApiFormModal({ const duplicatePart = useCreateApiFormModal({
url: ApiEndpoints.part_list, url: ApiEndpoints.part_list,

View File

@@ -336,11 +336,13 @@ function partTableFilters(): TableFilter[] {
*/ */
export function PartListTable({ export function PartListTable({
enableImport = true, enableImport = true,
basePartInstance,
props, props,
defaultPartData defaultPartData
}: Readonly<{ }: Readonly<{
enableImport?: boolean; enableImport?: boolean;
props?: InvenTreeTableProps; props?: InvenTreeTableProps;
basePartInstance?: any;
defaultPartData?: any; defaultPartData?: any;
}>) { }>) {
const tableColumns = useMemo(() => partTableColumns(), []); const tableColumns = useMemo(() => partTableColumns(), []);
@@ -384,10 +386,15 @@ export function PartListTable({
return defaultPartData ?? props?.params ?? {}; return defaultPartData ?? props?.params ?? {};
}, [defaultPartData, props?.params]); }, [defaultPartData, props?.params]);
const newPartFields = usePartFields({
create: true,
duplicatePartInstance: basePartInstance
});
const newPart = useCreateApiFormModal({ const newPart = useCreateApiFormModal({
url: ApiEndpoints.part_list, url: ApiEndpoints.part_list,
title: t`Add Part`, title: t`Add Part`,
fields: usePartFields({ create: true }), fields: newPartFields,
initialData: initialPartData, initialData: initialPartData,
follow: true, follow: true,
modelType: ModelType.part modelType: ModelType.part

View File

@@ -43,6 +43,7 @@ export function PartVariantTable({ part }: Readonly<{ part: any }>) {
ancestor: part.pk ancestor: part.pk
} }
}} }}
basePartInstance={part}
defaultPartData={{ defaultPartData={{
...part, ...part,
variant_of: part.pk, variant_of: part.pk,