mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Parameter table editing (#6760)
* table updates - Store page data in tablestate - Store record count data in table state * Expose "records" to table state * edit or add parameters from ParametricPartTable - Click on parameter cells to edit / add * Mark fields as disabled * Update table - Display edit icon on hover * Fix callback
This commit is contained in:
parent
45ecebaf19
commit
0b7bfdb4a4
@ -28,6 +28,12 @@ export type TableState = {
|
|||||||
setHiddenColumns: (columns: string[]) => void;
|
setHiddenColumns: (columns: string[]) => void;
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
setSearchTerm: (term: string) => void;
|
setSearchTerm: (term: string) => void;
|
||||||
|
recordCount: number;
|
||||||
|
setRecordCount: (count: number) => void;
|
||||||
|
page: number;
|
||||||
|
setPage: (page: number) => void;
|
||||||
|
records: any[];
|
||||||
|
setRecords: (records: any[]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,6 +77,12 @@ export function useTable(tableName: string): TableState {
|
|||||||
setSelectedRecords([]);
|
setSelectedRecords([]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Total record count
|
||||||
|
const [recordCount, setRecordCount] = useState<number>(0);
|
||||||
|
|
||||||
|
// Pagination data
|
||||||
|
const [page, setPage] = useState<number>(1);
|
||||||
|
|
||||||
// A list of hidden columns, saved to local storage
|
// A list of hidden columns, saved to local storage
|
||||||
const [hiddenColumns, setHiddenColumns] = useLocalStorage<string[]>({
|
const [hiddenColumns, setHiddenColumns] = useLocalStorage<string[]>({
|
||||||
key: `inventree-hidden-table-columns-${tableName}`,
|
key: `inventree-hidden-table-columns-${tableName}`,
|
||||||
@ -80,6 +92,9 @@ export function useTable(tableName: string): TableState {
|
|||||||
// Search term
|
// Search term
|
||||||
const [searchTerm, setSearchTerm] = useState<string>('');
|
const [searchTerm, setSearchTerm] = useState<string>('');
|
||||||
|
|
||||||
|
// Table records
|
||||||
|
const [records, setRecords] = useState<any[]>([]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tableKey,
|
tableKey,
|
||||||
refreshTable,
|
refreshTable,
|
||||||
@ -94,6 +109,12 @@ export function useTable(tableName: string): TableState {
|
|||||||
hiddenColumns,
|
hiddenColumns,
|
||||||
setHiddenColumns,
|
setHiddenColumns,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
setSearchTerm
|
setSearchTerm,
|
||||||
|
recordCount,
|
||||||
|
setRecordCount,
|
||||||
|
page,
|
||||||
|
setPage,
|
||||||
|
records,
|
||||||
|
setRecords
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -16,4 +16,5 @@ export type TableColumn<T = any> = {
|
|||||||
ellipsis?: boolean; // Whether the column should be ellipsized
|
ellipsis?: boolean; // Whether the column should be ellipsized
|
||||||
textAlignment?: 'left' | 'center' | 'right'; // The text alignment of the column
|
textAlignment?: 'left' | 'center' | 'right'; // The text alignment of the column
|
||||||
cellsStyle?: any; // The style of the cells in the column
|
cellsStyle?: any; // The style of the cells in the column
|
||||||
|
extra?: any; // Extra data to pass to the render function
|
||||||
};
|
};
|
||||||
|
@ -14,8 +14,12 @@ import { modals } from '@mantine/modals';
|
|||||||
import { showNotification } from '@mantine/notifications';
|
import { showNotification } from '@mantine/notifications';
|
||||||
import { IconFilter, IconRefresh, IconTrash } from '@tabler/icons-react';
|
import { IconFilter, IconRefresh, IconTrash } from '@tabler/icons-react';
|
||||||
import { IconBarcode, IconPrinter } from '@tabler/icons-react';
|
import { IconBarcode, IconPrinter } from '@tabler/icons-react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { dataTagSymbol, useQuery } from '@tanstack/react-query';
|
||||||
import { DataTable, DataTableSortStatus } from 'mantine-datatable';
|
import {
|
||||||
|
DataTable,
|
||||||
|
DataTableCellClickHandler,
|
||||||
|
DataTableSortStatus
|
||||||
|
} from 'mantine-datatable';
|
||||||
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
|
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
@ -57,6 +61,7 @@ const defaultPageSize: number = 25;
|
|||||||
* @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format)
|
* @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format)
|
||||||
* @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions
|
* @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions
|
||||||
* @param onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked
|
* @param onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked
|
||||||
|
* @param onCellClick : (event: any, record: any, recordIndex: number, column: any, columnIndex: number) => void - Callback function when a cell is clicked
|
||||||
*/
|
*/
|
||||||
export type InvenTreeTableProps<T = any> = {
|
export type InvenTreeTableProps<T = any> = {
|
||||||
params?: any;
|
params?: any;
|
||||||
@ -79,6 +84,7 @@ export type InvenTreeTableProps<T = any> = {
|
|||||||
dataFormatter?: (data: any) => any;
|
dataFormatter?: (data: any) => any;
|
||||||
rowActions?: (record: T) => RowAction[];
|
rowActions?: (record: T) => RowAction[];
|
||||||
onRowClick?: (record: T, index: number, event: any) => void;
|
onRowClick?: (record: T, index: number, event: any) => void;
|
||||||
|
onCellClick?: DataTableCellClickHandler<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,15 +266,12 @@ export function InvenTreeTable<T = any>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
|
|
||||||
// Filter list visibility
|
// Filter list visibility
|
||||||
const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
|
const [filtersVisible, setFiltersVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
// Reset the pagination state when the search term changes
|
// Reset the pagination state when the search term changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPage(1);
|
tableState.setPage(1);
|
||||||
}, [tableState.searchTerm]);
|
}, [tableState.searchTerm]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -295,7 +298,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
if (tableProps.enablePagination && paginate) {
|
if (tableProps.enablePagination && paginate) {
|
||||||
let pageSize = tableProps.pageSize ?? defaultPageSize;
|
let pageSize = tableProps.pageSize ?? defaultPageSize;
|
||||||
queryParams.limit = pageSize;
|
queryParams.limit = pageSize;
|
||||||
queryParams.offset = (page - 1) * pageSize;
|
queryParams.offset = (tableState.page - 1) * pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ordering
|
// Ordering
|
||||||
@ -356,7 +359,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSortStatusChange = (status: DataTableSortStatus) => {
|
const handleSortStatusChange = (status: DataTableSortStatus) => {
|
||||||
setPage(1);
|
tableState.setPage(1);
|
||||||
setSortStatus(status);
|
setSortStatus(status);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -388,7 +391,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
results = [];
|
results = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecordCount(response.data?.count ?? results.length);
|
tableState.setRecordCount(response.data?.count ?? results.length);
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
case 400:
|
case 400:
|
||||||
@ -420,7 +423,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
|
|
||||||
const { data, isFetching, refetch } = useQuery({
|
const { data, isFetching, refetch } = useQuery({
|
||||||
queryKey: [
|
queryKey: [
|
||||||
page,
|
tableState.page,
|
||||||
props.params,
|
props.params,
|
||||||
sortStatus.columnAccessor,
|
sortStatus.columnAccessor,
|
||||||
sortStatus.direction,
|
sortStatus.direction,
|
||||||
@ -433,7 +436,10 @@ export function InvenTreeTable<T = any>({
|
|||||||
refetchOnMount: true
|
refetchOnMount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const [recordCount, setRecordCount] = useState<number>(0);
|
// Update tableState.records when new data received
|
||||||
|
useEffect(() => {
|
||||||
|
tableState.setRecords(data ?? []);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
// Callback function to delete the selected records in the table
|
// Callback function to delete the selected records in the table
|
||||||
const deleteSelectedRecords = useCallback(() => {
|
const deleteSelectedRecords = useCallback(() => {
|
||||||
@ -597,10 +603,10 @@ export function InvenTreeTable<T = any>({
|
|||||||
pinLastColumn={tableProps.rowActions != undefined}
|
pinLastColumn={tableProps.rowActions != undefined}
|
||||||
idAccessor={tableProps.idAccessor}
|
idAccessor={tableProps.idAccessor}
|
||||||
minHeight={300}
|
minHeight={300}
|
||||||
totalRecords={recordCount}
|
totalRecords={tableState.recordCount}
|
||||||
recordsPerPage={tableProps.pageSize ?? defaultPageSize}
|
recordsPerPage={tableProps.pageSize ?? defaultPageSize}
|
||||||
page={page}
|
page={tableState.page}
|
||||||
onPageChange={setPage}
|
onPageChange={tableState.setPage}
|
||||||
sortStatus={sortStatus}
|
sortStatus={sortStatus}
|
||||||
onSortStatusChange={handleSortStatusChange}
|
onSortStatusChange={handleSortStatusChange}
|
||||||
selectedRecords={
|
selectedRecords={
|
||||||
@ -614,9 +620,10 @@ export function InvenTreeTable<T = any>({
|
|||||||
rowExpansion={tableProps.rowExpansion}
|
rowExpansion={tableProps.rowExpansion}
|
||||||
fetching={isFetching}
|
fetching={isFetching}
|
||||||
noRecordsText={missingRecordsText}
|
noRecordsText={missingRecordsText}
|
||||||
records={data}
|
records={tableState.records}
|
||||||
columns={dataColumns}
|
columns={dataColumns}
|
||||||
onRowClick={tableProps.onRowClick}
|
onRowClick={tableProps.onRowClick}
|
||||||
|
onCellClick={tableProps.onCellClick}
|
||||||
defaultColumnProps={{
|
defaultColumnProps={{
|
||||||
noWrap: true,
|
noWrap: true,
|
||||||
textAlignment: 'left',
|
textAlignment: 'left',
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { ActionIcon, Group, Text, Tooltip } from '@mantine/core';
|
||||||
|
import { useHover } from '@mantine/hooks';
|
||||||
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
|
import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
|
||||||
import { YesNoButton } from '../../components/items/YesNoButton';
|
import { YesNoButton } from '../../components/items/YesNoButton';
|
||||||
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 { getDetailUrl } from '../../functions/urls';
|
import { getDetailUrl } from '../../functions/urls';
|
||||||
|
import {
|
||||||
|
useCreateApiFormModal,
|
||||||
|
useEditApiFormModal
|
||||||
|
} 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 { useUserState } from '../../states/UserState';
|
||||||
@ -16,6 +25,73 @@ import { DescriptionColumn, PartColumn } from '../ColumnRenderers';
|
|||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { TableHoverCard } from '../TableHoverCard';
|
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) => {
|
||||||
|
event?.preventDefault();
|
||||||
|
event?.stopPropagation();
|
||||||
|
event?.nativeEvent?.stopImmediatePropagation();
|
||||||
|
onEdit();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Group grow ref={ref} position="apart">
|
||||||
|
<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}>
|
||||||
|
<IconEdit />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function ParametricPartTable({
|
export default function ParametricPartTable({
|
||||||
categoryId
|
categoryId
|
||||||
}: {
|
}: {
|
||||||
@ -40,6 +116,73 @@ export default function ParametricPartTable({
|
|||||||
refetchOnMount: true
|
refetchOnMount: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [selectedPart, setSelectedPart] = useState<number>(0);
|
||||||
|
const [selectedTemplate, setSelectedTemplate] = useState<number>(0);
|
||||||
|
const [selectedParameter, setSelectedParameter] = useState<number>(0);
|
||||||
|
|
||||||
|
const partParameterFields: ApiFormFieldSet = useMemo(() => {
|
||||||
|
return {
|
||||||
|
part: {
|
||||||
|
disabled: true
|
||||||
|
},
|
||||||
|
template: {
|
||||||
|
disabled: true
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addParameter = useCreateApiFormModal({
|
||||||
|
url: ApiEndpoints.part_parameter_list,
|
||||||
|
title: t`Add Part Parameter`,
|
||||||
|
fields: partParameterFields,
|
||||||
|
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: partParameterFields,
|
||||||
|
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(() => {
|
const parameterColumns: TableColumn[] = useMemo(() => {
|
||||||
let data = categoryParmeters.data ?? [];
|
let data = categoryParmeters.data ?? [];
|
||||||
|
|
||||||
@ -54,43 +197,33 @@ export default function ParametricPartTable({
|
|||||||
accessor: `parameter_${template.pk}`,
|
accessor: `parameter_${template.pk}`,
|
||||||
title: title,
|
title: title,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
render: (record: any) => {
|
extra: {
|
||||||
// Find matching template parameter
|
template: template.pk
|
||||||
let parameter = record.parameters?.find(
|
},
|
||||||
(p: any) => p.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) {
|
if (parameter) {
|
||||||
return '-';
|
setSelectedParameter(parameter.pk);
|
||||||
}
|
editParameter.open();
|
||||||
|
} else {
|
||||||
let extra: any[] = [];
|
addParameter.open();
|
||||||
|
}
|
||||||
if (
|
}}
|
||||||
template.units &&
|
/>
|
||||||
parameter.data_numeric &&
|
)
|
||||||
parameter.data_numeric != parameter.data
|
|
||||||
) {
|
|
||||||
extra.push(`${parameter.data_numeric} [${template.units}]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let value: any = parameter.data;
|
|
||||||
|
|
||||||
if (template?.checkbox) {
|
|
||||||
value = <YesNoButton value={parameter.data} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableHoverCard
|
|
||||||
value={value}
|
|
||||||
extra={extra}
|
|
||||||
title={t`Internal Units`}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [categoryParmeters.data]);
|
}, [user, categoryParmeters.data]);
|
||||||
|
|
||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
const partColumns: TableColumn[] = [
|
const partColumns: TableColumn[] = [
|
||||||
@ -111,25 +244,58 @@ export default function ParametricPartTable({
|
|||||||
return [...partColumns, ...parameterColumns];
|
return [...partColumns, ...parameterColumns];
|
||||||
}, [parameterColumns]);
|
}, [parameterColumns]);
|
||||||
|
|
||||||
|
// Callback when a parameter cell is clicked - either edit or add a new parameter
|
||||||
|
const handleCellClick = useCallback(
|
||||||
|
(record: any, column: any) => {
|
||||||
|
let template_id = column?.extra?.template;
|
||||||
|
|
||||||
|
if (!template_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedPart(record.pk);
|
||||||
|
setSelectedTemplate(template_id);
|
||||||
|
|
||||||
|
// Find the associated parameter
|
||||||
|
let parameter = record?.parameters?.find(
|
||||||
|
(p: any) => p.template == template_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parameter) {
|
||||||
|
// Parameter exists - open edit dialog
|
||||||
|
setSelectedParameter(parameter.pk);
|
||||||
|
editParameter.open();
|
||||||
|
} else {
|
||||||
|
// Parameter does not exist - create it!
|
||||||
|
addParameter.open();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<>
|
||||||
url={apiUrl(ApiEndpoints.part_list)}
|
{addParameter.modal}
|
||||||
tableState={table}
|
{editParameter.modal}
|
||||||
columns={tableColumns}
|
<InvenTreeTable
|
||||||
props={{
|
url={apiUrl(ApiEndpoints.part_list)}
|
||||||
enableDownload: false,
|
tableState={table}
|
||||||
params: {
|
columns={tableColumns}
|
||||||
category: categoryId,
|
props={{
|
||||||
cascade: true,
|
enableDownload: false,
|
||||||
category_detail: true,
|
params: {
|
||||||
parameters: true
|
category: categoryId,
|
||||||
},
|
cascade: true,
|
||||||
onRowClick: (record) => {
|
category_detail: true,
|
||||||
if (record.pk) {
|
parameters: true
|
||||||
navigate(getDetailUrl(ModelType.part, record.pk));
|
},
|
||||||
|
onRowClick: (record) => {
|
||||||
|
if (record.pk) {
|
||||||
|
navigate(getDetailUrl(ModelType.part, record.pk));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user