@inventreedb/ui 0.11.3 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/.vite/manifest.json +45 -5
  3. package/dist/_virtual/dynamic-import-helper.js +20 -0
  4. package/dist/_virtual/dynamic-import-helper.js.map +1 -0
  5. package/dist/components/Boundary.js +5 -4
  6. package/dist/components/Boundary.js.map +1 -1
  7. package/dist/components/InvenTreeTable.js +4 -3
  8. package/dist/components/InvenTreeTable.js.map +1 -1
  9. package/dist/components/RowActions.js +3 -2
  10. package/dist/components/RowActions.js.map +1 -1
  11. package/dist/components/TableColumnSelect.js +1 -1
  12. package/dist/components/TableColumnSelect.js.map +1 -1
  13. package/dist/components/TagsList.d.ts +3 -0
  14. package/dist/components/TagsList.js +21 -0
  15. package/dist/components/TagsList.js.map +1 -0
  16. package/dist/components/nav/DetailDrawer.d.ts +1 -0
  17. package/dist/components/nav/DetailDrawer.js +1 -0
  18. package/dist/components/nav/DetailDrawer.js.map +1 -1
  19. package/dist/enums/ApiEndpoints.d.ts +15 -4
  20. package/dist/enums/ApiEndpoints.js +15 -4
  21. package/dist/enums/ApiEndpoints.js.map +1 -1
  22. package/dist/enums/ModelInformation.d.ts +1 -0
  23. package/dist/enums/ModelInformation.js +55 -2
  24. package/dist/enums/ModelInformation.js.map +1 -1
  25. package/dist/enums/ModelType.d.ts +4 -1
  26. package/dist/enums/ModelType.js +3 -0
  27. package/dist/enums/ModelType.js.map +1 -1
  28. package/dist/enums/Roles.d.ts +1 -0
  29. package/dist/enums/Roles.js +1 -0
  30. package/dist/enums/Roles.js.map +1 -1
  31. package/dist/functions/Events.js +4 -3
  32. package/dist/functions/Events.js.map +1 -1
  33. package/dist/functions/Navigation.js +6 -3
  34. package/dist/functions/Navigation.js.map +1 -1
  35. package/dist/functions/Plugins.js +4 -2
  36. package/dist/functions/Plugins.js.map +1 -1
  37. package/dist/hooks/MonitorBackgroundTask.js +10 -8
  38. package/dist/hooks/MonitorBackgroundTask.js.map +1 -1
  39. package/dist/hooks/MonitorDataOutput.js +4 -3
  40. package/dist/hooks/MonitorDataOutput.js.map +1 -1
  41. package/dist/hooks/UseFilterSet.js +45 -7
  42. package/dist/hooks/UseFilterSet.js.map +1 -1
  43. package/dist/hooks/UseTable.js +1 -1
  44. package/dist/index.d.ts +6 -1
  45. package/dist/index.js +20 -11
  46. package/dist/index.js.map +1 -1
  47. package/dist/node_modules/@mantine/hooks/esm/use-debounced-value/use-debounced-value.js +40 -15
  48. package/dist/node_modules/@mantine/hooks/esm/use-debounced-value/use-debounced-value.js.map +1 -1
  49. package/dist/node_modules/@mantine/hooks/esm/use-document-visibility/use-document-visibility.js +1 -1
  50. package/dist/node_modules/@mantine/hooks/esm/use-document-visibility/use-document-visibility.js.map +1 -1
  51. package/dist/node_modules/@mantine/hooks/esm/use-local-storage/create-storage.js +57 -62
  52. package/dist/node_modules/@mantine/hooks/esm/use-local-storage/create-storage.js.map +1 -1
  53. package/dist/node_modules/@mantine/hooks/esm/use-local-storage/use-local-storage.js.map +1 -1
  54. package/dist/node_modules/@mantine/hooks/esm/use-window-event/use-window-event.js +5 -3
  55. package/dist/node_modules/@mantine/hooks/esm/use-window-event/use-window-event.js.map +1 -1
  56. package/dist/node_modules/@mantine/hooks/esm/utils/random-id/random-id.js.map +1 -1
  57. package/dist/node_modules/@remix-run/router/dist/router.js +10 -0
  58. package/dist/node_modules/@remix-run/router/dist/router.js.map +1 -1
  59. package/dist/node_modules/@sentry/browser/build/npm/esm/prod/report-dialog.js +2 -2
  60. package/dist/node_modules/@sentry/browser/build/npm/esm/prod/report-dialog.js.map +1 -1
  61. package/dist/node_modules/@sentry/core/build/esm/scope.js +6 -5
  62. package/dist/node_modules/@sentry/core/build/esm/scope.js.map +1 -1
  63. package/dist/node_modules/@sentry/core/build/esm/utils/chain-and-copy-promiselike.js +1 -1
  64. package/dist/node_modules/@sentry/core/build/esm/utils/chain-and-copy-promiselike.js.map +1 -1
  65. package/dist/node_modules/@sentry/core/build/esm/utils/is.js +1 -1
  66. package/dist/node_modules/@sentry/core/build/esm/utils/is.js.map +1 -1
  67. package/dist/node_modules/@sentry/core/build/esm/utils/misc.js +1 -1
  68. package/dist/node_modules/@sentry/core/build/esm/utils/misc.js.map +1 -1
  69. package/dist/node_modules/@sentry/core/build/esm/utils/randomSafeContext.js +1 -1
  70. package/dist/node_modules/@sentry/core/build/esm/utils/randomSafeContext.js.map +1 -1
  71. package/dist/node_modules/@sentry/core/build/esm/utils/time.js +1 -1
  72. package/dist/node_modules/@sentry/core/build/esm/utils/time.js.map +1 -1
  73. package/dist/node_modules/@tabler/icons-react/dist/esm/createReactComponent.js +6 -0
  74. package/dist/node_modules/@tabler/icons-react/dist/esm/createReactComponent.js.map +1 -1
  75. package/dist/node_modules/@tabler/icons-react/dist/esm/defaultAttributes.js +6 -0
  76. package/dist/node_modules/@tabler/icons-react/dist/esm/defaultAttributes.js.map +1 -1
  77. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconAdjustments.js +6 -0
  78. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconAdjustments.js.map +1 -1
  79. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowRight.js +6 -0
  80. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowRight.js.map +1 -1
  81. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.js +6 -0
  82. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.js.map +1 -1
  83. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.js +6 -0
  84. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.js.map +1 -1
  85. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCircleCheck.js +6 -0
  86. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCircleCheck.js.map +1 -1
  87. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCircleX.js +6 -0
  88. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCircleX.js.map +1 -1
  89. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.js +6 -0
  90. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.js.map +1 -1
  91. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.js +6 -0
  92. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.js.map +1 -1
  93. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconEdit.js +6 -0
  94. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconEdit.js.map +1 -1
  95. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconExclamationCircle.js +6 -0
  96. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconExclamationCircle.js.map +1 -1
  97. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconPlus.js +6 -0
  98. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconPlus.js.map +1 -1
  99. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconSearch.js +6 -0
  100. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconSearch.js.map +1 -1
  101. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconTag.js +14 -0
  102. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconTag.js.map +1 -0
  103. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconTrash.js +6 -0
  104. package/dist/node_modules/@tabler/icons-react/dist/esm/icons/IconTrash.js.map +1 -1
  105. package/dist/node_modules/@tanstack/query-core/build/modern/focusManager.js +31 -20
  106. package/dist/node_modules/@tanstack/query-core/build/modern/focusManager.js.map +1 -1
  107. package/dist/node_modules/@tanstack/query-core/build/modern/onlineManager.js +27 -17
  108. package/dist/node_modules/@tanstack/query-core/build/modern/onlineManager.js.map +1 -1
  109. package/dist/node_modules/@tanstack/query-core/build/modern/queryObserver.js +179 -177
  110. package/dist/node_modules/@tanstack/query-core/build/modern/queryObserver.js.map +1 -1
  111. package/dist/node_modules/@tanstack/query-core/build/modern/timeoutManager.js +31 -21
  112. package/dist/node_modules/@tanstack/query-core/build/modern/timeoutManager.js.map +1 -1
  113. package/dist/node_modules/@tanstack/react-query/build/modern/errorBoundaryUtils.js +1 -1
  114. package/dist/node_modules/@tanstack/react-query/build/modern/errorBoundaryUtils.js.map +1 -1
  115. package/dist/node_modules/@tanstack/react-query/build/modern/suspense.js +1 -1
  116. package/dist/node_modules/@tanstack/react-query/build/modern/suspense.js.map +1 -1
  117. package/dist/node_modules/@tanstack/react-query/build/modern/useBaseQuery.js +7 -4
  118. package/dist/node_modules/@tanstack/react-query/build/modern/useBaseQuery.js.map +1 -1
  119. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +10 -1
  120. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -1
  121. package/dist/node_modules/react/cjs/react-jsx-runtime.production.js +10 -1
  122. package/dist/node_modules/react/cjs/react-jsx-runtime.production.js.map +1 -1
  123. package/dist/node_modules/react-router/dist/index.js +11 -1
  124. package/dist/node_modules/react-router/dist/index.js.map +1 -1
  125. package/dist/node_modules/react-router-dom/dist/index.js +10 -0
  126. package/dist/node_modules/react-router-dom/dist/index.js.map +1 -1
  127. package/dist/plugin/InventreeHmrPlugin.d.ts +8 -0
  128. package/dist/plugin/InventreeHmrPlugin.js +21 -0
  129. package/dist/plugin/InventreeHmrPlugin.js.map +1 -0
  130. package/dist/plugin/LocalizedComponent.d.ts +9 -0
  131. package/dist/plugin/LocalizedComponent.js +57 -0
  132. package/dist/plugin/LocalizedComponent.js.map +1 -0
  133. package/dist/states/StoredTableState.js +2 -1
  134. package/dist/states/StoredTableState.js.map +1 -1
  135. package/dist/states/types.d.ts +3 -0
  136. package/dist/types/Filters.d.ts +11 -0
  137. package/dist/types/Forms.d.ts +6 -1
  138. package/dist/types/Panel.d.ts +26 -0
  139. package/dist/types/Plugins.d.ts +14 -2
  140. package/dist/types/Plugins.js +2 -2
  141. package/dist/types/Plugins.js.map +1 -1
  142. package/dist/types/Rendering.d.ts +54 -0
  143. package/dist/types/Tables.d.ts +7 -3
  144. package/lib/components/Boundary.tsx +7 -3
  145. package/lib/components/RowActions.tsx +2 -2
  146. package/lib/components/TableColumnSelect.tsx +1 -1
  147. package/lib/components/TagsList.tsx +27 -0
  148. package/lib/components/nav/DetailDrawer.tsx +1 -1
  149. package/lib/enums/ApiEndpoints.tsx +18 -4
  150. package/lib/enums/ModelInformation.tsx +26 -2
  151. package/lib/enums/ModelType.tsx +4 -1
  152. package/lib/enums/Roles.tsx +3 -0
  153. package/lib/functions/Navigation.tsx +1 -1
  154. package/lib/hooks/UseFilterSet.tsx +62 -11
  155. package/lib/index.ts +14 -1
  156. package/lib/plugin/InventreeHmrPlugin.tsx +40 -0
  157. package/lib/plugin/LocalizedComponent.tsx +85 -0
  158. package/lib/states/types.tsx +7 -0
  159. package/lib/types/Filters.tsx +19 -0
  160. package/lib/types/Forms.tsx +7 -1
  161. package/lib/types/Panel.tsx +30 -0
  162. package/lib/types/Plugins.tsx +20 -1
  163. package/lib/types/Rendering.tsx +61 -0
  164. package/lib/types/Tables.tsx +8 -3
  165. package/package.json +19 -18
@@ -0,0 +1,26 @@
1
+ import { ReactNode } from 'react';
2
+ export type PanelIndicatorType = 'info' | 'warning' | 'danger' | null;
3
+ /**
4
+ * Type used to specify a single panel in a panel group
5
+ */
6
+ export type PanelType = {
7
+ name: string;
8
+ label: string;
9
+ controls?: ReactNode;
10
+ icon?: ReactNode;
11
+ notification_dot?: PanelIndicatorType | (() => Promise<PanelIndicatorType>);
12
+ content?: ReactNode;
13
+ hidden?: boolean;
14
+ disabled?: boolean;
15
+ showHeadline?: boolean;
16
+ supportsDirty?: boolean;
17
+ };
18
+ /**
19
+ * Type used to specify a group of panels
20
+ */
21
+ export type PanelGroupType = {
22
+ id: string;
23
+ label: string;
24
+ panelIDs?: string[];
25
+ panels?: PanelType[];
26
+ };
@@ -2,12 +2,14 @@ import { I18n } from '@lingui/core';
2
2
  import { MantineColorScheme, MantineTheme } from '@mantine/core';
3
3
  import { QueryClient } from '@tanstack/react-query';
4
4
  import { AxiosInstance } from 'axios';
5
+ import { JSX } from 'react';
5
6
  import { NavigateFunction } from 'react-router-dom';
6
7
  import { ModelDict } from '../enums/ModelInformation';
7
8
  import { ModelType } from '../enums/ModelType';
8
- import { ApiFormModalProps, BulkEditApiFormModalProps, StockOperationProps } from './Forms';
9
+ import { setRenderProps } from '../states/types';
10
+ import { ApiFormModalProps, ApiFormProps, BulkEditApiFormModalProps, StockOperationProps } from './Forms';
9
11
  import { UseModalReturn } from './Modals';
10
- import { RenderInstanceProps } from './Rendering';
12
+ import { RemoteInstanceProps, RenderInlineModelProps, RenderInstanceProps, ThumbnailProps } from './Rendering';
11
13
  import { SettingsStateProps } from './Settings';
12
14
  import { InvenTreeTableRenderProps } from './Tables';
13
15
  import { UserStateProps } from './User';
@@ -38,6 +40,10 @@ export type InvenTreeFormsContext = {
38
40
  create: (props: ApiFormModalProps) => UseModalReturn;
39
41
  delete: (props: ApiFormModalProps) => UseModalReturn;
40
42
  edit: (props: ApiFormModalProps) => UseModalReturn;
43
+ editApiForm: (props: {
44
+ id?: string;
45
+ props: ApiFormProps;
46
+ }) => React.ReactNode;
41
47
  stockActions: StockAdjustmentFormsContext;
42
48
  };
43
49
  export type InvenTreeTablesContext<T extends Record<string, any>> = {
@@ -88,6 +94,9 @@ export type InvenTreePluginContext = {
88
94
  globalSettings: SettingsStateProps;
89
95
  modelInformation: ModelDict;
90
96
  renderInstance: (props: Readonly<RenderInstanceProps>) => React.ReactNode;
97
+ renderRemoteInstance: (props: Readonly<RemoteInstanceProps>) => React.ReactNode;
98
+ renderInlineModel: (props: Readonly<RenderInlineModelProps>) => React.ReactNode;
99
+ thumbnail: (props: Readonly<ThumbnailProps>) => JSX.Element;
91
100
  host: string;
92
101
  i18n: I18n;
93
102
  locale: string;
@@ -95,6 +104,9 @@ export type InvenTreePluginContext = {
95
104
  theme: MantineTheme;
96
105
  colorScheme: MantineColorScheme;
97
106
  forms: InvenTreeFormsContext;
107
+ stateFnc: {
108
+ setRenderer: setRenderProps;
109
+ };
98
110
  tables: InvenTreeTablesContext<any>;
99
111
  importer: ImporterDrawerContext;
100
112
  model?: ModelType | string;
@@ -1,10 +1,10 @@
1
- const INVENTREE_PLUGIN_VERSION = "0.11.3";
1
+ const INVENTREE_PLUGIN_VERSION = "1.4.1";
2
2
  const INVENTREE_REACT_VERSION = "19.2.4";
3
3
  const INVENTREE_REACT_DOM_VERSION = (
4
4
  // @ts-ignore
5
5
  "19.2.4"
6
6
  );
7
- const INVENTREE_MANTINE_VERSION = "8.2.7";
7
+ const INVENTREE_MANTINE_VERSION = "9.2.1";
8
8
  export {
9
9
  INVENTREE_MANTINE_VERSION,
10
10
  INVENTREE_PLUGIN_VERSION,
@@ -1 +1 @@
1
- {"version":3,"file":"Plugins.js","sources":["../../lib/types/Plugins.tsx"],"sourcesContent":["import type { I18n } from '@lingui/core';\nimport type { MantineColorScheme, MantineTheme } from '@mantine/core';\nimport type { QueryClient } from '@tanstack/react-query';\nimport type { AxiosInstance } from 'axios';\nimport type { NavigateFunction } from 'react-router-dom';\nimport type { ModelDict } from '../enums/ModelInformation';\nimport type { ModelType } from '../enums/ModelType';\nimport type {\n ApiFormModalProps,\n BulkEditApiFormModalProps,\n StockOperationProps\n} from './Forms';\nimport type { UseModalReturn } from './Modals';\nimport type { RenderInstanceProps } from './Rendering';\nimport type { SettingsStateProps } from './Settings';\nimport type { InvenTreeTableRenderProps } from './Tables';\nimport type { UserStateProps } from './User';\n\nexport interface PluginProps {\n name: string;\n slug: string;\n version: null | string;\n}\n\nexport interface PluginVersion {\n inventree: string;\n react: string;\n reactDom: string;\n mantine: string;\n}\n\nexport type StockAdjustmentFormsContext = {\n addStock: (props: StockOperationProps) => UseModalReturn;\n assignStock: (props: StockOperationProps) => UseModalReturn;\n changeStatus: (props: StockOperationProps) => UseModalReturn;\n countStock: (props: StockOperationProps) => UseModalReturn;\n deleteStock: (props: StockOperationProps) => UseModalReturn;\n mergeStock: (props: StockOperationProps) => UseModalReturn;\n removeStock: (props: StockOperationProps) => UseModalReturn;\n transferStock: (props: StockOperationProps) => UseModalReturn;\n returnStock: (props: StockOperationProps) => UseModalReturn;\n};\n\nexport type InvenTreeFormsContext = {\n bulkEdit: (props: BulkEditApiFormModalProps) => UseModalReturn;\n create: (props: ApiFormModalProps) => UseModalReturn;\n delete: (props: ApiFormModalProps) => UseModalReturn;\n edit: (props: ApiFormModalProps) => UseModalReturn;\n stockActions: StockAdjustmentFormsContext;\n};\n\nexport type InvenTreeTablesContext<T extends Record<string, any>> = {\n renderTable: (props: InvenTreeTableRenderProps<T>) => React.ReactNode;\n};\n\nexport type ImporterDrawerContext = {\n open: (sessionId: number, options?: { onClose?: () => void }) => void;\n close: () => void;\n isOpen: () => boolean;\n sessionId: () => number | null;\n};\n\n/**\n * A set of properties which are passed to a plugin,\n * for rendering an element in the user interface.\n *\n * @param version - The version of the running InvenTree software stack\n * @param api - The Axios API instance (see ../states/ApiState.tsx)\n * @param queryClient - The Tanstack QueryClient instance (see ../states/QueryState.tsx)\n * @param user - The current user instance (see ../states/UserState.tsx)\n * @param userSettings - The current user settings (see ../states/SettingsState.tsx)\n * @param globalSettings - The global settings (see ../states/SettingsState.tsx)\n * @param modelInformation - A dictionary of available model information\n * @param renderInstance - A component function for rendering a model instance\n * @param host - The current host URL\n * @param i18n - The i18n instance for translations (from @lingui/core)\n * @param locale - The current locale string (e.g. 'en' / 'de')\n * @param navigate - The navigation function (see react-router-dom)\n * @param theme - The current Mantine theme\n * @param colorScheme - The current Mantine color scheme (e.g. 'light' / 'dark')\n * @param forms - A set of functions for opening various API forms (see ../components/Forms.tsx)\n * @param tables - A set of functions for rendering API tables\n * @param importer - A set of functions for controlling the global importer drawer (see ../components/importer/GlobalImporterDrawer.tsx)\n * @param model - The model type associated with the rendered component (if applicable)\n * @param id - The ID (primary key) of the model instance for the plugin (if applicable)\n * @param instance - The model instance data (if available)\n * @param reloadContent - A function which can be called to reload the plugin content\n * @param reloadInstance - A function which can be called to reload the model instance\n * @param context - Any additional context data which may be passed to the plugin\n */\nexport type InvenTreePluginContext = {\n version: PluginVersion;\n api: AxiosInstance;\n queryClient: QueryClient;\n user: UserStateProps;\n userSettings: SettingsStateProps;\n globalSettings: SettingsStateProps;\n modelInformation: ModelDict;\n renderInstance: (props: Readonly<RenderInstanceProps>) => React.ReactNode;\n host: string;\n i18n: I18n;\n locale: string;\n navigate: NavigateFunction;\n theme: MantineTheme;\n colorScheme: MantineColorScheme;\n forms: InvenTreeFormsContext;\n tables: InvenTreeTablesContext<any>;\n importer: ImporterDrawerContext;\n model?: ModelType | string;\n id?: string | number | null;\n instance?: any;\n reloadContent?: () => void;\n reloadInstance?: () => void;\n context?: any;\n};\n\n/*\n * The version of the InvenTree plugin context interface.\n * This number should be incremented if the interface changes.\n */\n\n// @ts-ignore\nexport const INVENTREE_PLUGIN_VERSION: string = __INVENTREE_LIB_VERSION__;\n// @ts-ignore\nexport const INVENTREE_REACT_VERSION: string = __INVENTREE_REACT_VERSION__;\n// @ts-ignore\nexport const INVENTREE_REACT_DOM_VERSION: string =\n // @ts-ignore\n __INVENTREE_REACT_DOM_VERSION__;\n// @ts-ignore\nexport const INVENTREE_MANTINE_VERSION: string = __INVENTREE_MANTINE_VERSION__;\n"],"names":["INVENTREE_PLUGIN_VERSION","__INVENTREE_LIB_VERSION__","INVENTREE_REACT_VERSION","__INVENTREE_REACT_VERSION__","INVENTREE_REACT_DOM_VERSION","__INVENTREE_REACT_DOM_VERSION__","INVENTREE_MANTINE_VERSION","__INVENTREE_MANTINE_VERSION__"],"mappings":"AA0HO,MAAMA,2BAAmCC;AAEzC,MAAMC,0BAAkCC;AAExC,MAAMC;AAAAA;AAAAA,EAEXC;AAAAA;AAEK,MAAMC,4BAAoCC;"}
1
+ {"version":3,"file":"Plugins.js","sources":["../../lib/types/Plugins.tsx"],"sourcesContent":["import type { I18n } from '@lingui/core';\nimport type { MantineColorScheme, MantineTheme } from '@mantine/core';\nimport type { QueryClient } from '@tanstack/react-query';\nimport type { AxiosInstance } from 'axios';\nimport type { JSX } from 'react';\nimport type { NavigateFunction } from 'react-router-dom';\nimport type { ModelDict } from '../enums/ModelInformation';\nimport type { ModelType } from '../enums/ModelType';\nimport type { setRenderProps } from '../states/types';\nimport type {\n ApiFormModalProps,\n ApiFormProps,\n BulkEditApiFormModalProps,\n StockOperationProps\n} from './Forms';\nimport type { UseModalReturn } from './Modals';\nimport type {\n RemoteInstanceProps,\n RenderInlineModelProps,\n RenderInstanceProps,\n ThumbnailProps\n} from './Rendering';\nimport type { SettingsStateProps } from './Settings';\nimport type { InvenTreeTableRenderProps } from './Tables';\nimport type { UserStateProps } from './User';\n\nexport interface PluginProps {\n name: string;\n slug: string;\n version: null | string;\n}\n\nexport interface PluginVersion {\n inventree: string;\n react: string;\n reactDom: string;\n mantine: string;\n}\n\nexport type StockAdjustmentFormsContext = {\n addStock: (props: StockOperationProps) => UseModalReturn;\n assignStock: (props: StockOperationProps) => UseModalReturn;\n changeStatus: (props: StockOperationProps) => UseModalReturn;\n countStock: (props: StockOperationProps) => UseModalReturn;\n deleteStock: (props: StockOperationProps) => UseModalReturn;\n mergeStock: (props: StockOperationProps) => UseModalReturn;\n removeStock: (props: StockOperationProps) => UseModalReturn;\n transferStock: (props: StockOperationProps) => UseModalReturn;\n returnStock: (props: StockOperationProps) => UseModalReturn;\n};\n\nexport type InvenTreeFormsContext = {\n bulkEdit: (props: BulkEditApiFormModalProps) => UseModalReturn;\n create: (props: ApiFormModalProps) => UseModalReturn;\n delete: (props: ApiFormModalProps) => UseModalReturn;\n edit: (props: ApiFormModalProps) => UseModalReturn;\n editApiForm: (props: { id?: string; props: ApiFormProps }) => React.ReactNode;\n stockActions: StockAdjustmentFormsContext;\n};\n\nexport type InvenTreeTablesContext<T extends Record<string, any>> = {\n renderTable: (props: InvenTreeTableRenderProps<T>) => React.ReactNode;\n};\n\nexport type ImporterDrawerContext = {\n open: (sessionId: number, options?: { onClose?: () => void }) => void;\n close: () => void;\n isOpen: () => boolean;\n sessionId: () => number | null;\n};\n\n/**\n * A set of properties which are passed to a plugin,\n * for rendering an element in the user interface.\n *\n * @param version - The version of the running InvenTree software stack\n * @param api - The Axios API instance (see ../states/ApiState.tsx)\n * @param queryClient - The Tanstack QueryClient instance (see ../states/QueryState.tsx)\n * @param user - The current user instance (see ../states/UserState.tsx)\n * @param userSettings - The current user settings (see ../states/SettingsState.tsx)\n * @param globalSettings - The global settings (see ../states/SettingsState.tsx)\n * @param modelInformation - A dictionary of available model information\n * @param renderInstance - A component function for rendering a model instance\n * @param host - The current host URL\n * @param i18n - The i18n instance for translations (from @lingui/core)\n * @param locale - The current locale string (e.g. 'en' / 'de')\n * @param navigate - The navigation function (see react-router-dom)\n * @param theme - The current Mantine theme\n * @param colorScheme - The current Mantine color scheme (e.g. 'light' / 'dark')\n * @param forms - A set of functions for opening various API forms (see ../components/Forms.tsx)\n * @param tables - A set of functions for rendering API tables\n * @param importer - A set of functions for controlling the global importer drawer (see ../components/importer/GlobalImporterDrawer.tsx)\n * @param model - The model type associated with the rendered component (if applicable)\n * @param id - The ID (primary key) of the model instance for the plugin (if applicable)\n * @param instance - The model instance data (if available)\n * @param reloadContent - A function which can be called to reload the plugin content\n * @param reloadInstance - A function which can be called to reload the model instance\n * @param context - Any additional context data which may be passed to the plugin\n */\nexport type InvenTreePluginContext = {\n version: PluginVersion;\n api: AxiosInstance;\n queryClient: QueryClient;\n user: UserStateProps;\n userSettings: SettingsStateProps;\n globalSettings: SettingsStateProps;\n modelInformation: ModelDict;\n renderInstance: (props: Readonly<RenderInstanceProps>) => React.ReactNode;\n renderRemoteInstance: (\n props: Readonly<RemoteInstanceProps>\n ) => React.ReactNode;\n renderInlineModel: (\n props: Readonly<RenderInlineModelProps>\n ) => React.ReactNode;\n thumbnail: (props: Readonly<ThumbnailProps>) => JSX.Element;\n host: string;\n i18n: I18n;\n locale: string;\n navigate: NavigateFunction;\n theme: MantineTheme;\n colorScheme: MantineColorScheme;\n forms: InvenTreeFormsContext;\n stateFnc: {\n setRenderer: setRenderProps;\n };\n tables: InvenTreeTablesContext<any>;\n importer: ImporterDrawerContext;\n model?: ModelType | string;\n id?: string | number | null;\n instance?: any;\n reloadContent?: () => void;\n reloadInstance?: () => void;\n context?: any;\n};\n\n/*\n * The version of the InvenTree plugin context interface.\n * This number should be incremented if the interface changes.\n */\n\n// @ts-ignore\nexport const INVENTREE_PLUGIN_VERSION: string = __INVENTREE_LIB_VERSION__;\n// @ts-ignore\nexport const INVENTREE_REACT_VERSION: string = __INVENTREE_REACT_VERSION__;\n// @ts-ignore\nexport const INVENTREE_REACT_DOM_VERSION: string =\n // @ts-ignore\n __INVENTREE_REACT_DOM_VERSION__;\n// @ts-ignore\nexport const INVENTREE_MANTINE_VERSION: string = __INVENTREE_MANTINE_VERSION__;\n"],"names":["INVENTREE_PLUGIN_VERSION","__INVENTREE_LIB_VERSION__","INVENTREE_REACT_VERSION","__INVENTREE_REACT_VERSION__","INVENTREE_REACT_DOM_VERSION","__INVENTREE_REACT_DOM_VERSION__","INVENTREE_MANTINE_VERSION","__INVENTREE_MANTINE_VERSION__"],"mappings":"AA6IO,MAAMA,2BAAmCC;AAEzC,MAAMC,0BAAkCC;AAExC,MAAMC;AAAAA;AAAAA,EAEXC;AAAAA;AAEK,MAAMC,4BAAoCC;"}
@@ -1,4 +1,8 @@
1
+ import { QueryObserverResult, UseQueryResult } from '@tanstack/react-query';
2
+ import { ReactNode } from 'react';
3
+ import { ApiEndpoints } from '..';
1
4
  import { ModelType } from '../enums/ModelType';
5
+ import { PathParams } from './Core';
2
6
  /**
3
7
  * Interface for rendering a model instance.
4
8
  */
@@ -7,6 +11,7 @@ export interface InstanceRenderInterface {
7
11
  link?: boolean;
8
12
  navigate?: any;
9
13
  showSecondary?: boolean;
14
+ showHover?: boolean;
10
15
  extra?: Record<string, any>;
11
16
  }
12
17
  type EnumDictionary<T extends string | symbol | number, U> = {
@@ -15,5 +20,54 @@ type EnumDictionary<T extends string | symbol | number, U> = {
15
20
  export type ModelRendererDict = EnumDictionary<ModelType, (props: Readonly<InstanceRenderInterface>) => React.ReactNode>;
16
21
  export type RenderInstanceProps = {
17
22
  model: ModelType | undefined;
23
+ custom_model?: string;
18
24
  } & InstanceRenderInterface;
25
+ export interface UseInstanceResult {
26
+ instance: any;
27
+ setInstance: (instance: any) => void;
28
+ refreshInstance: () => void;
29
+ refreshInstancePromise: () => Promise<QueryObserverResult<any, any>>;
30
+ instanceQuery: UseQueryResult;
31
+ isLoaded: boolean;
32
+ }
33
+ export interface useInstanceProps {
34
+ endpoint: ApiEndpoints;
35
+ pk?: string | number | undefined;
36
+ hasPrimaryKey?: boolean;
37
+ params?: any;
38
+ pathParams?: PathParams;
39
+ disabled?: boolean;
40
+ defaultValue?: any;
41
+ refetchOnMount?: boolean;
42
+ refetchOnWindowFocus?: boolean;
43
+ updateInterval?: number;
44
+ }
45
+ export interface RemoteInstanceProps {
46
+ model: ModelType;
47
+ modelUrl?: string;
48
+ modelRenderer?: (instance: any) => ReactNode;
49
+ pk: number;
50
+ }
51
+ export interface ThumbnailProps {
52
+ src?: string;
53
+ alt?: string;
54
+ size?: number;
55
+ text?: ReactNode;
56
+ align?: string;
57
+ link?: string;
58
+ hover?: boolean;
59
+ hoverSize?: number;
60
+ }
61
+ export interface RenderInlineModelProps {
62
+ primary: ReactNode;
63
+ secondary?: ReactNode;
64
+ showSecondary?: boolean;
65
+ prefix?: ReactNode;
66
+ suffix?: ReactNode;
67
+ image?: string;
68
+ labels?: string[];
69
+ url?: string;
70
+ navigate?: any;
71
+ tooltip?: string;
72
+ }
19
73
  export {};
@@ -48,7 +48,7 @@ export type TableState = {
48
48
  * @param editable - Whether the value of this column can be edited
49
49
  * @param definition - Optional field definition for the column
50
50
  * @param render - A custom render function
51
- * @param filter - A custom filter function
51
+ * @param filter - Filter name (string) to look up from tableFilters and attach an inline icon, or a custom render function for the filter popover
52
52
  * @param filtering - Whether the column is filterable
53
53
  * @param width - The width of the column
54
54
  * @param minWidth - The minimum width of the column
@@ -64,7 +64,7 @@ export type TableState = {
64
64
  */
65
65
  export type TableColumnProps<T = any> = {
66
66
  accessor?: string;
67
- title?: string;
67
+ title?: string | ReactNode;
68
68
  ordering?: string;
69
69
  sortable?: boolean;
70
70
  switchable?: boolean;
@@ -73,7 +73,9 @@ export type TableColumnProps<T = any> = {
73
73
  editable?: boolean;
74
74
  definition?: ApiFormFieldType;
75
75
  render?: (record: T, index?: number) => any;
76
- filter?: any;
76
+ filter?: string | string[] | (({ close }: {
77
+ close: () => void;
78
+ }) => ReactNode);
77
79
  filtering?: boolean;
78
80
  width?: number;
79
81
  minWidth?: string | number;
@@ -131,6 +133,7 @@ export type RowViewProps = RowAction & RowModelProps;
131
133
  * @param barcodeActions : any[] - List of barcode actions
132
134
  * @param tableFilters : TableFilter[] - List of custom filters
133
135
  * @param tableActions : any[] - List of custom action groups
136
+ * @param isRecordSelectable : (record: any, index: number) => boolean - Callback function to determine if a row is selectable
134
137
  * @param detailAction: boolean - Enable detail action for each row (default = true)
135
138
  * @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format)
136
139
  * @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions
@@ -161,6 +164,7 @@ export type InvenTreeTableProps<T = any> = {
161
164
  barcodeActions?: React.ReactNode[];
162
165
  tableFilters?: TableFilter[];
163
166
  tableActions?: React.ReactNode[];
167
+ isRecordSelectable?: (record: T, index: number) => boolean;
164
168
  rowExpansion?: DataTableRowExpansionProps<T>;
165
169
  dataFormatter?: (data: any) => any;
166
170
  rowActions?: (record: T) => RowAction[];
@@ -1,5 +1,5 @@
1
1
  import { t } from '@lingui/core/macro';
2
- import { Alert, Stack } from '@mantine/core';
2
+ import { Alert, Stack, Text } from '@mantine/core';
3
3
  import { ErrorBoundary, type FallbackRender } from '@sentry/react';
4
4
  import { IconExclamationCircle } from '@tabler/icons-react';
5
5
  import { type ReactNode, useCallback } from 'react';
@@ -14,8 +14,12 @@ export function DefaultFallback({
14
14
  title={`INVE-E17: ${t`Error rendering component`}: ${title}`}
15
15
  >
16
16
  <Stack gap='xs'>
17
- {t`An error occurred while rendering this component. Refer to the console for more information.`}
18
- {t`Try reloading the page, or contact your administrator if the problem persists.`}
17
+ <Text size='sm'>
18
+ {t`An error occurred while rendering this component. Refer to the console for more information.`}
19
+ </Text>
20
+ <Text size='sm'>
21
+ {t`Try reloading the page, or contact your administrator if the problem persists.`}
22
+ </Text>
19
23
  </Stack>
20
24
  </Alert>
21
25
  );
@@ -139,8 +139,8 @@ export function RowActions({
139
139
  aria-label={`row-action-menu-${index ?? ''}`}
140
140
  onClick={openMenu}
141
141
  disabled={disabled}
142
- variant='subtle'
143
- color='gray'
142
+ variant='transparent'
143
+ size='sm'
144
144
  >
145
145
  <IconDots />
146
146
  </ActionIcon>
@@ -23,7 +23,7 @@ export function TableColumnSelect({
23
23
  <Menu.Label>{t`Select Columns`}</Menu.Label>
24
24
  <Divider />
25
25
  {columns
26
- .filter((col) => col.switchable ?? true)
26
+ .filter((col) => (col.switchable ?? true) && !col.propHidden)
27
27
  .map((col) => (
28
28
  <Menu.Item key={col.accessor}>
29
29
  <Checkbox
@@ -0,0 +1,27 @@
1
+ import { ActionIcon, Badge, Group, Paper } from '@mantine/core';
2
+ import { IconTag } from '@tabler/icons-react';
3
+
4
+ export default function TagsList({
5
+ tags
6
+ }: Readonly<{
7
+ tags: string[];
8
+ }>) {
9
+ if (!tags || tags.length === 0) {
10
+ return null;
11
+ }
12
+
13
+ return (
14
+ <Paper p='xs' shadow='xs' withBorder>
15
+ <Group gap='xs'>
16
+ <ActionIcon size='sm' variant='transparent'>
17
+ <IconTag />
18
+ </ActionIcon>
19
+ {tags.map((tag: string) => (
20
+ <Badge key={tag} variant='outline' size='sm'>
21
+ {tag}
22
+ </Badge>
23
+ ))}
24
+ </Group>
25
+ </Paper>
26
+ );
27
+ }
@@ -26,7 +26,7 @@ export interface DrawerProps {
26
26
  closeOnEscape?: boolean;
27
27
  }
28
28
 
29
- function DetailDrawerComponent({
29
+ export function DetailDrawerComponent({
30
30
  title,
31
31
  position = 'right',
32
32
  size,
@@ -12,12 +12,13 @@ export enum ApiEndpoints {
12
12
  // User API endpoints
13
13
  user_list = 'user/',
14
14
  user_set_password = 'user/:id/set-password/',
15
- user_me = 'user/me/',
16
- user_profile = 'user/profile/',
17
- user_roles = 'user/roles/',
18
- user_token = 'user/token/',
19
15
  user_tokens = 'user/tokens/',
20
16
  user_simple_login = 'email/generate/',
17
+ // Individual user endpoints
18
+ user_me_profile = 'user/me/profile/',
19
+ user_me_roles = 'user/me/roles/',
20
+ user_me_token = 'user/me/token/',
21
+ user_me = 'user/me/',
21
22
 
22
23
  // User auth endpoints
23
24
  auth_base = '/auth/',
@@ -181,6 +182,7 @@ export enum ApiEndpoints {
181
182
  sales_order_complete = 'order/so/:id/complete/',
182
183
  sales_order_allocate = 'order/so/:id/allocate/',
183
184
  sales_order_allocate_serials = 'order/so/:id/allocate-serials/',
185
+ sales_order_auto_allocate = 'order/so/:id/auto-allocate/',
184
186
 
185
187
  sales_order_line_list = 'order/so-line/',
186
188
  sales_order_extra_line_list = 'order/so-extra-line/',
@@ -198,6 +200,17 @@ export enum ApiEndpoints {
198
200
  return_order_line_list = 'order/ro-line/',
199
201
  return_order_extra_line_list = 'order/ro-extra-line/',
200
202
 
203
+ transfer_order_list = 'order/transfer-order/',
204
+ transfer_order_issue = 'order/transfer-order/:id/issue/',
205
+ transfer_order_hold = 'order/transfer-order/:id/hold/',
206
+ transfer_order_cancel = 'order/transfer-order/:id/cancel/',
207
+ transfer_order_complete = 'order/transfer-order/:id/complete/',
208
+ transfer_order_allocate = 'order/transfer-order/:id/allocate/',
209
+ transfer_order_allocate_serials = 'order/transfer-order/:id/allocate-serials/',
210
+
211
+ transfer_order_line_list = 'order/transfer-order-line/',
212
+ transfer_order_allocation_list = 'order/transfer-order-allocation/',
213
+
201
214
  // Template API endpoints
202
215
  label_list = 'label/template/',
203
216
  label_print = 'label/print/',
@@ -246,6 +259,7 @@ export enum ApiEndpoints {
246
259
  config_list = 'admin/config/',
247
260
  parameter_list = 'parameter/',
248
261
  parameter_template_list = 'parameter/template/',
262
+ tag_list = 'tag/',
249
263
 
250
264
  // Internal system things
251
265
  system_internal_trace_end = 'system-internal/observability/end'
@@ -10,6 +10,7 @@ export interface ModelInformationInterface {
10
10
  url_detail?: string;
11
11
  api_endpoint: ApiEndpoints;
12
12
  admin_url?: string;
13
+ pk_field?: string;
13
14
  supports_barcode?: boolean;
14
15
  icon: keyof InvenTreeIconType;
15
16
  }
@@ -117,8 +118,8 @@ export const ModelInformationDict: ModelDict = {
117
118
  icon: 'history'
118
119
  },
119
120
  build: {
120
- label: () => t`Build`,
121
- label_multiple: () => t`Builds`,
121
+ label: () => t`Build Order`,
122
+ label_multiple: () => t`Build Orders`,
122
123
  url_overview: '/manufacturing/index/buildorders/',
123
124
  url_detail: '/manufacturing/build-order/:pk/',
124
125
  api_endpoint: ApiEndpoints.build_order_list,
@@ -186,6 +187,7 @@ export const ModelInformationDict: ModelDict = {
186
187
  label_multiple: () => t`Sales Order Shipments`,
187
188
  url_overview: '/sales/index/shipments',
188
189
  url_detail: '/sales/shipment/:pk/',
190
+ admin_url: '/order/salesordershipment/',
189
191
  api_endpoint: ApiEndpoints.sales_order_shipment_list,
190
192
  supports_barcode: true,
191
193
  icon: 'shipment'
@@ -206,6 +208,22 @@ export const ModelInformationDict: ModelDict = {
206
208
  api_endpoint: ApiEndpoints.return_order_line_list,
207
209
  icon: 'return_orders'
208
210
  },
211
+ transferorder: {
212
+ label: () => t`Transfer Order`,
213
+ label_multiple: () => t`Transfer Orders`,
214
+ url_overview: '/stock/location/index/transfer-orders',
215
+ url_detail: '/stock/transfer-order/:pk/',
216
+ api_endpoint: ApiEndpoints.transfer_order_list,
217
+ admin_url: '/order/transferorder/',
218
+ supports_barcode: true,
219
+ icon: 'transfer_orders'
220
+ },
221
+ transferorderlineitem: {
222
+ label: () => t`Transfer Order Line Item`,
223
+ label_multiple: () => t`Transfer Order Line Items`,
224
+ api_endpoint: ApiEndpoints.transfer_order_line_list,
225
+ icon: 'transfer-orders'
226
+ },
209
227
  address: {
210
228
  label: () => t`Address`,
211
229
  label_multiple: () => t`Addresses`,
@@ -301,5 +319,11 @@ export const ModelInformationDict: ModelDict = {
301
319
  url_overview: '/settings/admin/errors',
302
320
  url_detail: '/settings/admin/errors/:pk/',
303
321
  icon: 'exclamation'
322
+ },
323
+ tag: {
324
+ label: () => t`Tag`,
325
+ label_multiple: () => t`Tags`,
326
+ api_endpoint: ApiEndpoints.tag_list,
327
+ icon: 'tag'
304
328
  }
305
329
  };
@@ -24,6 +24,8 @@ export enum ModelType {
24
24
  salesordershipment = 'salesordershipment',
25
25
  returnorder = 'returnorder',
26
26
  returnorderlineitem = 'returnorderlineitem',
27
+ transferorder = 'transferorder',
28
+ transferorderlineitem = 'transferorderlineitem',
27
29
  importsession = 'importsession',
28
30
  address = 'address',
29
31
  contact = 'contact',
@@ -36,7 +38,8 @@ export enum ModelType {
36
38
  contenttype = 'contenttype',
37
39
  selectionlist = 'selectionlist',
38
40
  selectionentry = 'selectionentry',
39
- error = 'error'
41
+ error = 'error',
42
+ tag = 'tag'
40
43
  }
41
44
 
42
45
  export enum PluginPanelKey {
@@ -11,6 +11,7 @@ export enum UserRoles {
11
11
  part_category = 'part_category',
12
12
  purchase_order = 'purchase_order',
13
13
  return_order = 'return_order',
14
+ transfer_order = 'transfer_order',
14
15
  sales_order = 'sales_order',
15
16
  stock = 'stock',
16
17
  stock_location = 'stock_location'
@@ -40,6 +41,8 @@ export function userRoleLabel(role: UserRoles): string {
40
41
  return t`Purchase Orders`;
41
42
  case UserRoles.return_order:
42
43
  return t`Return Orders`;
44
+ case UserRoles.transfer_order:
45
+ return t`Transfer Orders`;
43
46
  case UserRoles.sales_order:
44
47
  return t`Sales Orders`;
45
48
  case UserRoles.stock:
@@ -55,7 +55,7 @@ export function getDetailUrl(
55
55
  }
56
56
  }
57
57
 
58
- console.error(`No detail URL found for model ${model} <${pk}>`);
58
+ console.warn(`No detail URL found for model ${model} <${pk}>`);
59
59
  return '';
60
60
  }
61
61
 
@@ -1,6 +1,10 @@
1
1
  import { useLocalStorage } from '@mantine/hooks';
2
- import { useCallback, useMemo } from 'react';
3
- import type { FilterSetState, TableFilter } from '../types/Filters';
2
+ import { useCallback, useEffect, useMemo } from 'react';
3
+ import type {
4
+ FilterSetState,
5
+ NamedFilterSet,
6
+ TableFilter
7
+ } from '../types/Filters';
4
8
 
5
9
  export default function useFilterSet(
6
10
  filterKey: string,
@@ -16,17 +20,26 @@ export default function useFilterSet(
16
20
  getInitialValueInEffect: false
17
21
  });
18
22
 
19
- const activeFilters: TableFilter[] = useMemo(() => {
23
+ // Named filter set snapshots (saved to local storage, separate key)
24
+ const [storedNamedSets, setStoredNamedSets] = useLocalStorage<
25
+ NamedFilterSet[]
26
+ >({
27
+ key: `inventree-filtersets-${filterKey}`,
28
+ defaultValue: [],
29
+ sync: false,
30
+ getInitialValueInEffect: false
31
+ });
32
+
33
+ useEffect(() => {
20
34
  if (storedFilters == null) {
21
- // If there are no stored filters, set initial values
22
- const filters = initialFilters || [];
23
- setStoredFilters(filters);
24
- return filters;
35
+ setStoredFilters(initialFilters || []);
25
36
  }
26
- return storedFilters || [];
27
- }, [storedFilters]);
37
+ }, [storedFilters, initialFilters, setStoredFilters]);
38
+
39
+ const activeFilters: TableFilter[] = useMemo(() => {
40
+ return storedFilters ?? initialFilters ?? [];
41
+ }, [storedFilters, initialFilters]);
28
42
 
29
- // Callback to clear all active filters from the table
30
43
  const clearActiveFilters = useCallback(() => {
31
44
  setStoredFilters([]);
32
45
  }, []);
@@ -38,10 +51,48 @@ export default function useFilterSet(
38
51
  [setStoredFilters]
39
52
  );
40
53
 
54
+ const saveFilterSet = useCallback(
55
+ (name: string) => {
56
+ const snapshot = activeFilters.map(
57
+ ({ name: n, value, displayValue }) => ({
58
+ name: n,
59
+ value,
60
+ displayValue
61
+ })
62
+ );
63
+ setStoredNamedSets((prev) => {
64
+ const without = (prev ?? []).filter((s) => s.name !== name);
65
+ return [...without, { name, filters: snapshot }];
66
+ });
67
+ },
68
+ [activeFilters, setStoredNamedSets]
69
+ );
70
+
71
+ const loadFilterSet = useCallback(
72
+ (name: string) => {
73
+ const saved = (storedNamedSets ?? []).find((s) => s.name === name);
74
+ if (saved) {
75
+ setStoredFilters(saved.filters as TableFilter[]);
76
+ }
77
+ },
78
+ [storedNamedSets, setStoredFilters]
79
+ );
80
+
81
+ const deleteFilterSet = useCallback(
82
+ (name: string) => {
83
+ setStoredNamedSets((prev) => (prev ?? []).filter((s) => s.name !== name));
84
+ },
85
+ [setStoredNamedSets]
86
+ );
87
+
41
88
  return {
42
89
  filterKey,
43
90
  activeFilters,
44
91
  setActiveFilters,
45
- clearActiveFilters
92
+ clearActiveFilters,
93
+ savedFilterSets: storedNamedSets ?? [],
94
+ saveFilterSet,
95
+ loadFilterSet,
96
+ deleteFilterSet
46
97
  };
47
98
  }
package/lib/index.ts CHANGED
@@ -21,6 +21,12 @@ export type {
21
21
  StockAdjustmentFormsContext
22
22
  } from './types/Plugins';
23
23
 
24
+ export type {
25
+ PanelIndicatorType,
26
+ PanelType,
27
+ PanelGroupType
28
+ } from './types/Panel';
29
+
24
30
  export type {
25
31
  RowAction,
26
32
  RowViewProps,
@@ -104,6 +110,7 @@ export { ProgressBar } from './components/ProgressBar';
104
110
  export { PassFailButton, YesNoButton } from './components/YesNoButton';
105
111
  export { SearchInput } from './components/SearchInput';
106
112
  export { TableColumnSelect } from './components/TableColumnSelect';
113
+ export { default as TagsList } from './components/TagsList';
107
114
  export { default as InvenTreeTable } from './components/InvenTreeTable';
108
115
  export {
109
116
  RowViewAction,
@@ -135,7 +142,8 @@ export {
135
142
  export {
136
143
  type DrawerProps,
137
144
  DetailDrawer,
138
- DetailDrawerLink
145
+ DetailDrawerLink,
146
+ DetailDrawerComponent
139
147
  } from './components/nav/DetailDrawer';
140
148
  export { StylishText } from './components/StylishText';
141
149
 
@@ -144,3 +152,8 @@ export {
144
152
  type StoredTableStateProps,
145
153
  useStoredTableState
146
154
  } from './states/StoredTableState';
155
+ export { useLocalLibState } from './states/LocalLibState';
156
+
157
+ // Plugin development utilities and hooks
158
+ export { default as InventreeHmrPlugin } from './plugin/InventreeHmrPlugin';
159
+ export { default as LocalizedComponent } from './plugin/LocalizedComponent';
@@ -0,0 +1,40 @@
1
+ import type { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Vite plugin which enables hot module replacement (HMR) for InvenTree plugin development.
5
+ *
6
+ * This is for use with the InvenTree plugin creator tool,
7
+ * allowing frontend plugin code to be "live reloaded" during development.
8
+ */
9
+ export default function InventreeHmrPlugin(): Plugin {
10
+ const fileRegex = /\.(js|jsx|ts|tsx)(\?|$)/;
11
+
12
+ const hmrBlock = [
13
+ '',
14
+ '// __inventree_hmr_injected__',
15
+ 'if (import.meta.hot) {',
16
+ ' import.meta.hot.accept((newModule) => {',
17
+ ' const key = new URL(import.meta.url).origin + new URL(import.meta.url).pathname;',
18
+ ' window.__plugin_hmr_callbacks?.[key]?.forEach(callback => {',
19
+ ' callback(newModule);',
20
+ ' });',
21
+ ' })',
22
+ '}'
23
+ ];
24
+
25
+ return {
26
+ name: 'inventree-hmr-plugin',
27
+ enforce: 'post',
28
+
29
+ transform(code, id) {
30
+ if (!fileRegex.test(id)) return;
31
+ if (id.includes('node_modules')) return;
32
+ if (code.includes('__inventree_hmr_injected__')) return;
33
+
34
+ return {
35
+ code: code + hmrBlock.join('\n'),
36
+ map: null
37
+ };
38
+ }
39
+ };
40
+ }