[PUI] Adds NewPart form (#6598)

This commit is contained in:
Oliver 2024-02-28 16:56:19 +11:00 committed by GitHub
parent 38d013ffe2
commit a2a7b60d41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 136 additions and 103 deletions

View File

@ -1,99 +1,94 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { IconPackages } from '@tabler/icons-react'; import { IconPackages } from '@tabler/icons-react';
import { useMemo } from 'react';
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
/** /**
* Construct a set of fields for creating / editing a Part instance * Construct a set of fields for creating / editing a Part instance
*/ */
export function partFields({ export function usePartFields({
editing = false, create = false
category_id
}: { }: {
editing?: boolean; create?: boolean;
category_id?: number;
}): ApiFormFieldSet { }): ApiFormFieldSet {
let fields: ApiFormFieldSet = { return useMemo(() => {
category: { const fields: ApiFormFieldSet = {
filters: { category: {
structural: false filters: {
} structural: false
}, }
name: {}, },
IPN: {}, name: {},
revision: {}, IPN: {},
description: {}, revision: {},
variant_of: {}, description: {},
keywords: {}, variant_of: {},
units: {}, keywords: {},
link: {}, units: {},
default_location: { link: {},
filters: { default_location: {
structural: false filters: {
} structural: false
}, }
default_expiry: {}, },
minimum_stock: {}, default_expiry: {},
responsible: { minimum_stock: {},
filters: { responsible: {
is_active: true filters: {
} is_active: true
}, }
component: {}, },
assembly: {}, component: {},
is_template: {}, assembly: {},
trackable: {}, is_template: {},
purchaseable: {}, trackable: {},
salable: {}, purchaseable: {},
virtual: {}, salable: {},
active: {} virtual: {},
}; active: {}
if (category_id != null) {
// TODO: Set the value of the category field
}
// Additional fields for creation
if (!editing) {
// TODO: Hide 'active' field
fields.copy_category_parameters = {};
fields.initial_stock = {
icon: <IconPackages />,
children: {
quantity: {},
location: {}
}
}; };
fields.initial_supplier = { // Additional fields for creation
children: { if (create) {
supplier: { fields.copy_category_parameters = {};
filters: {
is_supplier: true
}
},
sku: {},
manufacturer: {
filters: {
is_manufacturer: true
}
},
mpn: {}
}
};
}
// TODO: pop 'expiry' field if expiry not enabled fields.initial_stock = {
delete fields['default_expiry']; icon: <IconPackages />,
children: {
quantity: {},
location: {}
}
};
// TODO: pop 'revision' field if PART_ENABLE_REVISION is False fields.initial_supplier = {
delete fields['revision']; children: {
supplier: {
filters: {
is_supplier: true
}
},
sku: {},
manufacturer: {
filters: {
is_manufacturer: true
}
},
mpn: {}
}
};
}
// TODO: handle part duplications // TODO: pop 'expiry' field if expiry not enabled
delete fields['default_expiry'];
return fields; // TODO: pop 'revision' field if PART_ENABLE_REVISION is False
delete fields['revision'];
// TODO: handle part duplications
return fields;
}, [create]);
} }
/** /**

View File

@ -10,7 +10,7 @@ import { StylishText } from '../../components/items/StylishText';
import { StatusRenderer } from '../../components/render/StatusRenderer'; import { StatusRenderer } from '../../components/render/StatusRenderer';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { partCategoryFields, partFields } from '../../forms/PartForms'; import { partCategoryFields, usePartFields } from '../../forms/PartForms';
import { useCreateStockItem } from '../../forms/StockForms'; import { useCreateStockItem } from '../../forms/StockForms';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
@ -28,10 +28,13 @@ function ApiFormsPlayground() {
fields: fields fields: fields
}); });
const createPartFields = usePartFields({ create: true });
const editPartFields = usePartFields({ create: false });
const newPart = useCreateApiFormModal({ const newPart = useCreateApiFormModal({
url: ApiEndpoints.part_list, url: ApiEndpoints.part_list,
title: 'Create Part', title: 'Create Part',
fields: partFields({}), fields: createPartFields,
initialData: { initialData: {
description: 'A part created via the API' description: 'A part created via the API'
} }
@ -41,7 +44,7 @@ function ApiFormsPlayground() {
url: ApiEndpoints.part_list, url: ApiEndpoints.part_list,
pk: 1, pk: 1,
title: 'Edit Part', title: 'Edit Part',
fields: partFields({ editing: true }) fields: editPartFields
}); });
const newAttachment = useCreateApiFormModal({ const newAttachment = useCreateApiFormModal({
@ -62,7 +65,7 @@ function ApiFormsPlayground() {
const [name, setName] = useState('Hello'); const [name, setName] = useState('Hello');
const partFieldsState: any = useMemo<any>(() => { const partFieldsState: any = useMemo<any>(() => {
const fields = partFields({}); const fields = editPartFields;
fields.name = { fields.name = {
...fields.name, ...fields.name,
value: name, value: name,

View File

@ -46,7 +46,7 @@ import { formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { partFields } from '../../forms/PartForms'; import { usePartFields } from '../../forms/PartForms';
import { useEditApiFormModal } from '../../hooks/UseForm'; import { useEditApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
@ -630,11 +630,13 @@ export default function PartDetail() {
); );
}, [part, id]); }, [part, id]);
const partFields = usePartFields({ create: false });
const editPart = useEditApiFormModal({ const editPart = useEditApiFormModal({
url: ApiEndpoints.part_list, url: ApiEndpoints.part_list,
pk: part.pk, pk: part.pk,
title: t`Edit Part`, title: t`Edit Part`,
fields: partFields({ editing: true }), fields: partFields,
onFormSuccess: refreshInstance onFormSuccess: refreshInstance
}); });

View File

@ -3,14 +3,19 @@ import { Group, Text } from '@mantine/core';
import { ReactNode, useMemo } from 'react'; import { ReactNode, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { Thumbnail } from '../../components/images/Thumbnail'; import { Thumbnail } from '../../components/images/Thumbnail';
import { formatPriceRange } from '../../defaults/formatters'; import { formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles';
import { usePartFields } from '../../forms/PartForms';
import { shortenString } from '../../functions/tables'; import { shortenString } from '../../functions/tables';
import { getDetailUrl } from '../../functions/urls'; import { getDetailUrl } from '../../functions/urls';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn, LinkColumn } from '../ColumnRenderers'; import { DescriptionColumn, LinkColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -261,25 +266,53 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) {
const tableFilters = useMemo(() => partTableFilters(), []); const tableFilters = useMemo(() => partTableFilters(), []);
const table = useTable('part-list'); const table = useTable('part-list');
const navigate = useNavigate(); const navigate = useNavigate();
const user = useUserState();
const newPart = useCreateApiFormModal({
url: ApiEndpoints.part_list,
title: t`Add Part`,
fields: usePartFields({ create: true }),
initialData: {
...(props.params ?? {})
},
onFormSuccess: (data: any) => {
if (data.pk) {
navigate(getDetailUrl(ModelType.part, data.pk));
}
}
});
const tableActions = useMemo(() => {
return [
<AddItemButton
hidden={!user.hasAddRole(UserRoles.part)}
tooltip={t`Add Part`}
onClick={() => newPart.open()}
/>
];
}, [user]);
return ( return (
<InvenTreeTable <>
url={apiUrl(ApiEndpoints.part_list)} {newPart.modal}
tableState={table} <InvenTreeTable
columns={tableColumns} url={apiUrl(ApiEndpoints.part_list)}
props={{ tableState={table}
...props, columns={tableColumns}
enableDownload: true, props={{
tableFilters: tableFilters, ...props,
params: { enableDownload: true,
...props.params, tableFilters: tableFilters,
category_detail: true tableActions: tableActions,
}, params: {
onRowClick: (record) => ...props.params,
navigate(getDetailUrl(ModelType.part, record.pk)) category_detail: true
}} },
/> onRowClick: (record) =>
navigate(getDetailUrl(ModelType.part, record.pk))
}}
/>
</>
); );
} }