mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-02 13:28:49 +00:00
284 lines
7.5 KiB
TypeScript
284 lines
7.5 KiB
TypeScript
import { t } from '@lingui/macro';
|
|
import { ActionIcon, Group, Tooltip } from '@mantine/core';
|
|
import { useHover } from '@mantine/hooks';
|
|
import { IconEdit } from '@tabler/icons-react';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
|
|
import { api } from '../../App';
|
|
import { YesNoButton } from '../../components/buttons/YesNoButton';
|
|
import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
|
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
|
import { ModelType } from '../../enums/ModelType';
|
|
import { UserRoles } from '../../enums/Roles';
|
|
import { usePartParameterFields } from '../../forms/PartForms';
|
|
import { cancelEvent } from '../../functions/events';
|
|
import {
|
|
useCreateApiFormModal,
|
|
useEditApiFormModal
|
|
} from '../../hooks/UseForm';
|
|
import { useTable } from '../../hooks/UseTable';
|
|
import { apiUrl } from '../../states/ApiState';
|
|
import { useUserState } from '../../states/UserState';
|
|
import { TableColumn } from '../Column';
|
|
import { DescriptionColumn, PartColumn } from '../ColumnRenderers';
|
|
import { TableFilter } from '../Filter';
|
|
import { InvenTreeTable } from '../InvenTreeTable';
|
|
import { TableHoverCard } from '../TableHoverCard';
|
|
|
|
// Render an individual parameter cell
|
|
function ParameterCell({
|
|
record,
|
|
template,
|
|
canEdit,
|
|
onEdit
|
|
}: {
|
|
record: any;
|
|
template: any;
|
|
canEdit: boolean;
|
|
onEdit: () => void;
|
|
}) {
|
|
const { hovered, ref } = useHover();
|
|
|
|
// Find matching template parameter
|
|
let parameter = record.parameters?.find(
|
|
(p: any) => p.template == template.pk
|
|
);
|
|
|
|
let extra: any[] = [];
|
|
|
|
let value: any = parameter?.data;
|
|
|
|
if (template?.checkbox && value != undefined) {
|
|
value = <YesNoButton value={parameter.data} />;
|
|
}
|
|
|
|
if (
|
|
template.units &&
|
|
parameter &&
|
|
parameter.data_numeric &&
|
|
parameter.data_numeric != parameter.data
|
|
) {
|
|
extra.push(`${parameter.data_numeric} [${template.units}]`);
|
|
}
|
|
|
|
const handleClick = useCallback((event: any) => {
|
|
cancelEvent(event);
|
|
onEdit();
|
|
}, []);
|
|
|
|
return (
|
|
<div>
|
|
<Group grow ref={ref} justify="space-between">
|
|
<Group grow style={{ flex: 1 }}>
|
|
<TableHoverCard
|
|
value={value ?? '-'}
|
|
extra={extra}
|
|
title={t`Internal Units`}
|
|
/>
|
|
</Group>
|
|
{hovered && canEdit && (
|
|
<div style={{ flex: 0 }}>
|
|
<Tooltip label={t`Edit parameter`}>
|
|
<ActionIcon size="xs" onClick={handleClick} variant="transparent">
|
|
<IconEdit />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</div>
|
|
)}
|
|
</Group>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function ParametricPartTable({
|
|
categoryId
|
|
}: {
|
|
categoryId?: any;
|
|
}) {
|
|
const table = useTable('parametric-parts');
|
|
const user = useUserState();
|
|
|
|
const categoryParmeters = useQuery({
|
|
queryKey: ['category-parameters', categoryId],
|
|
queryFn: async () => {
|
|
return api
|
|
.get(apiUrl(ApiEndpoints.part_parameter_template_list), {
|
|
params: {
|
|
category: categoryId
|
|
}
|
|
})
|
|
.then((response) => response.data)
|
|
.catch((_error) => []);
|
|
},
|
|
refetchOnMount: true
|
|
});
|
|
|
|
const [selectedPart, setSelectedPart] = useState<number>(0);
|
|
const [selectedTemplate, setSelectedTemplate] = useState<number>(0);
|
|
const [selectedParameter, setSelectedParameter] = useState<number>(0);
|
|
|
|
const partParameterFields: ApiFormFieldSet = usePartParameterFields();
|
|
|
|
const addParameter = useCreateApiFormModal({
|
|
url: ApiEndpoints.part_parameter_list,
|
|
title: t`Add Part Parameter`,
|
|
fields: useMemo(() => ({ ...partParameterFields }), [partParameterFields]),
|
|
focus: 'data',
|
|
onFormSuccess: (parameter: any) => {
|
|
updateParameterRecord(selectedPart, parameter);
|
|
},
|
|
initialData: {
|
|
part: selectedPart,
|
|
template: selectedTemplate
|
|
}
|
|
});
|
|
|
|
const editParameter = useEditApiFormModal({
|
|
url: ApiEndpoints.part_parameter_list,
|
|
title: t`Edit Part Parameter`,
|
|
pk: selectedParameter,
|
|
fields: useMemo(() => ({ ...partParameterFields }), [partParameterFields]),
|
|
focus: 'data',
|
|
onFormSuccess: (parameter: any) => {
|
|
updateParameterRecord(selectedPart, parameter);
|
|
}
|
|
});
|
|
|
|
// Update a single parameter record in the table
|
|
const updateParameterRecord = useCallback(
|
|
(part: number, parameter: any) => {
|
|
let records = table.records;
|
|
let partIndex = records.findIndex((record: any) => record.pk == part);
|
|
|
|
if (partIndex < 0) {
|
|
// No matching part: reload the entire table
|
|
table.refreshTable();
|
|
return;
|
|
}
|
|
|
|
let parameterIndex = records[partIndex].parameters.findIndex(
|
|
(p: any) => p.pk == parameter.pk
|
|
);
|
|
|
|
if (parameterIndex < 0) {
|
|
// No matching parameter - append new parameter
|
|
records[partIndex].parameters.push(parameter);
|
|
} else {
|
|
records[partIndex].parameters[parameterIndex] = parameter;
|
|
}
|
|
|
|
table.setRecords(records);
|
|
},
|
|
[table.records]
|
|
);
|
|
|
|
const parameterColumns: TableColumn[] = useMemo(() => {
|
|
let data = categoryParmeters.data ?? [];
|
|
|
|
return data.map((template: any) => {
|
|
let title = template.name;
|
|
|
|
if (template.units) {
|
|
title += ` [${template.units}]`;
|
|
}
|
|
|
|
return {
|
|
accessor: `parameter_${template.pk}`,
|
|
title: title,
|
|
sortable: true,
|
|
extra: {
|
|
template: template.pk
|
|
},
|
|
render: (record: any) => (
|
|
<ParameterCell
|
|
record={record}
|
|
template={template}
|
|
canEdit={user.hasChangeRole(UserRoles.part)}
|
|
onEdit={() => {
|
|
setSelectedTemplate(template.pk);
|
|
setSelectedPart(record.pk);
|
|
let parameter = record.parameters?.find(
|
|
(p: any) => p.template == template.pk
|
|
);
|
|
|
|
if (parameter) {
|
|
setSelectedParameter(parameter.pk);
|
|
editParameter.open();
|
|
} else {
|
|
addParameter.open();
|
|
}
|
|
}}
|
|
/>
|
|
)
|
|
};
|
|
});
|
|
}, [user, categoryParmeters.data]);
|
|
|
|
const tableFilters: TableFilter[] = useMemo(() => {
|
|
return [
|
|
{
|
|
name: 'active',
|
|
label: t`Active`,
|
|
description: t`Show active parts`
|
|
},
|
|
{
|
|
name: 'locked',
|
|
label: t`Locked`,
|
|
description: t`Show locked parts`
|
|
},
|
|
{
|
|
name: 'assembly',
|
|
label: t`Assembly`,
|
|
description: t`Show assembly parts`
|
|
}
|
|
];
|
|
}, []);
|
|
|
|
const tableColumns: TableColumn[] = useMemo(() => {
|
|
const partColumns: TableColumn[] = [
|
|
{
|
|
accessor: 'name',
|
|
sortable: true,
|
|
switchable: false,
|
|
noWrap: true,
|
|
render: (record: any) => PartColumn(record)
|
|
},
|
|
DescriptionColumn({}),
|
|
{
|
|
accessor: 'IPN',
|
|
sortable: true
|
|
},
|
|
{
|
|
accessor: 'total_in_stock',
|
|
sortable: true
|
|
}
|
|
];
|
|
|
|
return [...partColumns, ...parameterColumns];
|
|
}, [parameterColumns]);
|
|
|
|
return (
|
|
<>
|
|
{addParameter.modal}
|
|
{editParameter.modal}
|
|
<InvenTreeTable
|
|
url={apiUrl(ApiEndpoints.part_list)}
|
|
tableState={table}
|
|
columns={tableColumns}
|
|
props={{
|
|
enableDownload: false,
|
|
params: {
|
|
category: categoryId,
|
|
cascade: true,
|
|
category_detail: true,
|
|
parameters: true
|
|
},
|
|
modelType: ModelType.part,
|
|
tableFilters: tableFilters
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|