mirror of
https://github.com/inventree/InvenTree.git
synced 2026-04-14 23:38:53 +00:00
[UI] Import context (#11685)
* Refactor ImporterDrawer - Use a single, globally accessible object - Provide global state management * Expose global importer state to the plugin interface * Improve registration of data import serializers * Update frontend version / docs * Bump API version
This commit is contained in:
@@ -1,11 +1,14 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 470
|
INVENTREE_API_VERSION = 471
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
|
||||||
|
v471 -> 2026-04-07 : https://github.com/inventree/InvenTree/pull/11685
|
||||||
|
- Adds data importer support for the "SalesOrderShipment" model
|
||||||
|
|
||||||
v470 -> 2026-04-01 : https://github.com/inventree/InvenTree/pull/11659
|
v470 -> 2026-04-01 : https://github.com/inventree/InvenTree/pull/11659
|
||||||
- Renames "is_staff" field to "is_admin" and updates help texts accordingly to highlight current security boundaries
|
- Renames "is_staff" field to "is_admin" and updates help texts accordingly to highlight current security boundaries
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ class DataImportSerializerRegister:
|
|||||||
def register(self, serializer) -> None:
|
def register(self, serializer) -> None:
|
||||||
"""Register a new serializer with the importer registry."""
|
"""Register a new serializer with the importer registry."""
|
||||||
if not issubclass(serializer, DataImportSerializerMixin):
|
if not issubclass(serializer, DataImportSerializerMixin):
|
||||||
logger.debug('Invalid serializer class: %s', type(serializer))
|
logger.debug('Invalid serializer class: %s', serializer.__name__)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not issubclass(serializer, Serializer):
|
if not issubclass(serializer, Serializer):
|
||||||
logger.debug('Invalid serializer class: %s', type(serializer))
|
logger.debug('Invalid serializer class: %s', serializer.__name__)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug('Registering serializer class for import: %s', type(serializer))
|
logger.debug('Registering serializer class for import: %s', serializer.__name__)
|
||||||
|
|
||||||
if serializer not in self.supported_serializers:
|
if serializer not in self.supported_serializers:
|
||||||
self.supported_serializers.append(serializer)
|
self.supported_serializers.append(serializer)
|
||||||
|
|||||||
@@ -1297,7 +1297,10 @@ class SalesOrderLineItemSerializer(
|
|||||||
|
|
||||||
@register_importer()
|
@register_importer()
|
||||||
class SalesOrderShipmentSerializer(
|
class SalesOrderShipmentSerializer(
|
||||||
FilterableSerializerMixin, NotesFieldMixin, InvenTreeModelSerializer
|
DataImportExportSerializerMixin,
|
||||||
|
FilterableSerializerMixin,
|
||||||
|
NotesFieldMixin,
|
||||||
|
InvenTreeModelSerializer,
|
||||||
):
|
):
|
||||||
"""Serializer for the SalesOrderShipment class."""
|
"""Serializer for the SalesOrderShipment class."""
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
This file contains historical changelog information for the InvenTree UI components library.
|
This file contains historical changelog information for the InvenTree UI components library.
|
||||||
|
|
||||||
|
### 0.10.0 - April 2026
|
||||||
|
|
||||||
|
Exposes the `importer` object to the plugin context, allow plugins to initialize a data import session using the data importer wizard.
|
||||||
|
|
||||||
### 0.9.0 - March 2026
|
### 0.9.0 - March 2026
|
||||||
|
|
||||||
Exposes the `useMonitorBackgroundTask` hook, which allows plugins to monitor the status of a background task and display notifications when the task is complete. This is useful for plugins that offload long-running tasks to the background and want to provide feedback to the user when the task is complete.
|
Exposes the `useMonitorBackgroundTask` hook, which allows plugins to monitor the status of a background task and display notifications when the task is complete. This is useful for plugins that offload long-running tasks to the background and want to provide feedback to the user when the task is complete.
|
||||||
|
|||||||
@@ -48,6 +48,13 @@ export type InvenTreeFormsContext = {
|
|||||||
stockActions: StockAdjustmentFormsContext;
|
stockActions: StockAdjustmentFormsContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ImporterDrawerContext = {
|
||||||
|
open: (sessionId: number, options?: { onClose?: () => void }) => void;
|
||||||
|
close: () => void;
|
||||||
|
isOpen: () => boolean;
|
||||||
|
sessionId: () => number | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of properties which are passed to a plugin,
|
* A set of properties which are passed to a plugin,
|
||||||
* for rendering an element in the user interface.
|
* for rendering an element in the user interface.
|
||||||
@@ -59,6 +66,8 @@ export type InvenTreeFormsContext = {
|
|||||||
* @param globalSettings - The global settings (see ../states/SettingsState.tsx)
|
* @param globalSettings - The global settings (see ../states/SettingsState.tsx)
|
||||||
* @param navigate - The navigation function (see react-router-dom)
|
* @param navigate - The navigation function (see react-router-dom)
|
||||||
* @param theme - The current Mantine theme
|
* @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 colorScheme - The current Mantine color scheme (e.g. 'light' / 'dark')
|
||||||
* @param host - The current host URL
|
* @param host - The current host URL
|
||||||
* @param i18n - The i18n instance for translations (from @lingui/core)
|
* @param i18n - The i18n instance for translations (from @lingui/core)
|
||||||
@@ -87,6 +96,7 @@ export type InvenTreePluginContext = {
|
|||||||
navigate: NavigateFunction;
|
navigate: NavigateFunction;
|
||||||
theme: MantineTheme;
|
theme: MantineTheme;
|
||||||
forms: InvenTreeFormsContext;
|
forms: InvenTreeFormsContext;
|
||||||
|
importer: ImporterDrawerContext;
|
||||||
colorScheme: MantineColorScheme;
|
colorScheme: MantineColorScheme;
|
||||||
model?: ModelType | string;
|
model?: ModelType | string;
|
||||||
id?: string | number | null;
|
id?: string | number | null;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@inventreedb/ui",
|
"name": "@inventreedb/ui",
|
||||||
"description": "UI components for the InvenTree project",
|
"description": "UI components for the InvenTree project",
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
|
import ImporterDrawer from './ImporterDrawer';
|
||||||
|
|
||||||
|
export default function GlobalImporterDrawer() {
|
||||||
|
const isOpen = useImporterState((state) => state.isOpen);
|
||||||
|
const sessionId = useImporterState((state) => state.sessionId);
|
||||||
|
const closeImporter = useImporterState((state) => state.closeImporter);
|
||||||
|
|
||||||
|
if (!isOpen || sessionId === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImporterDrawer
|
||||||
|
sessionId={sessionId}
|
||||||
|
opened={isOpen}
|
||||||
|
onClose={closeImporter}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
} from '../../states/SettingsStates';
|
} from '../../states/SettingsStates';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import { Boundary } from '../Boundary';
|
import { Boundary } from '../Boundary';
|
||||||
|
import GlobalImporterDrawer from '../importer/GlobalImporterDrawer';
|
||||||
import { ApiIcon } from '../items/ApiIcon';
|
import { ApiIcon } from '../items/ApiIcon';
|
||||||
import { useInvenTreeContext } from '../plugins/PluginContext';
|
import { useInvenTreeContext } from '../plugins/PluginContext';
|
||||||
import { callExternalPluginFunction } from '../plugins/PluginSource';
|
import { callExternalPluginFunction } from '../plugins/PluginSource';
|
||||||
@@ -118,6 +119,7 @@ export default function LayoutComponent() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
|
<>
|
||||||
<Flex direction='column' mih='100vh'>
|
<Flex direction='column' mih='100vh'>
|
||||||
<Header />
|
<Header />
|
||||||
<Container className={classes.layoutContent} size='100%'>
|
<Container className={classes.layoutContent} size='100%'>
|
||||||
@@ -143,6 +145,8 @@ export default function LayoutComponent() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<GlobalImporterDrawer />
|
||||||
|
</>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ import {
|
|||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
|
import {
|
||||||
|
type ImporterOpenOptions,
|
||||||
|
closeGlobalImporter,
|
||||||
|
getGlobalImporterState,
|
||||||
|
openGlobalImporter
|
||||||
|
} from '../../states/ImporterState';
|
||||||
import { useServerApiState } from '../../states/ServerApiState';
|
import { useServerApiState } from '../../states/ServerApiState';
|
||||||
import { RenderInstance } from '../render/Instance';
|
import { RenderInstance } from '../render/Instance';
|
||||||
|
|
||||||
@@ -70,6 +76,13 @@ export const useInvenTreeContext = () => {
|
|||||||
renderInstance: RenderInstance,
|
renderInstance: RenderInstance,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
colorScheme: colorScheme,
|
colorScheme: colorScheme,
|
||||||
|
importer: {
|
||||||
|
open: (sessionId: number, options?: ImporterOpenOptions) =>
|
||||||
|
openGlobalImporter(sessionId, options),
|
||||||
|
close: () => closeGlobalImporter(),
|
||||||
|
isOpen: () => getGlobalImporterState().isOpen,
|
||||||
|
sessionId: () => getGlobalImporterState().sessionId
|
||||||
|
},
|
||||||
forms: {
|
forms: {
|
||||||
bulkEdit: useBulkEditApiFormModal,
|
bulkEdit: useBulkEditApiFormModal,
|
||||||
create: useCreateApiFormModal,
|
create: useCreateApiFormModal,
|
||||||
|
|||||||
62
src/frontend/src/states/ImporterState.tsx
Normal file
62
src/frontend/src/states/ImporterState.tsx
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* This file contains a global state manager for the importer drawer, allowing it to be opened and closed from anywhere in the app without needing to pass props down through the component tree.
|
||||||
|
* The state includes the current session ID for the importer, as well as an optional callback function that can be executed when the importer is closed.
|
||||||
|
* This allows for flexible handling of importer actions, such as refreshing data after an import is completed.
|
||||||
|
* The state is managed using the Zustand library, which provides a simple and efficient way to create global state in React applications.
|
||||||
|
* The `useImporterState` hook can be used to access and manipulate the importer state from any component, while the `openGlobalImporter` and `closeGlobalImporter` functions provide convenient ways to control the importer from outside of React components.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
export interface ImporterOpenOptions {
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImporterStateProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
sessionId: number | null;
|
||||||
|
onCloseCallback?: () => void;
|
||||||
|
openImporter: (sessionId: number, options?: ImporterOpenOptions) => void;
|
||||||
|
closeImporter: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useImporterState = create<ImporterStateProps>()((set, get) => ({
|
||||||
|
isOpen: false,
|
||||||
|
sessionId: null,
|
||||||
|
onCloseCallback: undefined,
|
||||||
|
|
||||||
|
openImporter: (sessionId: number, options?: ImporterOpenOptions) => {
|
||||||
|
set({
|
||||||
|
sessionId,
|
||||||
|
isOpen: true,
|
||||||
|
onCloseCallback: options?.onClose
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeImporter: () => {
|
||||||
|
const callback = get().onCloseCallback;
|
||||||
|
|
||||||
|
set({
|
||||||
|
sessionId: null,
|
||||||
|
isOpen: false,
|
||||||
|
onCloseCallback: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
callback?.();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
export function openGlobalImporter(
|
||||||
|
sessionId: number,
|
||||||
|
options?: ImporterOpenOptions
|
||||||
|
) {
|
||||||
|
useImporterState.getState().openImporter(sessionId, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeGlobalImporter() {
|
||||||
|
useImporterState.getState().closeImporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getGlobalImporterState() {
|
||||||
|
return useImporterState.getState();
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ import {
|
|||||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Thumbnail } from '../../components/images/Thumbnail';
|
import { Thumbnail } from '../../components/images/Thumbnail';
|
||||||
import ImporterDrawer from '../../components/importer/ImporterDrawer';
|
|
||||||
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
||||||
import { RenderPart } from '../../components/render/Part';
|
import { RenderPart } from '../../components/render/Part';
|
||||||
import { useApi } from '../../contexts/ApiContext';
|
import { useApi } from '../../contexts/ApiContext';
|
||||||
@@ -39,6 +38,7 @@ import {
|
|||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import { useTable } from '../../hooks/UseTable';
|
import { useTable } from '../../hooks/UseTable';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import {
|
import {
|
||||||
BooleanColumn,
|
BooleanColumn,
|
||||||
@@ -81,12 +81,7 @@ export function BomTable({
|
|||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
const table = useTable('bom');
|
const table = useTable('bom');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
const [importOpened, setImportOpened] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
@@ -501,8 +496,9 @@ export function BomTable({
|
|||||||
title: t`Import BOM Data`,
|
title: t`Import BOM Data`,
|
||||||
fields: importSessionFields,
|
fields: importSessionFields,
|
||||||
onFormSuccess: (response: any) => {
|
onFormSuccess: (response: any) => {
|
||||||
setSelectedSession(response.pk);
|
openImporter(response.pk, {
|
||||||
setImportOpened(true);
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -690,15 +686,6 @@ export function BomTable({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<ImporterDrawer
|
|
||||||
sessionId={selectedSession ?? -1}
|
|
||||||
opened={selectedSession != undefined && importOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedSession(undefined);
|
|
||||||
setImportOpened(false);
|
|
||||||
table.refreshTable();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import type { TableColumn } from '@lib/types/Tables';
|
|||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { IconFileUpload, IconPlus } from '@tabler/icons-react';
|
import { IconFileUpload, IconPlus } from '@tabler/icons-react';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import ImporterDrawer from '../../components/importer/ImporterDrawer';
|
|
||||||
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
||||||
import { useParameterFields } from '../../forms/CommonForms';
|
import { useParameterFields } from '../../forms/CommonForms';
|
||||||
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
@@ -22,6 +21,7 @@ import {
|
|||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import { useTable } from '../../hooks/UseTable';
|
import { useTable } from '../../hooks/UseTable';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import {
|
import {
|
||||||
DateColumn,
|
DateColumn,
|
||||||
@@ -129,12 +129,7 @@ export function ParameterTable({
|
|||||||
const [selectedParameter, setSelectedParameter] = useState<any | undefined>(
|
const [selectedParameter, setSelectedParameter] = useState<any | undefined>(
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
const [importOpened, setImportOpened] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
const importSessionFields = useMemo(() => {
|
const importSessionFields = useMemo(() => {
|
||||||
const fields = dataImporterSessionFields({
|
const fields = dataImporterSessionFields({
|
||||||
@@ -154,8 +149,9 @@ export function ParameterTable({
|
|||||||
title: t`Import Parameters`,
|
title: t`Import Parameters`,
|
||||||
fields: importSessionFields,
|
fields: importSessionFields,
|
||||||
onFormSuccess: (response: any) => {
|
onFormSuccess: (response: any) => {
|
||||||
setSelectedSession(response.pk);
|
openImporter(response.pk, {
|
||||||
setImportOpened(true);
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,15 +258,6 @@ export function ParameterTable({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ImporterDrawer
|
|
||||||
sessionId={selectedSession ?? -1}
|
|
||||||
opened={selectedSession !== undefined && importOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedSession(undefined);
|
|
||||||
setImportOpened(false);
|
|
||||||
table.refreshTable();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
IconShoppingCart
|
IconShoppingCart
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||||
import ImporterDrawer from '../../components/importer/ImporterDrawer';
|
|
||||||
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
import { ActionDropdown } from '../../components/items/ActionDropdown';
|
||||||
import ImportPartWizard from '../../components/wizards/ImportPartWizard';
|
import ImportPartWizard from '../../components/wizards/ImportPartWizard';
|
||||||
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
||||||
@@ -35,6 +34,7 @@ import {
|
|||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import { usePluginsWithMixin } from '../../hooks/UsePlugins';
|
import { usePluginsWithMixin } from '../../hooks/UsePlugins';
|
||||||
import { useTable } from '../../hooks/UseTable';
|
import { useTable } from '../../hooks/UseTable';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useGlobalSettingsState } from '../../states/SettingsStates';
|
import { useGlobalSettingsState } from '../../states/SettingsStates';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import {
|
import {
|
||||||
@@ -357,12 +357,7 @@ export function PartListTable({
|
|||||||
});
|
});
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
const globalSettings = useGlobalSettingsState();
|
const globalSettings = useGlobalSettingsState();
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
const [importOpened, setImportOpened] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
const importSessionFields = useMemo(() => {
|
const importSessionFields = useMemo(() => {
|
||||||
const fields = dataImporterSessionFields({
|
const fields = dataImporterSessionFields({
|
||||||
@@ -383,8 +378,9 @@ export function PartListTable({
|
|||||||
title: t`Import Parts`,
|
title: t`Import Parts`,
|
||||||
fields: importSessionFields,
|
fields: importSessionFields,
|
||||||
onFormSuccess: (response: any) => {
|
onFormSuccess: (response: any) => {
|
||||||
setSelectedSession(response.pk);
|
openImporter(response.pk, {
|
||||||
setImportOpened(true);
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -598,15 +594,6 @@ export function PartListTable({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ImporterDrawer
|
|
||||||
sessionId={selectedSession ?? -1}
|
|
||||||
opened={selectedSession != undefined && importOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedSession(undefined);
|
|
||||||
setImportOpened(false);
|
|
||||||
table.refreshTable();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { formatDecimal } from '@lib/functions/Formatting';
|
|||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import ImporterDrawer from '../../components/importer/ImporterDrawer';
|
|
||||||
import { RenderInstance } from '../../components/render/Instance';
|
import { RenderInstance } from '../../components/render/Instance';
|
||||||
import { formatCurrency } from '../../defaults/formatters';
|
import { formatCurrency } from '../../defaults/formatters';
|
||||||
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
@@ -36,6 +35,7 @@ import {
|
|||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import useStatusCodes from '../../hooks/UseStatusCodes';
|
import useStatusCodes from '../../hooks/UseStatusCodes';
|
||||||
import { useTable } from '../../hooks/UseTable';
|
import { useTable } from '../../hooks/UseTable';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { useGlobalSettingsState } from '../../states/SettingsStates';
|
import { useGlobalSettingsState } from '../../states/SettingsStates';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import {
|
import {
|
||||||
@@ -77,12 +77,7 @@ export function PurchaseOrderLineItemTable({
|
|||||||
const globalSettings = useGlobalSettingsState();
|
const globalSettings = useGlobalSettingsState();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
// Data import
|
|
||||||
const [importOpened, setImportOpened] = useState<boolean>(false);
|
|
||||||
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
const importSessionFields = useMemo(() => {
|
const importSessionFields = useMemo(() => {
|
||||||
const fields = dataImporterSessionFields({
|
const fields = dataImporterSessionFields({
|
||||||
@@ -115,8 +110,9 @@ export function PurchaseOrderLineItemTable({
|
|||||||
title: t`Import Line Items`,
|
title: t`Import Line Items`,
|
||||||
fields: importSessionFields,
|
fields: importSessionFields,
|
||||||
onFormSuccess: (response: any) => {
|
onFormSuccess: (response: any) => {
|
||||||
setSelectedSession(response.pk);
|
openImporter(response.pk, {
|
||||||
setImportOpened(true);
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -452,15 +448,6 @@ export function PurchaseOrderLineItemTable({
|
|||||||
modelField: 'part'
|
modelField: 'part'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ImporterDrawer
|
|
||||||
sessionId={selectedSession ?? -1}
|
|
||||||
opened={selectedSession != undefined && importOpened}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedSession(undefined);
|
|
||||||
setImportOpened(false);
|
|
||||||
table.refreshTable();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { ModelType } from '@lib/enums/ModelType';
|
|||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
import ImporterDrawer from '../../components/importer/ImporterDrawer';
|
|
||||||
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||||
import { RenderUser } from '../../components/render/User';
|
import { RenderUser } from '../../components/render/User';
|
||||||
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
@@ -19,14 +18,14 @@ import {
|
|||||||
useDeleteApiFormModal
|
useDeleteApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
import { useTable } from '../../hooks/UseTable';
|
import { useTable } from '../../hooks/UseTable';
|
||||||
|
import { useImporterState } from '../../states/ImporterState';
|
||||||
import { DateColumn, StatusColumn } from '../ColumnRenderers';
|
import { DateColumn, StatusColumn } from '../ColumnRenderers';
|
||||||
import { StatusFilterOptions, UserFilter } from '../Filter';
|
import { StatusFilterOptions, UserFilter } from '../Filter';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
export default function ImportSessionTable() {
|
export default function ImportSessionTable() {
|
||||||
const table = useTable('importsession');
|
const table = useTable('importsession');
|
||||||
|
const openImporter = useImporterState((state) => state.openImporter);
|
||||||
const [opened, setOpened] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
const [selectedSession, setSelectedSession] = useState<number | undefined>(
|
||||||
undefined
|
undefined
|
||||||
@@ -47,7 +46,9 @@ export default function ImportSessionTable() {
|
|||||||
}),
|
}),
|
||||||
onFormSuccess: (response: any) => {
|
onFormSuccess: (response: any) => {
|
||||||
setSelectedSession(response.pk);
|
setSelectedSession(response.pk);
|
||||||
setOpened(true);
|
openImporter(response.pk, {
|
||||||
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
table.refreshTable();
|
table.refreshTable();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -159,19 +160,12 @@ export default function ImportSessionTable() {
|
|||||||
enableSelection: true,
|
enableSelection: true,
|
||||||
onRowClick: (record: any) => {
|
onRowClick: (record: any) => {
|
||||||
setSelectedSession(record.pk);
|
setSelectedSession(record.pk);
|
||||||
setOpened(true);
|
openImporter(record.pk, {
|
||||||
|
onClose: table.refreshTable
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ImporterDrawer
|
|
||||||
sessionId={selectedSession ?? -1}
|
|
||||||
opened={selectedSession !== undefined && opened}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedSession(undefined);
|
|
||||||
setOpened(false);
|
|
||||||
table.refreshTable();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user