Add useTable hook (#6000)

* Add new hook - useTable

- Will replace useTableRefresh
- More extensible (further functionality to follow)
- Pass entire state through to final table
- Defined interface for return type

* Update BomTable

* Update UsedInTable

* Refactor attachment table

* Update remaining tables

* Clean StockItemTable

* Fix NotificationTable

* Remove unused import
This commit is contained in:
Oliver 2023-11-28 23:15:08 +11:00 committed by GitHub
parent c7bf1348e7
commit c3aeadda4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 160 additions and 168 deletions

View File

@ -9,6 +9,7 @@ import { DataTable, DataTableSortStatus } from 'mantine-datatable';
import { Fragment, useEffect, useMemo, useState } from 'react';
import { api } from '../../App';
import { TableState } from '../../hooks/UseTable';
import { ButtonMenu } from '../buttons/ButtonMenu';
import { TableColumn } from './Column';
import { TableColumnSelect } from './ColumnSelect';
@ -25,8 +26,7 @@ const defaultPageSize: number = 25;
* Set of optional properties which can be passed to an InvenTreeTable component
*
* @param params : any - Base query parameters
* @param tableKey : string - Unique key for the table (used for local storage)
* @param refreshId : string - Unique ID for the table (used to trigger a refresh)
* @param tableState : TableState - State manager for the table
* @param defaultSortColumn : string - Default column to sort by
* @param noRecordsText : string - Text to display when no records are found
* @param enableDownload : boolean - Enable download actions
@ -92,18 +92,19 @@ const defaultInvenTreeTableProps: InvenTreeTableProps = {
*/
export function InvenTreeTable<T = any>({
url,
tableKey,
tableState,
columns,
props
}: {
url: string;
tableKey: string;
tableState: TableState;
columns: TableColumn<T>[];
props: InvenTreeTableProps<T>;
}) {
// Use the first part of the table key as the table name
const tableName: string = useMemo(() => {
return tableKey.split('-')[0];
let key = tableState?.tableKey ?? 'table';
return key.split('-')[0];
}, []);
// Build table properties based on provided props (and default props)
@ -411,14 +412,12 @@ export function InvenTreeTable<T = any>({
const [recordCount, setRecordCount] = useState<number>(0);
/*
* Reload the table whenever the refetch changes
* Reload the table whenever the tableKey changes
* this allows us to programmatically refresh the table
*
* Implement this using the custom useTableRefresh hook
*/
useEffect(() => {
refetch();
}, [tableKey, props.params]);
}, [tableState?.tableKey, props.params]);
return (
<>

View File

@ -12,7 +12,7 @@ import { ApiPaths } from '../../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles';
import { bomItemFields } from '../../../forms/BomForms';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { Thumbnail } from '../../images/Thumbnail';
@ -51,7 +51,7 @@ export function BomTable({
const user = useUserState();
const { tableKey, refreshTable } = useTableRefresh('bom');
const table = useTable('bom');
const tableColumns: TableColumn[] = useMemo(() => {
return [
@ -289,7 +289,7 @@ export function BomTable({
title: t`Edit Bom Item`,
fields: bomItemFields(),
successMessage: t`Bom item updated`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}
})
@ -305,7 +305,7 @@ export function BomTable({
pk: record.pk,
title: t`Delete Bom Item`,
successMessage: t`Bom item deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to remove this BOM item?`}</Text>
)
@ -322,7 +322,7 @@ export function BomTable({
return (
<InvenTreeTable
url={apiUrl(ApiPaths.bom_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { ThumbnailHoverCard } from '../../images/Thumbnail';
import { TableColumn } from '../Column';
@ -22,7 +22,7 @@ export function UsedInTable({
}) {
const navigate = useNavigate();
const { tableKey } = useTableRefresh('usedin');
const table = useTable('usedin');
const tableColumns: TableColumn[] = useMemo(() => {
return [
@ -86,7 +86,7 @@ export function UsedInTable({
return (
<InvenTreeTable
url={apiUrl(ApiPaths.bom_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom';
import { renderDate } from '../../../defaults/formatters';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { ThumbnailHoverCard } from '../../images/Thumbnail';
import { ProgressBar } from '../../items/ProgressBar';
@ -128,12 +128,12 @@ export function BuildOrderTable({ params = {} }: { params?: any }) {
const navigate = useNavigate();
const { tableKey, refreshTable } = useTableRefresh('buildorder');
const table = useTable('buildorder');
return (
<InvenTreeTable
url={apiUrl(ApiPaths.build_order_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
enableDownload: true,

View File

@ -13,7 +13,7 @@ import {
deleteAttachment,
editAttachment
} from '../../../forms/AttachmentForms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { AttachmentLink } from '../../items/AttachmentLink';
import { TableColumn } from '../Column';
@ -82,7 +82,7 @@ export function AttachmentTable({
pk: number;
model: string;
}): ReactNode {
const { tableKey, refreshTable } = useTableRefresh(`${model}-attachments`);
const table = useTable(`${model}-attachments`);
const tableColumns = useMemo(() => attachmentTableColumns(), []);
@ -122,7 +122,7 @@ export function AttachmentTable({
model: model,
pk: record.pk,
attachmentType: record.attachment ? 'file' : 'link',
callback: refreshTable
callback: table.refreshTable
});
}
})
@ -136,7 +136,7 @@ export function AttachmentTable({
deleteAttachment({
endpoint: endpoint,
pk: record.pk,
callback: refreshTable
callback: table.refreshTable
});
}
})
@ -162,7 +162,7 @@ export function AttachmentTable({
color: 'green'
});
refreshTable();
table.refreshTable();
return response;
})
@ -192,7 +192,7 @@ export function AttachmentTable({
model: model,
pk: pk,
attachmentType: 'file',
callback: refreshTable
callback: table.refreshTable
});
}}
>
@ -211,7 +211,7 @@ export function AttachmentTable({
model: model,
pk: pk,
attachmentType: 'link',
callback: refreshTable
callback: table.refreshTable
});
}}
>
@ -230,7 +230,7 @@ export function AttachmentTable({
<InvenTreeTable
key="attachment-table"
url={url}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
noRecordsText: t`No attachments found`,

View File

@ -4,7 +4,7 @@ import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import { DescriptionColumn } from '../ColumnRenderers';
@ -21,7 +21,7 @@ export function CompanyTable({
params?: any;
path?: string;
}) {
const { tableKey } = useTableRefresh('company');
const table = useTable('company');
const navigate = useNavigate();
@ -56,7 +56,7 @@ export function CompanyTable({
return (
<InvenTreeTable
url={apiUrl(ApiPaths.company_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
params: {

View File

@ -2,6 +2,7 @@ import { t } from '@lingui/macro';
import { useMemo } from 'react';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { TableState } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable';
@ -9,11 +10,11 @@ import { RowAction } from '../RowActions';
export function NotificationTable({
params,
tableKey,
tableState,
actions
}: {
params: any;
tableKey: string;
tableState: TableState;
actions: (record: any) => RowAction[];
}) {
const columns: TableColumn[] = useMemo(() => {
@ -42,7 +43,7 @@ export function NotificationTable({
return (
<InvenTreeTable
url={apiUrl(ApiPaths.notifications_list)}
tableKey={tableKey}
tableState={tableState}
columns={columns}
props={{
rowActions: actions,

View File

@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { TableColumn } from '../Column';
import { DescriptionColumn } from '../ColumnRenderers';
@ -15,7 +15,7 @@ import { InvenTreeTable } from '../InvenTreeTable';
export function PartCategoryTable({ params = {} }: { params?: any }) {
const navigate = useNavigate();
const { tableKey, refreshTable } = useTableRefresh('partcategory');
const table = useTable('partcategory');
const tableColumns: TableColumn[] = useMemo(() => {
return [
@ -42,7 +42,7 @@ export function PartCategoryTable({ params = {} }: { params?: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.category_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
enableDownload: true,

View File

@ -9,7 +9,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
@ -23,7 +23,7 @@ import { RowDeleteAction, RowEditAction } from '../RowActions';
* Construct a table listing parameters for a given part
*/
export function PartParameterTable({ partId }: { partId: any }) {
const { tableKey, refreshTable } = useTableRefresh('part-parameters');
const table = useTable('part-parameters');
const user = useUserState();
@ -124,7 +124,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
data: {}
},
successMessage: t`Part parameter updated`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}
})
@ -139,7 +139,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
pk: record.pk,
title: t`Delete Part Parameter`,
successMessage: t`Part parameter deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to remove this parameter?`}</Text>
)
@ -170,7 +170,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
data: {}
},
successMessage: t`Part parameter added`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}, [partId]);
@ -189,7 +189,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.part_parameter_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
rowActions: rowActions,

View File

@ -10,7 +10,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
@ -19,9 +19,7 @@ import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions';
export function PartParameterTemplateTable() {
const { tableKey, refreshTable } = useTableRefresh(
'part-parameter-templates'
);
const table = useTable('part-parameter-templates');
const user = useUserState();
@ -67,7 +65,7 @@ export function PartParameterTemplateTable() {
title: t`Edit Parameter Template`,
fields: partParameterTemplateFields(),
successMessage: t`Parameter template updated`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}
}),
@ -79,7 +77,7 @@ export function PartParameterTemplateTable() {
pk: record.pk,
title: t`Delete Parameter Template`,
successMessage: t`Parameter template deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: <Text>{t`Remove parameter template`}</Text>
});
}
@ -95,7 +93,7 @@ export function PartParameterTemplateTable() {
title: t`Create Parameter Template`,
fields: partParameterTemplateFields(),
successMessage: t`Parameter template created`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}, []);
@ -112,7 +110,7 @@ export function PartParameterTemplateTable() {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.part_parameter_template_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
rowActions: rowActions,

View File

@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { shortenString } from '../../../functions/tables';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import { TableColumn } from '../Column';
@ -265,14 +265,14 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) {
const tableColumns = useMemo(() => partTableColumns(), []);
const tableFilters = useMemo(() => partTableFilters(), []);
const { tableKey, refreshTable } = useTableRefresh('part');
const table = useTable('part-list');
const navigate = useNavigate();
return (
<InvenTreeTable
url={apiUrl(ApiPaths.part_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
...props,

View File

@ -7,7 +7,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles';
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { Thumbnail } from '../../images/Thumbnail';
@ -19,7 +19,7 @@ import { RowDeleteAction } from '../RowActions';
* Construct a table listing related parts for a given part
*/
export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
const { tableKey, refreshTable } = useTableRefresh('relatedparts');
const table = useTable('relatedparts');
const navigate = useNavigate();
@ -80,7 +80,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
}
},
successMessage: t`Related part added`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}, [partId]);
@ -115,7 +115,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
preFormContent: (
<Text>{t`Are you sure you want to remove this relationship?`}</Text>
),
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}
})
@ -127,7 +127,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.related_part_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -11,7 +11,7 @@ import { useCallback, useMemo } from 'react';
import { api } from '../../../App';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { StylishText } from '../../items/StylishText';
import { TableColumn } from '../Column';
@ -49,7 +49,7 @@ function PluginIcon(plugin: any) {
* Table displaying list of available plugins
*/
export function PluginListTable({ props }: { props: InvenTreeTableProps }) {
const { tableKey, refreshTable } = useTableRefresh('plugin');
const table = useTable('plugin');
const pluginTableColumns: TableColumn[] = useMemo(
() => [
@ -147,7 +147,7 @@ export function PluginListTable({ props }: { props: InvenTreeTableProps }) {
api
.patch(url, { active: active })
.then(() => {
refreshTable();
table.refreshTable();
notifications.hide(id);
notifications.show({
title: t`Plugin updated`,
@ -203,7 +203,7 @@ export function PluginListTable({ props }: { props: InvenTreeTableProps }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.plugin_list)}
tableKey={tableKey}
tableState={table}
columns={pluginTableColumns}
props={{
...props,

View File

@ -8,7 +8,7 @@ import { ApiPaths } from '../../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles';
import { purchaseOrderLineItemFields } from '../../../forms/PurchaseOrderForms';
import { openCreateApiForm, openEditApiForm } from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { ActionButton } from '../../buttons/ActionButton';
@ -39,9 +39,7 @@ export function PurchaseOrderLineItemTable({
orderId: number;
params?: any;
}) {
const { tableKey, refreshTable } = useTableRefresh(
'purchase-order-line-item'
);
const table = useTable('purchase-order-line-item');
const user = useUserState();
@ -75,7 +73,7 @@ export function PurchaseOrderLineItemTable({
pk: record.pk,
title: t`Edit Line Item`,
fields: fields,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Line item updated`
});
}
@ -226,7 +224,7 @@ export function PurchaseOrderLineItemTable({
create: true,
orderId: orderId
}),
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Line item added`
});
}, [orderId]);
@ -251,7 +249,7 @@ export function PurchaseOrderLineItemTable({
return (
<InvenTreeTable
url={apiUrl(ApiPaths.purchase_order_line_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
enableSelection: true,

View File

@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import {
@ -25,7 +25,7 @@ import { InvenTreeTable } from '../InvenTreeTable';
export function PurchaseOrderTable({ params }: { params?: any }) {
const navigate = useNavigate();
const { tableKey } = useTableRefresh('purchase-order');
const table = useTable('purchase-order');
// TODO: Custom filters
@ -76,7 +76,7 @@ export function PurchaseOrderTable({ params }: { params?: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.purchase_order_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -6,8 +6,8 @@ import { ApiPaths } from '../../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles';
import { useSupplierPartFields } from '../../../forms/CompanyForms';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useCreateApiFormModal } from '../../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
@ -23,7 +23,7 @@ import { TableHoverCard } from '../TableHoverCard';
*/
export function SupplierPartTable({ params }: { params: any }): ReactNode {
const { tableKey, refreshTable } = useTableRefresh('supplierparts');
const table = useTable('supplierparts');
const user = useUserState();
@ -162,7 +162,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
url: ApiPaths.supplier_part_list,
title: t`Add Supplier Part`,
fields: addSupplierPartFields,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Supplier part created`
});
@ -195,7 +195,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
pk: record.pk,
title: t`Edit Supplier Part`,
fields: editSupplierPartFields,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Supplier part updated`
});
}
@ -209,7 +209,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
pk: record.pk,
title: t`Delete Supplier Part`,
successMessage: t`Supplier part deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to remove this supplier part?`}</Text>
)
@ -226,7 +226,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
{addSupplierPartModal}
<InvenTreeTable
url={apiUrl(ApiPaths.supplier_part_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import {
@ -19,7 +19,7 @@ import {
import { InvenTreeTable } from '../InvenTreeTable';
export function ReturnOrderTable({ params }: { params?: any }) {
const { tableKey } = useTableRefresh('return-orders');
const table = useTable('return-orders');
const navigate = useNavigate();
@ -74,7 +74,7 @@ export function ReturnOrderTable({ params }: { params?: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.return_order_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import {
@ -20,7 +20,7 @@ import {
import { InvenTreeTable } from '../InvenTreeTable';
export function SalesOrderTable({ params }: { params?: any }) {
const { tableKey } = useTableRefresh('sales-order');
const table = useTable('sales-order');
const navigate = useNavigate();
@ -73,7 +73,7 @@ export function SalesOrderTable({ params }: { params?: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.sales_order_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
params: {

View File

@ -5,7 +5,7 @@ import { useCallback, useMemo } from 'react';
import { api } from '../../../App';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { ActionButton } from '../../buttons/ActionButton';
import { InvenTreeTable } from '../InvenTreeTable';
@ -14,7 +14,7 @@ import { InvenTreeTable } from '../InvenTreeTable';
* Table for displaying available currencies
*/
export function CurrencyTable() {
const { tableKey, refreshTable } = useTableRefresh('currency');
const table = useTable('currency');
const columns = useMemo(() => {
return [
@ -35,7 +35,7 @@ export function CurrencyTable() {
api
.post(apiUrl(ApiPaths.currency_refresh), {})
.then(() => {
refreshTable();
table.refreshTable();
showNotification({
message: t`Exchange rates updated`,
color: 'green'
@ -63,7 +63,7 @@ export function CurrencyTable() {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.currency_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
customActionGroups: tableActions,

View File

@ -9,7 +9,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
@ -21,7 +21,7 @@ import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
* Table for displaying list of custom physical units
*/
export function CustomUnitsTable() {
const { tableKey, refreshTable } = useTableRefresh('custom-units');
const table = useTable('custom-units');
const user = useUserState();
@ -63,7 +63,7 @@ export function CustomUnitsTable() {
definition: {},
symbol: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Custom unit updated`
});
}
@ -76,7 +76,7 @@ export function CustomUnitsTable() {
pk: record.pk,
title: t`Delete custom unit`,
successMessage: t`Custom unit deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to remove this custom unit?`}</Text>
)
@ -98,7 +98,7 @@ export function CustomUnitsTable() {
symbol: {}
},
successMessage: t`Custom unit created`,
onFormSuccess: refreshTable
onFormSuccess: table.refreshTable
});
}, []);
@ -116,7 +116,7 @@ export function CustomUnitsTable() {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.custom_unit_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
rowActions: rowActions,

View File

@ -8,7 +8,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { TableColumn } from '../Column';
@ -19,7 +19,7 @@ import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
* Table for displaying list of groups
*/
export function GroupTable() {
const { tableKey, refreshTable } = useTableRefresh('groups');
const table = useTable('groups');
const columns: TableColumn[] = useMemo(() => {
return [
@ -42,7 +42,7 @@ export function GroupTable() {
fields: {
name: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Group updated`
});
}
@ -54,7 +54,7 @@ export function GroupTable() {
pk: record.pk,
title: t`Delete group`,
successMessage: t`Group deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to delete this group?`}</Text>
)
@ -69,7 +69,7 @@ export function GroupTable() {
url: ApiPaths.group_list,
title: t`Add group`,
fields: { name: {} },
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Added group`
});
}, []);
@ -91,7 +91,7 @@ export function GroupTable() {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.group_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
rowActions: rowActions,

View File

@ -9,7 +9,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { useUserState } from '../../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
@ -22,7 +22,7 @@ import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
* Table for displaying list of project codes
*/
export function ProjectCodeTable() {
const { tableKey, refreshTable } = useTableRefresh('project-code');
const table = useTable('project-codes');
const user = useUserState();
@ -53,7 +53,7 @@ export function ProjectCodeTable() {
description: {},
responsible: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Project code updated`
});
}
@ -66,7 +66,7 @@ export function ProjectCodeTable() {
pk: record.pk,
title: t`Delete project code`,
successMessage: t`Project code deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to remove this project code?`}</Text>
)
@ -87,7 +87,7 @@ export function ProjectCodeTable() {
description: {},
responsible: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Added project code`
});
}, []);
@ -105,7 +105,7 @@ export function ProjectCodeTable() {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.project_code_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
rowActions: rowActions,

View File

@ -9,7 +9,7 @@ import {
openDeleteApiForm,
openEditApiForm
} from '../../../functions/forms';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { TableColumn } from '../Column';
@ -39,7 +39,7 @@ export interface UserDetailI {
* Table for displaying list of users
*/
export function UserTable() {
const { tableKey, refreshTable } = useTableRefresh('users');
const table = useTable('users');
const [opened, { open, close }] = useDisclosure(false);
const [userDetail, setUserDetail] = useState<UserDetailI>();
@ -103,7 +103,7 @@ export function UserTable() {
first_name: {},
last_name: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`User updated`
});
}
@ -115,7 +115,7 @@ export function UserTable() {
pk: record.pk,
title: t`Delete user`,
successMessage: t`User deleted`,
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
preFormContent: (
<Text>{t`Are you sure you want to delete this user?`}</Text>
)
@ -135,7 +135,7 @@ export function UserTable() {
first_name: {},
last_name: {}
},
onFormSuccess: refreshTable,
onFormSuccess: table.refreshTable,
successMessage: t`Added user`
});
}, []);
@ -155,12 +155,12 @@ export function UserTable() {
<UserDrawer
opened={opened}
close={close}
refreshTable={refreshTable}
refreshTable={table.refreshTable}
userDetail={userDetail}
/>
<InvenTreeTable
url={apiUrl(ApiPaths.user_list)}
tableKey={tableKey}
tableState={table}
columns={columns}
props={{
rowActions: rowActions,

View File

@ -6,13 +6,12 @@ import { useNavigate } from 'react-router-dom';
import { formatCurrency, renderDate } from '../../../defaults/formatters';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail';
import { TableColumn } from '../Column';
import { StatusColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter';
import { RowAction } from '../RowActions';
import { TableHoverCard } from '../TableHoverCard';
import { InvenTreeTable } from './../InvenTreeTable';
@ -172,7 +171,7 @@ function stockItemTableColumns(): TableColumn[] {
return (
<TableHoverCard
value={
<Group spacing="xs" position="left">
<Group spacing="xs" position="left" noWrap={true}>
<Text color={color}>{text}</Text>
{part.units && (
<Text size="xs" color={color}>
@ -264,27 +263,19 @@ export function StockItemTable({ params = {} }: { params?: any }) {
let tableColumns = useMemo(() => stockItemTableColumns(), []);
let tableFilters = useMemo(() => stockItemTableFilters(), []);
const { tableKey, refreshTable } = useTableRefresh('stockitem');
function stockItemRowActions(record: any): RowAction[] {
let actions: RowAction[] = [];
// TODO: Custom row actions for stock table
return actions;
}
const table = useTable('stockitems');
const navigate = useNavigate();
return (
<InvenTreeTable
url={apiUrl(ApiPaths.stock_item_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
enableDownload: true,
enableSelection: true,
customFilters: tableFilters,
rowActions: stockItemRowActions,
onRowClick: (record) => navigate(`/stock/item/${record.pk}`),
params: {
...params,

View File

@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { ApiPaths } from '../../../enums/ApiEndpoints';
import { useTableRefresh } from '../../../hooks/TableRefresh';
import { useTable } from '../../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState';
import { YesNoButton } from '../../items/YesNoButton';
import { TableColumn } from '../Column';
@ -14,7 +14,7 @@ import { InvenTreeTable } from '../InvenTreeTable';
* Stock location table
*/
export function StockLocationTable({ params = {} }: { params?: any }) {
const { tableKey, refreshTable } = useTableRefresh('stocklocation');
const table = useTable('stocklocation');
const navigate = useNavigate();
@ -64,7 +64,7 @@ export function StockLocationTable({ params = {} }: { params?: any }) {
return (
<InvenTreeTable
url={apiUrl(ApiPaths.stock_location_list)}
tableKey={tableKey}
tableState={table}
columns={tableColumns}
props={{
enableDownload: true,

View File

@ -1,29 +0,0 @@
import { randomId } from '@mantine/hooks';
import { useCallback, useState } from 'react';
/**
* Custom hook for refreshing an InvenTreeTable externally
* Returns a unique ID for the table, which can be updated to trigger a refresh of the <table className=""></table>
*
* @returns { tableKey, refreshTable }
*
* To use this hook:
* const { tableKey, refreshTable } = useTableRefresh();
*
* Then, pass the refreshId to the InvenTreeTable component:
* <InvenTreeTable tableKey={tableKey} ... />
*/
export function useTableRefresh(tableName: string) {
const [tableKey, setTableKey] = useState<string>(generateTableName());
function generateTableName() {
return `${tableName}-${randomId()}`;
}
// Generate a new ID to refresh the table
const refreshTable = useCallback(function () {
setTableKey(generateTableName());
}, []);
return { tableKey, refreshTable };
}

View File

@ -0,0 +1,34 @@
import { randomId } from '@mantine/hooks';
import { useCallback, useState } from 'react';
export type TableState = {
tableKey: string;
refreshTable: () => void;
};
/**
* A custom hook for managing the state of an <InvenTreeTable> component.
*
* tableKey: A unique key for the table. When this key changes, the table will be refreshed.
* refreshTable: A callback function to externally refresh the table.
*
*/
export function useTable(tableName: string): TableState {
// Function to generate a new ID (to refresh the table)
function generateTableName() {
return `${tableName}-${randomId()}`;
}
const [tableKey, setTableKey] = useState<string>(generateTableName());
// Callback used to refresh (reload) the table
const refreshTable = useCallback(() => {
setTableKey(generateTableName());
}, []);
return {
tableKey,
refreshTable
};
}

View File

@ -14,12 +14,12 @@ import { PageDetail } from '../components/nav/PageDetail';
import { PanelGroup } from '../components/nav/PanelGroup';
import { NotificationTable } from '../components/tables/notifications/NotificationsTable';
import { ApiPaths } from '../enums/ApiEndpoints';
import { useTableRefresh } from '../hooks/TableRefresh';
import { useTable } from '../hooks/UseTable';
import { apiUrl } from '../states/ApiState';
export default function NotificationsPage() {
const unreadRefresh = useTableRefresh('unreadnotifications');
const historyRefresh = useTableRefresh('readnotifications');
const unreadTable = useTable('unreadnotifications');
const readTable = useTable('readnotifications');
const notificationPanels = useMemo(() => {
return [
@ -30,7 +30,7 @@ export default function NotificationsPage() {
content: (
<NotificationTable
params={{ read: false }}
tableKey={unreadRefresh.tableKey}
tableState={unreadTable}
actions={(record) => [
{
title: t`Mark as read`,
@ -43,7 +43,7 @@ export default function NotificationsPage() {
read: true
})
.then((response) => {
unreadRefresh.refreshTable();
unreadTable.refreshTable();
});
}
}
@ -58,7 +58,7 @@ export default function NotificationsPage() {
content: (
<NotificationTable
params={{ read: true }}
tableKey={historyRefresh.tableKey}
tableState={readTable}
actions={(record) => [
{
title: t`Mark as unread`,
@ -71,7 +71,7 @@ export default function NotificationsPage() {
read: false
})
.then((response) => {
historyRefresh.refreshTable();
readTable.refreshTable();
});
}
},
@ -83,7 +83,7 @@ export default function NotificationsPage() {
api
.delete(apiUrl(ApiPaths.notifications_list, record.pk))
.then((response) => {
historyRefresh.refreshTable();
readTable.refreshTable();
});
}
}
@ -92,7 +92,7 @@ export default function NotificationsPage() {
)
}
];
}, [historyRefresh, unreadRefresh]);
}, [unreadTable, readTable]);
return (
<>