2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-04-25 04:23:33 +00:00

[plugin] Render tables (#11733)

* Move useFilterSet state to the @lib

* Refactor useTable hook into @lib

* Refactor string helper functions

* Refactor constructFormUrl func

* Refactor Boundary component

* Refactor StoredTableState

* More refactoring

* Refactor CopyButton and CopyableCell

* Pass table render func to plugins

* Provide internal wrapper function, while allowing the "api" and "navigate" functions to be provided by the caller

* Adds <InvenTreeTable /> component which is exposed to plugins

* Update frontend versioning

* Update docs

* Handle condition where UI does not provide table rendering function

* Move queryFilters out of custom state

* Fix exported type

* Extract searchParams

- Cannot be used outside of router component
- Only provide when the table is generated internally

* Bump UI version

* Fix for right-click context menu

- Function needs to be defined with the context menu provider
This commit is contained in:
Oliver
2026-04-13 20:36:29 +10:00
committed by GitHub
parent 27ce60dea3
commit 23f43ffd33
120 changed files with 506 additions and 304 deletions
+8
View File
@@ -2,6 +2,14 @@
This file contains historical changelog information for the InvenTree UI components library.
### 0.11.1 - April 2026
Fixes dependency issues for the `InvenTreeTable` component, which were introduced in `0.11.0`. This ensures that the component works correctly and does not cause issues with plugin builds.
### 0.11.0 - April 2026
Adds the `InvenTreeTable` component, which provides plugins with a method of implementing an API-driven data table which is consistent with the rest of the InvenTree UI. This component supports features such as pagination, sorting, and filtering, and can be used to display data from the InvenTree API in a tabular format.
### 0.10.1 - April 2026
Allows plugins to specify custom model rendering functions within the data import wizard, allowing import of data models not defined in the core InvenTree codebase.
@@ -10,8 +10,7 @@ import {
Text,
Tooltip
} from '@mantine/core';
import { InvenTreeIcon } from '../../functions/icons';
import { IconCheck, IconCopy } from '@tabler/icons-react';
import type { JSX } from 'react';
@@ -62,11 +61,7 @@ export function CopyButton({
variant={copied ? 'transparent' : (variant ?? 'transparent')}
size={size ?? 'sm'}
>
{copied ? (
<InvenTreeIcon icon='check' />
) : (
<InvenTreeIcon icon='copy' />
)}
{copied ? <IconCheck /> : <IconCopy />}
{content}
{label && (
<Text p={size ?? 'sm'} size={size ?? 'sm'}>
@@ -1,6 +1,6 @@
import { Group } from '@mantine/core';
import { useState } from 'react';
import { CopyButton } from '../components/buttons/CopyButton';
import { CopyButton } from './CopyButton';
/**
* A wrapper component that adds a copy button to cell content on hover
@@ -0,0 +1,63 @@
import { Alert } from '@mantine/core';
import {
INVENTREE_PLUGIN_VERSION,
type InvenTreePluginContext
} from '../types/Plugins';
import type {
InvenTreeTableProps,
TableColumn,
TableState
} from '../types/Tables';
/**
* Wrapper function which allows plugins to render an InvenTree component instance directly,
* in a similar way to the standard InvenTreeTable component.
*
* Note: The InventreePluginContext "context" object must be provided when rendering the table
*
*/
export default function InvenTreeTable({
url,
tableState,
tableData,
columns,
props,
context
}: {
url?: string;
tableState: TableState;
tableData?: any[];
columns: TableColumn<any>[];
props: InvenTreeTableProps;
context: InvenTreePluginContext;
}) {
if (!context?.tables?.renderTable) {
return (
<Alert title='Plugin Version Error' color='red'>
{
'The <InvenTreeTable> component cannot be rendered because the plugin context is missing the "renderTable" function.'
}
<br />
{
'This means that the InvenTree UI library version is incompatible with this plugin version.'
}
<br />
<b>Plugin Version:</b> {INVENTREE_PLUGIN_VERSION}
<br />
<b>UI Version:</b> {context?.version?.inventree || 'unknown'}
<br />
</Alert>
);
}
return context?.tables.renderTable({
url: url,
tableState: tableState,
tableData: tableData,
columns: columns,
props: props,
api: context.api,
navigate: context.navigate
});
}
+47
View File
@@ -0,0 +1,47 @@
import type { ApiEndpoints } from '../enums/ApiEndpoints';
import type { PathParams } from '../types/Core';
import type { ApiFormFieldSet, ApiFormFieldType } from '../types/Forms';
import { apiUrl } from './Api';
/**
* Construct an API url from the provided ApiFormProps object
*/
export function constructFormUrl(
url: ApiEndpoints | string,
pk?: string | number,
pathParams?: PathParams,
queryParams?: URLSearchParams
): string {
let formUrl = apiUrl(url, pk, pathParams);
if (queryParams) {
formUrl += `?${queryParams.toString()}`;
}
return formUrl;
}
export type NestedDict = { [key: string]: string | number | NestedDict };
export function mapFields(
fields: ApiFormFieldSet,
fieldFunction: (path: string, value: ApiFormFieldType, key: string) => any,
_path?: string
): NestedDict {
const res: NestedDict = {};
for (const [k, v] of Object.entries(fields)) {
const path = _path ? `${_path}.${k}` : k;
let value: any;
if (v.field_type === 'nested object' && v.children) {
value = mapFields(v.children, fieldFunction, path);
} else {
value = fieldFunction(path, v, k);
}
if (value !== undefined) res[k] = value;
}
return res;
}
@@ -0,0 +1,50 @@
import { t } from '@lingui/core/macro';
import { notifications } from '@mantine/notifications';
/**
* Show a notification that the feature is not yet implemented
*/
export function notYetImplemented() {
notifications.hide('not-implemented');
notifications.show({
title: t`Not implemented`,
message: t`This feature is not yet implemented`,
color: 'red',
id: 'not-implemented'
});
}
/**
* Show a notification that the user does not have permission to perform the action
*/
export function permissionDenied() {
notifications.show({
title: t`Permission Denied`,
message: t`You do not have permission to perform this action`,
color: 'red'
});
}
/**
* Display a notification on an invalid return code
*/
export function invalidResponse(returnCode: number) {
// TODO: Specific return code messages
notifications.show({
title: t`Invalid Return Code`,
message: t`Server returned status ${returnCode}`,
color: 'red'
});
}
/**
* Display a notification on timeout
*/
export function showTimeoutNotification() {
notifications.show({
title: t`Timeout`,
message: t`The request timed out`,
color: 'red'
});
}
@@ -1,8 +1,8 @@
import type { FilterSetState, TableFilter } from '@lib/types/Filters';
import { useLocalStorage } from '@mantine/hooks';
import { useCallback, useMemo } from 'react';
import type { FilterSetState, TableFilter } from '../types/Filters';
export function useFilterSet(
export default function useFilterSet(
filterKey: string,
initialFilters?: TableFilter[]
): FilterSetState {
@@ -1,10 +1,9 @@
import { randomId } from '@mantine/hooks';
import { useCallback, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import type { FilterSetState, TableFilter } from '@lib/types/Filters';
import type { TableState } from '@lib/types/Tables';
import { useFilterSet } from './UseFilterSet';
import type { FilterSetState, TableFilter } from '../types/Filters';
import type { TableState } from '../types/Tables';
import useFilterSet from './UseFilterSet';
export type TableStateExtraProps = {
idAccessor?: string;
@@ -17,7 +16,7 @@ export type TableStateExtraProps = {
* Refer to the TableState type definition for more information.
*/
export function useTable(
export default function useTable(
tableName: string,
tableProps: TableStateExtraProps = {
idAccessor: 'pk',
@@ -29,13 +28,6 @@ export function useTable(
return `${tableName.replaceAll('-', '')}-${randomId()}`;
}
// Extract URL query parameters (e.g. ?active=true&overdue=false)
const [queryFilters, setQueryFilters] = useSearchParams();
const clearQueryFilters = useCallback(() => {
setQueryFilters({});
}, []);
const [tableKey, setTableKey] = useState<string>(generateTableName());
// Callback used to refresh (reload) the table
@@ -133,9 +125,6 @@ export function useTable(
isLoading,
setIsLoading,
filterSet,
queryFilters,
setQueryFilters,
clearQueryFilters,
expandedRecords,
setExpandedRecords,
isRowExpanded,
+49 -1
View File
@@ -15,10 +15,20 @@ export { UserRoles, UserPermissions } from './enums/Roles';
export type {
InvenTreePluginContext,
InvenTreeFormsContext,
InvenTreeTablesContext,
ImporterDrawerContext,
PluginVersion,
StockAdjustmentFormsContext
} from './types/Plugins';
export type { RowAction, RowViewProps } from './types/Tables';
export type {
RowAction,
RowViewProps,
TableColumn,
TableColumnProps,
InvenTreeTableProps,
InvenTreeTableRenderProps
} from './types/Tables';
export type {
ApiFormFieldChoice,
@@ -42,6 +52,14 @@ export {
getDetailUrl,
navigateToLink
} from './functions/Navigation';
export {
notYetImplemented,
permissionDenied,
invalidResponse,
showTimeoutNotification
} from './functions/Notification';
export {
checkPluginVersion,
initPlugin
@@ -53,16 +71,32 @@ export {
formatFileSize
} from './functions/Formatting';
export {
constructFormUrl,
mapFields,
type NestedDict
} from './functions/Forms';
export {
shortenString,
hashString
} from './functions/String';
// Common UI components
export {
ActionButton,
type ActionButtonProps
} from './components/ActionButton';
export { AddItemButton } from './components/AddItemButton';
export { Boundary, DefaultFallback } from './components/Boundary';
export { ButtonMenu } from './components/ButtonMenu';
export { CopyButton } from './components/CopyButton';
export { CopyableCell } from './components/CopyableCell';
export { ProgressBar } from './components/ProgressBar';
export { PassFailButton, YesNoButton } from './components/YesNoButton';
export { SearchInput } from './components/SearchInput';
export { TableColumnSelect } from './components/TableColumnSelect';
export { default as InvenTreeTable } from './components/InvenTreeTable';
export {
RowViewAction,
RowDuplicateAction,
@@ -77,7 +111,21 @@ export {
default as useMonitorDataOutput,
type MonitorDataOutputProps
} from './hooks/MonitorDataOutput';
export {
default as useMonitorBackgroundTask,
type MonitorBackgroundTaskProps
} from './hooks/MonitorBackgroundTask';
export { default as useFilterSet } from './hooks/UseFilterSet';
export {
default as useTable,
type TableStateExtraProps
} from './hooks/UseTable';
// State management
export {
type StoredTableStateProps,
useStoredTableState
} from './states/StoredTableState';
@@ -13,7 +13,7 @@ const DEFAULT_PAGE_SIZE: number = 25;
* - columnNames: An object mapping table keys to arrays of column names.
* - sorting: An object mapping table keys to sorting configurations.
*/
interface StoredTableStateProps {
export interface StoredTableStateProps {
pageSize: number;
setPageSize: (size: number) => void;
tableSorting: Record<string, any>;
+17 -9
View File
@@ -13,6 +13,7 @@ import type {
import type { UseModalReturn } from './Modals';
import type { RenderInstanceProps } from './Rendering';
import type { SettingsStateProps } from './Settings';
import type { InvenTreeTableRenderProps } from './Tables';
import type { UserStateProps } from './User';
export interface PluginProps {
@@ -48,6 +49,10 @@ export type InvenTreeFormsContext = {
stockActions: StockAdjustmentFormsContext;
};
export type InvenTreeTablesContext<T extends Record<string, any>> = {
renderTable: (props: InvenTreeTableRenderProps<T>) => React.ReactNode;
};
export type ImporterDrawerContext = {
open: (sessionId: number, options?: { onClose?: () => void }) => void;
close: () => void;
@@ -61,20 +66,22 @@ export type ImporterDrawerContext = {
*
* @param version - The version of the running InvenTree software stack
* @param api - The Axios API instance (see ../states/ApiState.tsx)
* @param queryClient - The Tanstack QueryClient instance (see ../states/QueryState.tsx)
* @param user - The current user instance (see ../states/UserState.tsx)
* @param userSettings - The current user settings (see ../states/SettingsState.tsx)
* @param globalSettings - The global settings (see ../states/SettingsState.tsx)
* @param navigate - The navigation function (see react-router-dom)
* @param theme - The current Mantine theme
* @param forms - A set of functions for opening various API forms (see ../components/Forms.tsx)
* @param importer - A set of functions for controlling the global importer drawer (see ../components/importer/GlobalImporterDrawer.tsx)
* @param colorScheme - The current Mantine color scheme (e.g. 'light' / 'dark')
* @param modelInformation - A dictionary of available model information
* @param renderInstance - A component function for rendering a model instance
* @param host - The current host URL
* @param i18n - The i18n instance for translations (from @lingui/core)
* @param locale - The current locale string (e.g. 'en' / 'de')
* @param navigate - The navigation function (see react-router-dom)
* @param theme - The current Mantine theme
* @param colorScheme - The current Mantine color scheme (e.g. 'light' / 'dark')
* @param forms - A set of functions for opening various API forms (see ../components/Forms.tsx)
* @param tables - A set of functions for rendering API tables
* @param importer - A set of functions for controlling the global importer drawer (see ../components/importer/GlobalImporterDrawer.tsx)
* @param model - The model type associated with the rendered component (if applicable)
* @param modelInformation - A dictionary of available model information
* @param renderInstance - A component function for rendering a model instance
* @param id - The ID (primary key) of the model instance for the plugin (if applicable)
* @param instance - The model instance data (if available)
* @param reloadContent - A function which can be called to reload the plugin content
@@ -95,9 +102,10 @@ export type InvenTreePluginContext = {
locale: string;
navigate: NavigateFunction;
theme: MantineTheme;
forms: InvenTreeFormsContext;
importer: ImporterDrawerContext;
colorScheme: MantineColorScheme;
forms: InvenTreeFormsContext;
tables: InvenTreeTablesContext<any>;
importer: ImporterDrawerContext;
model?: ModelType | string;
id?: string | number | null;
instance?: any;
+18 -7
View File
@@ -1,10 +1,12 @@
import type { MantineStyleProp } from '@mantine/core';
import type { AxiosInstance } from 'axios';
import type { ShowContextMenuFunction } from 'mantine-contextmenu';
import type {
DataTableCellClickHandler,
DataTableRowExpansionProps
} from 'mantine-datatable';
import type { ReactNode } from 'react';
import type { NavigateFunction, SetURLSearchParams } from 'react-router-dom';
import type { NavigateFunction } from 'react-router-dom';
import type { ModelType } from '../enums/ModelType';
import type { FilterSetState, TableFilter } from './Filters';
import type { ApiFormFieldType } from './Forms';
@@ -17,9 +19,6 @@ import type { ApiFormFieldType } from './Forms';
* isLoading: A boolean flag to indicate if the table is currently loading data
* setIsLoading: A function to set the isLoading flag
* filterSet: A group of active filters
* queryFilters: A map of query filters (e.g. ?active=true&overdue=false) passed in the URL
* setQueryFilters: A function to set the query filters
* clearQueryFilters: A function to clear all query filters
* expandedRecords: An array of expanded records (rows) in the table
* setExpandedRecords: A function to set the expanded records
* isRowExpanded: A function to determine if a record is expanded
@@ -49,9 +48,6 @@ export type TableState = {
isLoading: boolean;
setIsLoading: (value: boolean) => void;
filterSet: FilterSetState;
queryFilters: URLSearchParams;
setQueryFilters: SetURLSearchParams;
clearQueryFilters: () => void;
expandedRecords: any[];
setExpandedRecords: (records: any[]) => void;
isRowExpanded: (pk: number) => boolean;
@@ -219,3 +215,18 @@ export type InvenTreeTableProps<T = any> = {
minHeight?: number;
noHeader?: boolean;
};
export type InvenTreeTableRenderProps<T extends Record<string, any>> = {
url?: string;
tableState: TableState;
tableData?: T[];
columns: TableColumn<T>[];
props: InvenTreeTableProps<T>;
api: AxiosInstance;
navigate: NavigateFunction;
// The following attributes are for internal use only (plugins should not use these directly)
showContextMenu?: ShowContextMenuFunction;
searchParams?: URLSearchParams;
setSearchParams?: (params: URLSearchParams) => void;
};
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@inventreedb/ui",
"description": "UI components for the InvenTree project",
"version": "0.10.1",
"version": "0.11.1",
"private": false,
"type": "module",
"license": "MIT",
@@ -13,9 +13,9 @@ import {
import { IconCamera, IconScan } from '@tabler/icons-react';
import { useCallback, useMemo, useState } from 'react';
import { Boundary } from '@lib/components/Boundary';
import { useLocalStorage } from '@mantine/hooks';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { Boundary } from '../Boundary';
import BarcodeCameraInput from './BarcodeCameraInput';
import BarcodeKeyboardInput from './BarcodeKeyboardInput';
@@ -18,11 +18,11 @@ import { useQuery } from '@tanstack/react-query';
import QR from 'qrcode';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { CopyButton } from '@lib/components/CopyButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import { api } from '../../App';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { CopyButton } from '../buttons/CopyButton';
import type { QrCodeType } from '../items/ActionDropdown';
import { extractErrorMessage } from '../../functions/api';
@@ -5,6 +5,7 @@ import interactionPlugin from '@fullcalendar/interaction';
import FullCalendar from '@fullcalendar/react';
import { ActionButton } from '@lib/components/ActionButton';
import { Boundary } from '@lib/components/Boundary';
import { SearchInput } from '@lib/components/SearchInput';
import type { TableFilter } from '@lib/types/Filters';
import { t } from '@lingui/core/macro';
@@ -36,7 +37,6 @@ import {
import type { CalendarState } from '../../hooks/UseCalendar';
import { useLocalState } from '../../states/LocalState';
import { FilterSelectDrawer } from '../../tables/FilterSelectDrawer';
import { Boundary } from '../Boundary';
import { StylishText } from '../items/StylishText';
export interface InvenTreeCalendarProps extends CalendarOptions {
@@ -2,7 +2,7 @@ import { t } from '@lingui/core/macro';
import { ActionIcon, Box, Group, Overlay, Paper, Tooltip } from '@mantine/core';
import { IconX } from '@tabler/icons-react';
import { Boundary } from '../Boundary';
import { Boundary } from '@lib/components/Boundary';
import type { ModelType } from '@lib/index';
import type { JSX } from 'react';
@@ -17,6 +17,7 @@ import { getValueAtPath } from 'mantine-datatable';
import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { CopyButton } from '@lib/components/CopyButton';
import { ProgressBar } from '@lib/components/ProgressBar';
import { YesNoButton } from '@lib/components/YesNoButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
@@ -29,7 +30,6 @@ import { useApi } from '../../contexts/ApiContext';
import { formatDate, formatDecimal } from '../../defaults/formatters';
import { InvenTreeIcon } from '../../functions/icons';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { CopyButton } from '../buttons/CopyButton';
import { StylishText } from '../items/StylishText';
import { getModelInfo } from '../render/ModelType';
import { StatusRenderer } from '../render/StatusRenderer';
@@ -25,12 +25,12 @@ import Split from '@uiw/react-split';
import type React from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Boundary } from '@lib/components/Boundary';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import { api } from '../../../App';
import type { TemplateI } from '../../../tables/settings/TemplateTable';
import { Boundary } from '../../Boundary';
import { SplitButton } from '../../buttons/SplitButton';
import { StandaloneField } from '../../forms/StandaloneField';
+11 -12
View File
@@ -22,26 +22,25 @@ import {
} from 'react-hook-form';
import { type NavigateFunction, useNavigate } from 'react-router-dom';
import { Boundary } from '@lib/components/Boundary';
import { isTrue } from '@lib/functions/Conversion';
import {
type NestedDict,
constructFormUrl,
mapFields
} from '@lib/functions/Forms';
import { getDetailUrl } from '@lib/functions/Navigation';
import {
invalidResponse,
showTimeoutNotification
} from '@lib/functions/Notification';
import type {
ApiFormFieldSet,
ApiFormFieldType,
ApiFormProps
} from '@lib/types/Forms';
import { useApi } from '../../contexts/ApiContext';
import {
type NestedDict,
constructField,
constructFormUrl,
extractAvailableFields,
mapFields
} from '../../functions/forms';
import {
invalidResponse,
showTimeoutNotification
} from '../../functions/notifications';
import { Boundary } from '../Boundary';
import { constructField, extractAvailableFields } from '../../functions/forms';
import { KeepFormOpenSwitch } from './KeepFormOpenSwitch';
import { ApiFormField } from './fields/ApiFormField';
@@ -20,6 +20,7 @@ import { YesNoButton } from '@lib/components/YesNoButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import { cancelEvent } from '@lib/functions/Events';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -29,7 +30,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import type { ImportSessionState } from '../../hooks/UseImportSession';
import { useTable } from '../../hooks/UseTable';
import { InvenTreeTable } from '../../tables/InvenTreeTable';
import { RenderRemoteInstance } from '../render/Instance';
@@ -13,13 +13,13 @@ import {
import type { ContextModalProps } from '@mantine/modals';
import { useQuery } from '@tanstack/react-query';
import { CopyButton } from '@lib/components/CopyButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import { useShallow } from 'zustand/react/shallow';
import { api } from '../../App';
import { generateUrl } from '../../functions/urls';
import { useServerApiState } from '../../states/ServerApiState';
import { CopyButton } from '../buttons/CopyButton';
import { StylishText } from '../items/StylishText';
import type { JSX } from 'react';
+1 -1
View File
@@ -9,6 +9,7 @@ import { IconSearch } from '@tabler/icons-react';
import { type JSX, useEffect, useMemo, useState } from 'react';
import { Navigate, Outlet, useLocation, useNavigate } from 'react-router-dom';
import { Boundary } from '@lib/components/Boundary';
import { identifierString } from '@lib/functions/Conversion';
import { ApiEndpoints, apiUrl } from '@lib/index';
import { useQuery } from '@tanstack/react-query';
@@ -20,7 +21,6 @@ import {
useUserSettingsState
} from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
import { Boundary } from '../Boundary';
import GlobalImporterDrawer from '../importer/GlobalImporterDrawer';
import { ApiIcon } from '../items/ApiIcon';
import { useInvenTreeContext } from '../plugins/PluginContext';
@@ -23,6 +23,7 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { Boundary } from '@lib/components/Boundary';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import type { ModelType } from '@lib/enums/ModelType';
@@ -32,7 +33,6 @@ import { getBaseUrl } from '@lib/functions/Navigation';
import { navigateToLink } from '@lib/functions/Navigation';
import { api } from '../../App';
import { useUserState } from '../../states/UserState';
import { Boundary } from '../Boundary';
import { StylishText } from '../items/StylishText';
/**
@@ -1,8 +1,8 @@
import { Group, Paper, Space, Stack, Text } from '@mantine/core';
import { useHotkeys } from '@mantine/hooks';
import { shortenString } from '@lib/functions/String';
import { Fragment, type ReactNode, useMemo } from 'react';
import { shortenString } from '../../functions/tables';
import { useUserSettingsState } from '../../states/SettingsStates';
import { ApiImage } from '../images/ApiImage';
import { StylishText } from '../items/StylishText';
@@ -33,6 +33,7 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { type NavigateFunction, useNavigate } from 'react-router-dom';
import { Boundary } from '@lib/components/Boundary';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import { ModelType } from '@lib/enums/ModelType';
@@ -48,7 +49,6 @@ import { showNotification } from '@mantine/notifications';
import { api } from '../../App';
import { useUserSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
import { Boundary } from '../Boundary';
import { RenderInstance } from '../render/Instance';
import { getModelInfo } from '../render/ModelType';
@@ -32,6 +32,7 @@ import {
useParams
} from 'react-router-dom';
import { Boundary } from '@lib/components/Boundary';
import type { ModelType } from '@lib/enums/ModelType';
import { identifierString } from '@lib/functions/Conversion';
import { cancelEvent } from '@lib/functions/Events';
@@ -43,7 +44,6 @@ import { generateUrl } from '../../functions/urls';
import { usePluginPanels } from '../../hooks/UsePluginPanels';
import { useLocalState } from '../../states/LocalState';
import { vars } from '../../theme';
import { Boundary } from '../Boundary';
import { StylishText } from '../items/StylishText';
import type { PanelGroupType, PanelType } from '../panels/Panel';
import * as classes from './PanelGroup.css';
@@ -17,7 +17,9 @@ import {
INVENTREE_REACT_VERSION,
type InvenTreePluginContext
} from '@lib/types/Plugins';
import type { InvenTreeTableRenderProps } from '@lib/types/Tables';
import { i18n } from '@lingui/core';
import { useContextMenu } from 'mantine-contextmenu';
import { defaultLocale } from '../../contexts/LanguageContext';
import {
useAddStockItem,
@@ -43,6 +45,7 @@ import {
openGlobalImporter
} from '../../states/ImporterState';
import { useServerApiState } from '../../states/ServerApiState';
import { InvenTreeTableInternal } from '../../tables/InvenTreeTable';
import { RenderInstance } from '../render/Instance';
export const useInvenTreeContext = () => {
@@ -54,6 +57,7 @@ export const useInvenTreeContext = () => {
const theme = useMantineTheme();
const globalSettings = useGlobalSettingsState();
const userSettings = useUserSettingsState();
const { showContextMenu } = useContextMenu();
const contextData = useMemo<InvenTreePluginContext>(() => {
return {
@@ -83,6 +87,14 @@ export const useInvenTreeContext = () => {
isOpen: () => getGlobalImporterState().isOpen,
sessionId: () => getGlobalImporterState().sessionId
},
tables: {
renderTable: (props: InvenTreeTableRenderProps<any>) => (
<InvenTreeTableInternal
{...props}
showContextMenu={showContextMenu}
/>
)
},
forms: {
bulkEdit: useBulkEditApiFormModal,
create: useCreateApiFormModal,
@@ -3,6 +3,7 @@ import { Alert, MantineProvider, Stack, Text } from '@mantine/core';
import { IconExclamationCircle } from '@tabler/icons-react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Boundary } from '@lib/components/Boundary';
import { identifierString } from '@lib/functions/Conversion';
import type { InvenTreePluginContext } from '@lib/types/Plugins';
import { type Root, createRoot } from 'react-dom/client';
@@ -10,7 +11,6 @@ import { api, queryClient } from '../../App';
import { ApiProvider } from '../../contexts/ApiContext';
import { LanguageContext } from '../../contexts/LanguageContext';
import { useLocalState } from '../../states/LocalState';
import { Boundary } from '../Boundary';
import { findExternalPluginFunction } from './PluginSource';
/**
@@ -21,8 +21,8 @@ import type {
RenderInstanceProps
} from '@lib/types/Rendering';
export type { InstanceRenderInterface } from '@lib/types/Rendering';
import { shortenString } from '@lib/functions/String';
import { useApi } from '../../contexts/ApiContext';
import { shortenString } from '../../functions/tables';
import { Thumbnail } from '../images/Thumbnail';
import { RenderBuildItem, RenderBuildLine, RenderBuildOrder } from './Build';
import {
+1 -1
View File
@@ -5,7 +5,7 @@ import type { ReactNode } from 'react';
import { ModelType } from '@lib/enums/ModelType';
import { formatDecimal } from '@lib/functions/Formatting';
import { getDetailUrl } from '@lib/functions/Navigation';
import { shortenString } from '../../functions/tables';
import { shortenString } from '@lib/functions/String';
import { TableHoverCard } from '../../tables/TableHoverCard';
import { ApiIcon } from '../items/ApiIcon';
import { type InstanceRenderInterface, RenderInlineModel } from './Instance';
+1 -1
View File
@@ -5,7 +5,7 @@ import type { ReactNode } from 'react';
import { ModelType } from '@lib/enums/ModelType';
import { formatDecimal } from '@lib/functions/Formatting';
import { getDetailUrl } from '@lib/functions/Navigation';
import { shortenString } from '../../functions/tables';
import { shortenString } from '@lib/functions/String';
import { TableHoverCard } from '../../tables/TableHoverCard';
import { ApiIcon } from '../items/ApiIcon';
import {
@@ -13,13 +13,13 @@ import {
import { IconEdit } from '@tabler/icons-react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Boundary } from '@lib/components/Boundary';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import type { Setting } from '@lib/types/Settings';
import { api } from '../../App';
import { vars } from '../../theme';
import { Boundary } from '../Boundary';
import { RenderInstance } from '../render/Instance';
type ConfirmResult = {
@@ -1,5 +1,6 @@
import { ActionButton } from '@lib/components/ActionButton';
import { AddItemButton } from '@lib/components/AddItemButton';
import { CopyButton } from '@lib/components/CopyButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
@@ -32,7 +33,6 @@ import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance';
import useWizard from '../../hooks/UseWizard';
import { RenderPartColumn } from '../../tables/ColumnRenderers';
import { CopyButton } from '../buttons/CopyButton';
import RemoveRowButton from '../buttons/RemoveRowButton';
import { StandaloneField } from '../forms/StandaloneField';
import Expand from '../items/Expand';
@@ -1,3 +1,4 @@
import { Boundary } from '@lib/components/Boundary';
import { t } from '@lingui/core/macro';
import {
ActionIcon,
@@ -16,7 +17,6 @@ import {
IconCircleCheck
} from '@tabler/icons-react';
import { type ReactNode, useCallback, useMemo } from 'react';
import { Boundary } from '../Boundary';
import { StylishText } from '../items/StylishText';
/**
@@ -3,11 +3,11 @@ import { I18nProvider } from '@lingui/react';
import { LoadingOverlay, Text } from '@mantine/core';
import { type JSX, useEffect, useRef, useState } from 'react';
import { useStoredTableState } from '@lib/states/StoredTableState';
import { useShallow } from 'zustand/react/shallow';
import { api } from '../App';
import { useLocalState } from '../states/LocalState';
import { useServerApiState } from '../states/ServerApiState';
import { useStoredTableState } from '../states/StoredTableState';
import { fetchGlobalStates } from '../states/states';
export const defaultLocale = 'en';
+2 -48
View File
@@ -1,28 +1,6 @@
import type { AxiosResponse } from 'axios';
import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import type { PathParams } from '@lib/types/Core';
import { invalidResponse, permissionDenied } from '@lib/functions/Notification';
import type { ApiFormFieldSet, ApiFormFieldType } from '@lib/types/Forms';
import { invalidResponse, permissionDenied } from './notifications';
/**
* Construct an API url from the provided ApiFormProps object
*/
export function constructFormUrl(
url: ApiEndpoints | string,
pk?: string | number,
pathParams?: PathParams,
queryParams?: URLSearchParams
): string {
let formUrl = apiUrl(url, pk, pathParams);
if (queryParams) {
formUrl += `?${queryParams.toString()}`;
}
return formUrl;
}
import type { AxiosResponse } from 'axios';
/**
* Extract the available fields (for a given method) from the response object
@@ -104,30 +82,6 @@ export function extractAvailableFields(
return processFields(actions[method]);
}
export type NestedDict = { [key: string]: string | number | NestedDict };
export function mapFields(
fields: ApiFormFieldSet,
fieldFunction: (path: string, value: ApiFormFieldType, key: string) => any,
_path?: string
): NestedDict {
const res: NestedDict = {};
for (const [k, v] of Object.entries(fields)) {
const path = _path ? `${_path}.${k}` : k;
let value: any;
if (v.field_type === 'nested object' && v.children) {
value = mapFields(v.children, fieldFunction, path);
} else {
value = fieldFunction(path, v, k);
}
if (value !== undefined) res[k] = value;
}
return res;
}
/*
* Build a complete field definition based on the provided data
*/
@@ -1,56 +1,7 @@
import { t } from '@lingui/core/macro';
import { notifications } from '@mantine/notifications';
import { IconCircleCheck, IconExclamationCircle } from '@tabler/icons-react';
import { extractErrorMessage } from './api';
/**
* Show a notification that the feature is not yet implemented
*/
export function notYetImplemented() {
notifications.hide('not-implemented');
notifications.show({
title: t`Not implemented`,
message: t`This feature is not yet implemented`,
color: 'red',
id: 'not-implemented'
});
}
/**
* Show a notification that the user does not have permission to perform the action
*/
export function permissionDenied() {
notifications.show({
title: t`Permission Denied`,
message: t`You do not have permission to perform this action`,
color: 'red'
});
}
/**
* Display a notification on an invalid return code
*/
export function invalidResponse(returnCode: number) {
// TODO: Specific return code messages
notifications.show({
title: t`Invalid Return Code`,
message: t`Server returned status ${returnCode}`,
color: 'red'
});
}
/**
* Display a notification on timeout
*/
export function showTimeoutNotification() {
notifications.show({
title: t`Timeout`,
message: t`The request timed out`,
color: 'red'
});
}
/*
* Display a login / logout notification message.
* Any existing login notification(s) will be hidden.
+1 -1
View File
@@ -1,6 +1,7 @@
import type FullCalendar from '@fullcalendar/react';
import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useFilterSet from '@lib/hooks/UseFilterSet';
import type { FilterSetState } from '@lib/types/Filters';
import type { UseModalReturn } from '@lib/types/Modals';
import type { DateValue } from '@mantine/dates';
@@ -10,7 +11,6 @@ import { useCallback, useMemo, useRef, useState } from 'react';
import { api } from '../App';
import { showApiErrorMessage } from '../functions/notifications';
import useDataExport from './UseDataExport';
import { useFilterSet } from './UseFilterSet';
/*
* Type definition for representing the state of a calendar:
+2 -4
View File
@@ -23,6 +23,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import type { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import { notYetImplemented } from '@lib/functions/Notification';
import { hideNotification, showNotification } from '@mantine/notifications';
import dayjs from 'dayjs';
import { api } from '../../App';
@@ -30,10 +31,7 @@ import { BarcodeInput } from '../../components/barcodes/BarcodeInput';
import type { BarcodeScanItem } from '../../components/barcodes/BarcodeScanItem';
import { StylishText } from '../../components/items/StylishText';
import PageTitle from '../../components/nav/PageTitle';
import {
notYetImplemented,
showApiErrorMessage
} from '../../functions/notifications';
import { showApiErrorMessage } from '../../functions/notifications';
import BarcodeScanTable from '../../tables/general/BarcodeScanTable';
export default function Scan() {
@@ -1,4 +1,5 @@
import { create } from '@github/webauthn-json/browser-ponyfill';
import { CopyButton } from '@lib/components/CopyButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import { FlowEnum } from '@lib/types/Auth';
@@ -31,7 +32,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useShallow } from 'zustand/react/shallow';
import { api, queryClient } from '../../../../App';
import { CopyButton } from '../../../../components/buttons/CopyButton';
import { StylishText } from '../../../../components/items/StylishText';
import { authApi, doLogout } from '../../../../functions/auth';
import { useServerApiState } from '../../../../states/ServerApiState';
@@ -1,8 +1,8 @@
import { CopyButton } from '@lib/components/CopyButton';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
import { Divider, Group, Paper, Stack, Text, TextInput } from '@mantine/core';
import { QRCode } from '../../../../components/barcodes/QRCode';
import { CopyButton } from '../../../../components/buttons/CopyButton';
export function QrRegistrationForm({
url,
@@ -1,3 +1,4 @@
import { DefaultFallback } from '@lib/components/Boundary';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import type { AuthConfig, AuthProvider } from '@lib/types/Auth';
@@ -30,7 +31,6 @@ import {
import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo, useState } from 'react';
import { useShallow } from 'zustand/react/shallow';
import { DefaultFallback } from '../../../../components/Boundary';
import { StylishText } from '../../../../components/items/StylishText';
import { ProviderLogin, authApi } from '../../../../functions/auth';
import { useServerApiState } from '../../../../states/ServerApiState';
@@ -7,11 +7,11 @@ import { useCallback, useMemo, useState } from 'react';
import { ActionButton } from '@lib/components/ActionButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { api } from '../../../../App';
import { FactCollection } from '../../../../components/settings/FactCollection';
import { GlobalSettingList } from '../../../../components/settings/SettingList';
import { showApiErrorMessage } from '../../../../functions/notifications';
import { useTable } from '../../../../hooks/UseTable';
import { InvenTreeTable } from '../../../../tables/InvenTreeTable';
/*
@@ -4,8 +4,8 @@ import { useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { StylishText } from '../../../../components/items/StylishText';
import { useTable } from '../../../../hooks/UseTable';
import { BooleanColumn } from '../../../../tables/ColumnRenderers';
import { InvenTreeTable } from '../../../../tables/InvenTreeTable';
import CustomUnitsTable from '../../../../tables/settings/CustomUnitsTable';
+1 -1
View File
@@ -13,10 +13,10 @@ import { useCallback, useMemo } from 'react';
import { ActionButton } from '@lib/components/ActionButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { PageDetail } from '../components/nav/PageDetail';
import { PanelGroup } from '../components/panels/PanelGroup';
import { useApi } from '../contexts/ApiContext';
import { useTable } from '../hooks/UseTable';
import { NotificationTable } from '../tables/notifications/NotificationTable';
export default function NotificationsPage() {
@@ -2,6 +2,7 @@ import { RowDeleteAction, RowEditAction } from '@lib/components/RowActions';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { AddItemButton } from '@lib/index';
import type { TableColumn } from '@lib/types/Tables';
import { t } from '@lingui/core/macro';
@@ -25,7 +26,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { DateColumn, DecimalColumn } from '../../tables/ColumnRenderers';
import { InvenTreeTable } from '../../tables/InvenTreeTable';
@@ -13,11 +13,11 @@ import { type ReactNode, useMemo, useState } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { CHART_COLORS } from '../../../components/charts/colors';
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
import { formatDecimal, formatPriceRange } from '../../../defaults/formatters';
import { useTable } from '../../../hooks/UseTable';
import { DateColumn, PartColumn } from '../../../tables/ColumnRenderers';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { LoadingPricingData, NoPricingData } from './PricingPanel';
@@ -12,6 +12,7 @@ import {
import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
@@ -21,7 +22,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable';
import { useUserState } from '../../../states/UserState';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { NoPricingData } from './PricingPanel';
@@ -5,9 +5,9 @@ import { type ReactNode, useCallback, useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency, formatDate } from '../../../defaults/formatters';
import { useTable } from '../../../hooks/UseTable';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { NoPricingData } from './PricingPanel';
@@ -5,9 +5,9 @@ import { type ReactNode, useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency } from '../../../defaults/formatters';
import { useTable } from '../../../hooks/UseTable';
import { DateColumn } from '../../../tables/ColumnRenderers';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { NoPricingData } from './PricingPanel';
@@ -5,9 +5,9 @@ import { useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
import { useTable } from '../../../hooks/UseTable';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import {
SupplierPriceBreakColumns,
@@ -6,10 +6,10 @@ import { type ReactNode, useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
import { formatCurrency } from '../../../defaults/formatters';
import { useTable } from '../../../hooks/UseTable';
import { DateColumn, PartColumn } from '../../../tables/ColumnRenderers';
import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { NoPricingData } from './PricingPanel';
+85 -31
View File
@@ -1,12 +1,21 @@
import { Boundary } from '@lib/components/Boundary';
import { CopyableCell } from '@lib/components/CopyableCell';
import { RowActions } from '@lib/components/RowActions';
import { ModelInformationDict } from '@lib/enums/ModelInformation';
import { resolveItem } from '@lib/functions/Conversion';
import { cancelEvent } from '@lib/functions/Events';
import { mapFields } from '@lib/functions/Forms';
import { getDetailUrl } from '@lib/functions/Navigation';
import { navigateToLink } from '@lib/functions/Navigation';
import { hashString } from '@lib/functions/String';
import { useStoredTableState } from '@lib/states/StoredTableState';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { InvenTreeTableProps, TableState } from '@lib/types/Tables';
import type {
InvenTreeTableProps,
InvenTreeTableRenderProps,
TableState
} from '@lib/types/Tables';
import type { TableColumn } from '@lib/types/Tables';
import { t } from '@lingui/core/macro';
import { Box, Stack } from '@mantine/core';
@@ -24,16 +33,12 @@ import {
} from 'mantine-datatable';
import type React from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Boundary } from '../components/Boundary';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useApi } from '../contexts/ApiContext';
import { extractAvailableFields, mapFields } from '../functions/forms';
import { extractAvailableFields } from '../functions/forms';
import { showApiErrorMessage } from '../functions/notifications';
import { hashString } from '../functions/tables';
import { useLocalState } from '../states/LocalState';
import { useUserSettingsState } from '../states/SettingsStates';
import { useStoredTableState } from '../states/StoredTableState';
import { CopyableCell } from './CopyableCell';
import InvenTreeTableHeader from './InvenTreeTableHeader';
const ACTIONS_COLUMN_ACCESSOR: string = '--actions--';
@@ -62,20 +67,27 @@ const defaultInvenTreeTableProps: InvenTreeTableProps = {
/**
* Table Component which extends DataTable with custom InvenTree functionality
*
* This component is not used directly - instead, the "InvenTreeTable" component is a wrapper,
* which provides the necessary context and state management for this internal component.
*
* This function is also provided to the plugin context, and when used by external plugins,
* it must be supplied with with following additional context items:
* - api: AxiosInstance - The API instance for making requests to the server
* - navigate: NavigateFunction - The navigation function for navigating to different pages
*/
export function InvenTreeTable<T extends Record<string, any>>({
export function InvenTreeTableInternal<T extends Record<string, any>>({
url,
tableState,
tableData,
columns,
props
}: Readonly<{
url?: string;
tableState: TableState;
tableData?: any[];
columns: TableColumn<T>[];
props: InvenTreeTableProps<T>;
}>) {
props,
api,
navigate,
showContextMenu,
searchParams,
setSearchParams
}: Readonly<InvenTreeTableRenderProps<T>>) {
const { userTheme } = useLocalState();
const {
@@ -91,10 +103,6 @@ export function InvenTreeTable<T extends Record<string, any>>({
const [fieldNames, setFieldNames] = useState<Record<string, string>>({});
const api = useApi();
const navigate = useNavigate();
const { showContextMenu } = useContextMenu();
const userSettings = useUserSettingsState();
const stickyTableHeader = useMemo(() => {
@@ -388,11 +396,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
useEffect(() => {
tableState.setPage(1);
tableState.clearSelectedRecords();
}, [
tableState.searchTerm,
tableState.filterSet.activeFilters,
tableState.queryFilters
]);
}, [tableState.searchTerm, tableState.filterSet.activeFilters, searchParams]);
// Account for invalid page offsets
useEffect(() => {
@@ -426,9 +430,9 @@ export function InvenTreeTable<T extends Record<string, any>>({
...tableProps.params
};
if (tableState.queryFilters && tableState.queryFilters.size > 0) {
if (searchParams && searchParams.size > 0) {
// Allow override of filters based on URL query parameters
for (const [key, value] of tableState.queryFilters) {
for (const [key, value] of searchParams) {
queryParams[key] = value;
}
} else if (tableState.filterSet.activeFilters) {
@@ -467,7 +471,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
tableProps.params,
tableProps.enablePagination,
tableState.filterSet.activeFilters,
tableState.queryFilters,
searchParams,
tableState.searchTerm,
getOrderingTerm
]
@@ -609,7 +613,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
// Refetch data when the query parameters change
useEffect(() => {
refetch();
}, [tableState.queryFilters]);
}, [searchParams]);
useEffect(() => {
const loading: boolean =
@@ -705,7 +709,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
const empty = () => {};
let items: ContextMenuItemOptions[] = [];
if (props.rowActions) {
if (!!props.rowActions) {
items = props.rowActions(record).map((action) => ({
key: action.title ?? '',
title: action.title ?? '',
@@ -743,7 +747,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
});
}
return showContextMenu(items)(event);
return showContextMenu?.(items)(event);
};
// Pagination refresh table if pageSize changes
@@ -825,6 +829,8 @@ export function InvenTreeTable<T extends Record<string, any>>({
hasSwitchableColumns={hasSwitchableColumns}
columns={dataColumns}
filters={filters}
queryFilters={searchParams}
clearQueryFilters={() => setSearchParams?.(new URLSearchParams())}
toggleColumn={toggleColumn}
/>
</Boundary>
@@ -874,3 +880,51 @@ export function InvenTreeTable<T extends Record<string, any>>({
</>
);
}
/**
* This is an internal wrapper function for the InvenTreeTableInternal component,
* which provides the necessary context management for the table to function correctly.
*
* In addition to the provided table props, this wrapper provides context for:
*
* - api: The API instance for making requests to the server
* - navigate: The navigation function for navigating to different pages
*
*/
export function InvenTreeTable<T extends Record<string, any>>({
url,
tableState,
tableData,
columns,
props
}: Readonly<{
url?: string;
tableState: TableState;
tableData?: T[];
columns: TableColumn<T>[];
props: InvenTreeTableProps<T>;
}>) {
const api = useApi();
const navigate = useNavigate();
const { showContextMenu } = useContextMenu();
// Extract URL query parameters (e.g. ?active=true&overdue=false)
// Note: These can only be used internally (i.e *not in plugin context)
const [searchParams, setSearchParams] = useSearchParams();
return (
<InvenTreeTableInternal
url={url}
tableState={tableState}
tableData={tableData}
columns={columns}
props={props}
api={api}
navigate={navigate}
searchParams={searchParams}
setSearchParams={setSearchParams}
showContextMenu={showContextMenu}
/>
);
}
@@ -23,19 +23,19 @@ import { useMemo, useState } from 'react';
import { Fragment } from 'react/jsx-runtime';
import { ActionButton } from '@lib/components/ActionButton';
import { Boundary } from '@lib/components/Boundary';
import { ButtonMenu } from '@lib/components/ButtonMenu';
import { SearchInput } from '@lib/components/SearchInput';
import { TableColumnSelect } from '@lib/components/TableColumnSelect';
import { resolveItem } from '@lib/functions/Conversion';
import type { TableFilter } from '@lib/types/Filters';
import type { TableState } from '@lib/types/Tables';
import type { InvenTreeTableProps } from '@lib/types/Tables';
import { showNotification } from '@mantine/notifications';
import { Boundary } from '../components/Boundary';
import { PrintingActions } from '../components/buttons/PrintingActions';
import { StylishText } from '../components/items/StylishText';
import useDataExport from '../hooks/UseDataExport';
import { useDeleteApiFormModal } from '../hooks/UseForm';
import { TableColumnSelect } from './ColumnSelect';
import { FilterPreview, FilterSelectDrawer } from './FilterSelectDrawer';
/**
@@ -48,6 +48,8 @@ export default function InvenTreeTableHeader({
hasSwitchableColumns,
columns,
filters,
queryFilters,
clearQueryFilters,
toggleColumn
}: Readonly<{
tableUrl?: string;
@@ -56,6 +58,8 @@ export default function InvenTreeTableHeader({
hasSwitchableColumns: boolean;
columns: any;
filters: TableFilter[];
queryFilters?: URLSearchParams;
clearQueryFilters: () => void;
toggleColumn: (column: string) => void;
}>) {
// Filter list visibility
@@ -80,8 +84,8 @@ export default function InvenTreeTableHeader({
}
// Allow overriding of query parameters
if (tableState.queryFilters) {
for (const [key, value] of tableState.queryFilters) {
if (queryFilters) {
for (const [key, value] of queryFilters) {
if (value != undefined) {
filters[key] = value;
}
@@ -89,7 +93,7 @@ export default function InvenTreeTableHeader({
}
return filters;
}, [tableProps.params, tableState.filterSet, tableState.queryFilters]);
}, [tableProps.params, tableState.filterSet, queryFilters]);
const exportModal = useDataExport({
url: tableUrl ?? '',
@@ -139,12 +143,12 @@ export default function InvenTreeTableHeader({
});
const hasCustomSearch = useMemo(() => {
return tableState.queryFilters.has('search');
}, [tableState.queryFilters]);
return queryFilters?.has('search');
}, [queryFilters]);
const hasCustomFilters = useMemo(() => {
return (tableState?.queryFilters?.size ?? 0) > 0;
}, [tableState.queryFilters]);
return (queryFilters?.size ?? 0) > 0;
}, [queryFilters]);
// Extract ID values for label and report printing
const printingIdValues = useMemo(() => {
@@ -174,7 +178,7 @@ export default function InvenTreeTableHeader({
color='yellow'
withCloseButton
title={t`Custom table filters are active`}
onClose={() => tableState.clearQueryFilters()}
onClose={() => clearQueryFilters()}
/>
)}
<Group justify='apart' grow wrap='nowrap'>
+1 -1
View File
@@ -9,6 +9,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { navigateToLink } from '@lib/functions/Navigation';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { t } from '@lingui/core/macro';
@@ -37,7 +38,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useImporterState } from '../../states/ImporterState';
import { useUserState } from '../../states/UserState';
import {
+1 -1
View File
@@ -5,13 +5,13 @@ import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { RowEditAction, UserRoles } from '@lib/index';
import type { TableFilter } from '@lib/types/Filters';
import type { RowAction, TableColumn } from '@lib/types/Tables';
import { formatDecimal } from '../../defaults/formatters';
import { bomItemFields } from '../../forms/BomForms';
import { useEditApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DescriptionColumn,
@@ -6,6 +6,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { ActionButton, formatDecimal } from '@lib/index';
import type { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
@@ -19,7 +20,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DecimalColumn,
@@ -22,6 +22,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { formatDecimal } from '@lib/functions/Formatting';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { RowAction, TableColumn } from '@lib/types/Tables';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
@@ -38,7 +39,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import useStatusCodes from '../../hooks/UseStatusCodes';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
BooleanColumn,
@@ -7,10 +7,10 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { useBuildOrderFields } from '../../forms/BuildForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
import {
@@ -28,6 +28,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -52,7 +53,6 @@ import {
} from '../../hooks/UseForm';
import useStatusCodes from '../../hooks/UseStatusCodes';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
LocationColumn,
@@ -11,6 +11,7 @@ import { YesNoButton } from '@lib/components/YesNoButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import {
@@ -18,7 +19,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { LinkColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -9,13 +9,13 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { navigateToLink } from '@lib/functions/Navigation';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { companyFields } from '../../forms/CompanyForms';
import {
useCreateApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
BooleanColumn,
@@ -12,6 +12,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import { useNavigate } from 'react-router-dom';
@@ -21,7 +22,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -22,6 +22,7 @@ import {
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import type { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -33,7 +34,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -1,5 +1,6 @@
import { ActionButton } from '@lib/components/ActionButton';
import { type RowAction, RowViewAction } from '@lib/components/RowActions';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { t } from '@lingui/core/macro';
import { IconTrash } from '@tabler/icons-react';
@@ -7,7 +8,6 @@ import { useCallback, useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import type { BarcodeScanItem } from '../../components/barcodes/BarcodeScanItem';
import { RenderInstance } from '../../components/render/Instance';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -11,6 +11,7 @@ import {
import type { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import type { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency } from '../../defaults/formatters';
import { extraLineItemFields } from '../../forms/CommonForms';
@@ -19,7 +20,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DecimalColumn,
@@ -1,3 +1,4 @@
import useTable from '@lib/hooks/UseTable';
import {
ApiEndpoints,
ModelType,
@@ -20,7 +21,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useImporterState } from '../../states/ImporterState';
import { useUserState } from '../../states/UserState';
import {
@@ -1,3 +1,4 @@
import useTable from '@lib/hooks/UseTable';
import {
AddItemButton,
ApiEndpoints,
@@ -18,7 +19,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -1,4 +1,5 @@
import { cancelEvent } from '@lib/functions/Events';
import useTable from '@lib/hooks/UseTable';
import {
ApiEndpoints,
type ApiFormFieldSet,
@@ -25,7 +26,6 @@ import {
useCreateApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { InvenTreeTable } from '../InvenTreeTable';
import { TableHoverCard } from '../TableHoverCard';
@@ -26,6 +26,7 @@ import { AddItemButton } from '@lib/components/AddItemButton';
import { YesNoButton } from '@lib/components/YesNoButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import { RowDeleteAction, RowEditAction, formatDecimal } from '@lib/index';
import type { RowAction, TableColumn } from '@lib/types/Tables';
import type { InvenTreeTableProps } from '@lib/types/Tables';
@@ -54,7 +55,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { BooleanColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
import type { MachineDriverI, MachineTypeI } from './MachineTypeTable';
@@ -20,12 +20,12 @@ import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import type { InvenTreeTableProps } from '@lib/types/Tables';
import { InfoItem } from '../../components/items/InfoItem';
import { StylishText } from '../../components/items/StylishText';
import { DetailDrawer } from '../../components/nav/DetailDrawer';
import { useTable } from '../../hooks/UseTable';
import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
import { MachineListTable, useMachineTypeDriver } from './MachineListTable';
@@ -10,10 +10,10 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { IconCircleCheck } from '@tabler/icons-react';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DescriptionColumn,
@@ -10,6 +10,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { ActionDropdown } from '../../components/items/ActionDropdown';
@@ -21,7 +22,6 @@ import {
useCreateApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -11,6 +11,7 @@ import {
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -19,7 +20,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -6,10 +6,10 @@ import { ProgressBar } from '@lib/components/ProgressBar';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency, formatDecimal } from '../../defaults/formatters';
import { useTable } from '../../hooks/UseTable';
import { DateColumn, ReferenceColumn, StatusColumn } from '../ColumnRenderers';
import { IncludeVariantsFilter, StatusFilterOptions } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -10,9 +10,9 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DescriptionColumn,
+1 -1
View File
@@ -7,6 +7,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -33,7 +34,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import { usePluginsWithMixin } from '../../hooks/UsePlugins';
import { useTable } from '../../hooks/UseTable';
import { useImporterState } from '../../states/ImporterState';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
@@ -15,6 +15,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import { cancelEvent } from '@lib/functions/Events';
import useTable from '@lib/hooks/UseTable';
import { AddItemButton } from '@lib/index';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
@@ -25,7 +26,6 @@ import { useApi } from '../../contexts/ApiContext';
import { formatDate } from '../../defaults/formatters';
import { useTestResultFields } from '../../forms/StockForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { LocationColumn, PartColumn } from '../ColumnRenderers';
import {
BatchFilter,
@@ -17,6 +17,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -25,7 +26,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -12,6 +12,7 @@ import {
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import { Thumbnail } from '../../components/images/Thumbnail';
@@ -20,7 +21,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { NoteColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -10,6 +10,7 @@ import {
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { selectionListFields } from '../../forms/selectionListFields';
import {
@@ -17,7 +18,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -4,8 +4,8 @@ import { useMemo } from 'react';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { useTable } from '../../hooks/UseTable';
import { InvenTreeTable } from '../InvenTreeTable';
export interface PluginRegistryErrorI {
@@ -17,6 +17,7 @@ import { ActionButton } from '@lib/components/ActionButton';
import type { RowAction } from '@lib/components/RowActions';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableColumn } from '@lib/types/Tables';
import { DetailDrawer } from '../../components/nav/DetailDrawer';
import PluginDrawer from '../../components/plugins/PluginDrawer';
@@ -27,7 +28,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useServerApiState } from '../../states/ServerApiState';
import { useUserState } from '../../states/UserState';
import { BooleanColumn, LinkColumn } from '../ColumnRenderers';
@@ -12,6 +12,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { useManufacturerPartFields } from '../../forms/CompanyForms';
@@ -20,7 +21,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
CompanyColumn,
@@ -18,6 +18,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { formatDecimal } from '@lib/functions/Formatting';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { useNavigate } from 'react-router-dom';
@@ -34,7 +35,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import useStatusCodes from '../../hooks/UseStatusCodes';
import { useTable } from '../../hooks/UseTable';
import { useImporterState } from '../../states/ImporterState';
import { useUserState } from '../../states/UserState';
import {
@@ -6,11 +6,11 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { formatCurrency } from '../../defaults/formatters';
import { usePurchaseOrderFields } from '../../forms/PurchaseOrderForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
CompanyColumn,
@@ -14,6 +14,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { IconPackageImport } from '@tabler/icons-react';
@@ -25,7 +26,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import { usePluginsWithMixin } from '../../hooks/UsePlugins';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
BooleanColumn,
@@ -13,6 +13,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency } from '../../defaults/formatters';
@@ -21,7 +22,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import { CompanyColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -13,6 +13,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { formatCurrency } from '../../defaults/formatters';
@@ -26,7 +27,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import useStatusCodes from '../../hooks/UseStatusCodes';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DateColumn,
@@ -6,11 +6,11 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { formatCurrency } from '../../defaults/formatters';
import { useReturnOrderFields } from '../../forms/ReturnOrderForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
CompanyColumn,
@@ -11,6 +11,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
@@ -25,7 +26,6 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DescriptionColumn,
@@ -25,6 +25,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { RenderPart } from '../../components/render/Part';
@@ -41,7 +42,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
DateColumn,
@@ -19,6 +19,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import {
@@ -33,7 +34,6 @@ import {
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
CompanyColumn,
@@ -7,11 +7,11 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { formatCurrency } from '../../defaults/formatters';
import { useSalesOrderFields } from '../../forms/SalesOrderForms';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useUserState } from '../../states/UserState';
import {
AllocatedLinesProgressColumn,
@@ -1,7 +1,9 @@
import { AddItemButton } from '@lib/components/AddItemButton';
import { CopyButton } from '@lib/components/CopyButton';
import type { RowAction } from '@lib/components/RowActions';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
@@ -10,11 +12,9 @@ import { useDisclosure } from '@mantine/hooks';
import { IconCircleX } from '@tabler/icons-react';
import { useCallback, useMemo, useState } from 'react';
import { api } from '../../App';
import { CopyButton } from '../../components/buttons/CopyButton';
import { StylishText } from '../../components/items/StylishText';
import { showApiErrorMessage } from '../../functions/notifications';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { BooleanColumn, UserColumn } from '../ColumnRenderers';
import { UserFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable';
@@ -14,19 +14,19 @@ import { useDisclosure } from '@mantine/hooks';
import { IconExclamationCircle } from '@tabler/icons-react';
import { useCallback, useMemo, useState } from 'react';
import { CopyButton } from '@lib/components/CopyButton';
import { RowDeleteAction } from '@lib/components/RowActions';
import { PassFailButton } from '@lib/components/YesNoButton';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import { shortenString } from '@lib/functions/String';
import useTable from '@lib/hooks/UseTable';
import type { TableFilter } from '@lib/types/Filters';
import type { TableColumn } from '@lib/types/Tables';
import { CopyButton } from '../../components/buttons/CopyButton';
import { StylishText } from '../../components/items/StylishText';
import { RenderUser } from '../../components/render/User';
import { shortenString } from '../../functions/tables';
import { useDeleteApiFormModal } from '../../hooks/UseForm';
import { useTable } from '../../hooks/UseTable';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
import { UserFilter } from '../Filter';

Some files were not shown because too many files have changed in this diff Show More