@inventreedb/ui 0.0.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.
- package/.babelrc +8 -0
- package/.linguirc +55 -0
- package/README.md +17 -0
- package/index.html +15 -0
- package/lib/enums/ApiEndpoints.tsx +233 -0
- package/lib/enums/ModelType.tsx +38 -0
- package/lib/enums/Roles.tsx +25 -0
- package/lib/functions/Api.tsx +42 -0
- package/lib/functions/Plugins.tsx +27 -0
- package/lib/index.ts +11 -0
- package/lib/types/Auth.tsx +51 -0
- package/lib/types/Core.tsx +13 -0
- package/lib/types/Filters.tsx +69 -0
- package/lib/types/Forms.tsx +185 -0
- package/lib/types/Modals.tsx +17 -0
- package/lib/types/Plugins.tsx +68 -0
- package/lib/types/Server.tsx +8 -0
- package/lib/types/Settings.tsx +55 -0
- package/lib/types/Tables.tsx +69 -0
- package/lib/types/User.tsx +62 -0
- package/netlify.toml +22 -0
- package/package.json +125 -0
- package/playwright/global-setup.ts +45 -0
- package/playwright.config.ts +99 -0
- package/public/inventree.svg +291 -0
- package/src/App.tsx +35 -0
- package/src/assets/inventree.svg +1 -0
- package/src/components/Boundary.tsx +43 -0
- package/src/components/SplashScreen.tsx +35 -0
- package/src/components/barcodes/BarcodeCameraInput.tsx +207 -0
- package/src/components/barcodes/BarcodeInput.tsx +127 -0
- package/src/components/barcodes/BarcodeKeyboardInput.tsx +50 -0
- package/src/components/barcodes/BarcodeScanDialog.tsx +101 -0
- package/src/components/barcodes/BarcodeScanItem.tsx +23 -0
- package/src/components/barcodes/QRCode.tsx +211 -0
- package/src/components/buttons/ActionButton.tsx +61 -0
- package/src/components/buttons/AddItemButton.tsx +10 -0
- package/src/components/buttons/AdminButton.tsx +91 -0
- package/src/components/buttons/ButtonMenu.tsx +33 -0
- package/src/components/buttons/CopyButton.tsx +52 -0
- package/src/components/buttons/PrimaryActionButton.tsx +40 -0
- package/src/components/buttons/PrintingActions.tsx +191 -0
- package/src/components/buttons/RemoveRowButton.tsx +22 -0
- package/src/components/buttons/SSOButton.tsx +53 -0
- package/src/components/buttons/ScanButton.tsx +27 -0
- package/src/components/buttons/SegmentedIconControl.tsx +51 -0
- package/src/components/buttons/SplitButton.css.ts +19 -0
- package/src/components/buttons/SplitButton.tsx +111 -0
- package/src/components/buttons/SpotlightButton.tsx +22 -0
- package/src/components/buttons/StarredToggleButton.tsx +62 -0
- package/src/components/buttons/YesNoButton.tsx +42 -0
- package/src/components/calendar/Calendar.tsx +193 -0
- package/src/components/calendar/OrderCalendar.tsx +209 -0
- package/src/components/charts/colors.tsx +12 -0
- package/src/components/charts/tooltipFormatter.tsx +12 -0
- package/src/components/dashboard/DashboardLayout.tsx +327 -0
- package/src/components/dashboard/DashboardMenu.tsx +136 -0
- package/src/components/dashboard/DashboardWidget.tsx +82 -0
- package/src/components/dashboard/DashboardWidgetDrawer.tsx +130 -0
- package/src/components/dashboard/DashboardWidgetLibrary.tsx +189 -0
- package/src/components/dashboard/widgets/ColorToggleWidget.tsx +28 -0
- package/src/components/dashboard/widgets/GetStartedWidget.tsx +19 -0
- package/src/components/dashboard/widgets/LanguageSelectWidget.tsx +28 -0
- package/src/components/dashboard/widgets/NewsWidget.tsx +143 -0
- package/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx +134 -0
- package/src/components/details/Details.tsx +514 -0
- package/src/components/details/DetailsBadge.tsx +20 -0
- package/src/components/details/DetailsImage.tsx +462 -0
- package/src/components/details/ItemDetails.tsx +17 -0
- package/src/components/editors/NotesEditor.tsx +232 -0
- package/src/components/editors/TemplateEditor/CodeEditor/CodeEditor.tsx +158 -0
- package/src/components/editors/TemplateEditor/CodeEditor/index.tsx +12 -0
- package/src/components/editors/TemplateEditor/PdfPreview/PdfPreview.tsx +90 -0
- package/src/components/editors/TemplateEditor/PdfPreview/index.tsx +12 -0
- package/src/components/editors/TemplateEditor/TemplateEditor.tsx +425 -0
- package/src/components/editors/TemplateEditor/index.tsx +3 -0
- package/src/components/errors/ClientError.tsx +28 -0
- package/src/components/errors/GenericErrorPage.tsx +73 -0
- package/src/components/errors/NotAuthenticated.tsx +12 -0
- package/src/components/errors/NotFound.tsx +12 -0
- package/src/components/errors/PermissionDenied.tsx +12 -0
- package/src/components/errors/ServerError.tsx +13 -0
- package/src/components/forms/ApiForm.tsx +718 -0
- package/src/components/forms/AuthFormOptions.tsx +39 -0
- package/src/components/forms/AuthenticationForm.tsx +332 -0
- package/src/components/forms/HostOptionsForm.tsx +96 -0
- package/src/components/forms/InstanceOptions.tsx +178 -0
- package/src/components/forms/StandaloneField.tsx +55 -0
- package/src/components/forms/fields/ApiFormField.tsx +281 -0
- package/src/components/forms/fields/ChoiceField.tsx +86 -0
- package/src/components/forms/fields/DateField.tsx +79 -0
- package/src/components/forms/fields/DependentField.tsx +91 -0
- package/src/components/forms/fields/IconField.tsx +353 -0
- package/src/components/forms/fields/NestedObjectField.tsx +45 -0
- package/src/components/forms/fields/RelatedModelField.tsx +339 -0
- package/src/components/forms/fields/TableField.tsx +275 -0
- package/src/components/forms/fields/TextField.tsx +81 -0
- package/src/components/images/ApiImage.tsx +35 -0
- package/src/components/images/Thumbnail.tsx +52 -0
- package/src/components/importer/ImportDataSelector.tsx +433 -0
- package/src/components/importer/ImporterColumnSelector.tsx +244 -0
- package/src/components/importer/ImporterDrawer.tsx +173 -0
- package/src/components/importer/ImporterImportProgress.tsx +45 -0
- package/src/components/items/ActionDropdown.tsx +290 -0
- package/src/components/items/ApiIcon.css.ts +13 -0
- package/src/components/items/ApiIcon.tsx +32 -0
- package/src/components/items/AttachmentLink.tsx +79 -0
- package/src/components/items/ColorToggle.tsx +34 -0
- package/src/components/items/DashboardItem.tsx +33 -0
- package/src/components/items/DocInfo.tsx +20 -0
- package/src/components/items/DocTooltip.tsx +98 -0
- package/src/components/items/ErrorItem.tsx +17 -0
- package/src/components/items/Expand.tsx +14 -0
- package/src/components/items/GettingStartedCarousel.css.ts +30 -0
- package/src/components/items/GettingStartedCarousel.tsx +49 -0
- package/src/components/items/InfoItem.tsx +64 -0
- package/src/components/items/InvenTreeLogo.tsx +24 -0
- package/src/components/items/LanguageSelect.tsx +43 -0
- package/src/components/items/LanguageToggle.tsx +37 -0
- package/src/components/items/MenuLinks.tsx +113 -0
- package/src/components/items/OnlyStaff.tsx +10 -0
- package/src/components/items/ProgressBar.tsx +45 -0
- package/src/components/items/StylishText.tsx +59 -0
- package/src/components/items/TitleWithDoc.tsx +26 -0
- package/src/components/items/UnavailableIndicator.tsx +5 -0
- package/src/components/items/inventree.svg +1 -0
- package/src/components/modals/AboutInvenTreeModal.tsx +203 -0
- package/src/components/modals/LicenseModal.tsx +116 -0
- package/src/components/modals/QrModal.tsx +21 -0
- package/src/components/modals/ServerInfoModal.tsx +136 -0
- package/src/components/nav/Alerts.tsx +130 -0
- package/src/components/nav/BreadcrumbList.tsx +84 -0
- package/src/components/nav/DetailDrawer.css.ts +6 -0
- package/src/components/nav/DetailDrawer.tsx +105 -0
- package/src/components/nav/Footer.tsx +11 -0
- package/src/components/nav/Header.tsx +226 -0
- package/src/components/nav/InstanceDetail.tsx +46 -0
- package/src/components/nav/Layout.tsx +85 -0
- package/src/components/nav/MainMenu.tsx +101 -0
- package/src/components/nav/NavHoverMenu.tsx +15 -0
- package/src/components/nav/NavigationDrawer.tsx +230 -0
- package/src/components/nav/NavigationTree.tsx +210 -0
- package/src/components/nav/NotificationDrawer.tsx +231 -0
- package/src/components/nav/PageDetail.tsx +171 -0
- package/src/components/nav/PageTitle.tsx +53 -0
- package/src/components/nav/SearchDrawer.tsx +598 -0
- package/src/components/nav/SettingsHeader.tsx +50 -0
- package/src/components/panels/AttachmentPanel.tsx +27 -0
- package/src/components/panels/NotesPanel.tsx +36 -0
- package/src/components/panels/Panel.tsx +15 -0
- package/src/components/panels/PanelGroup.css.ts +10 -0
- package/src/components/panels/PanelGroup.tsx +292 -0
- package/src/components/plugins/LocateItemButton.tsx +94 -0
- package/src/components/plugins/PluginContext.tsx +67 -0
- package/src/components/plugins/PluginDrawer.tsx +156 -0
- package/src/components/plugins/PluginInterface.tsx +34 -0
- package/src/components/plugins/PluginPanel.tsx +37 -0
- package/src/components/plugins/PluginSettingsPanel.tsx +34 -0
- package/src/components/plugins/PluginSource.tsx +48 -0
- package/src/components/plugins/PluginUIFeature.tsx +174 -0
- package/src/components/plugins/PluginUIFeatureTypes.ts +78 -0
- package/src/components/plugins/RemoteComponent.tsx +137 -0
- package/src/components/render/Build.tsx +54 -0
- package/src/components/render/Company.tsx +114 -0
- package/src/components/render/Generic.tsx +49 -0
- package/src/components/render/Instance.tsx +240 -0
- package/src/components/render/InstanceFromUrl.tsx +33 -0
- package/src/components/render/ModelType.tsx +293 -0
- package/src/components/render/Order.tsx +124 -0
- package/src/components/render/Part.tsx +109 -0
- package/src/components/render/Plugin.tsx +21 -0
- package/src/components/render/Report.tsx +29 -0
- package/src/components/render/StatusRenderer.tsx +178 -0
- package/src/components/render/Stock.tsx +84 -0
- package/src/components/render/User.tsx +42 -0
- package/src/components/settings/FactCollection.tsx +31 -0
- package/src/components/settings/FactItem.tsx +17 -0
- package/src/components/settings/SettingItem.tsx +176 -0
- package/src/components/settings/SettingList.tsx +217 -0
- package/src/components/wizards/OrderPartsWizard.tsx +473 -0
- package/src/components/wizards/WizardDrawer.tsx +188 -0
- package/src/contexts/ApiContext.tsx +31 -0
- package/src/contexts/LanguageContext.tsx +155 -0
- package/src/contexts/ThemeContext.tsx +58 -0
- package/src/contexts/colorSchema.tsx +67 -0
- package/src/defaults/actions.tsx +87 -0
- package/src/defaults/backendMappings.tsx +32 -0
- package/src/defaults/defaultHostList.tsx +4 -0
- package/src/defaults/defaults.tsx +38 -0
- package/src/defaults/formatters.tsx +176 -0
- package/src/defaults/links.tsx +193 -0
- package/src/defaults/templates.tsx +53 -0
- package/src/forms/BomForms.tsx +26 -0
- package/src/forms/BuildForms.tsx +615 -0
- package/src/forms/CommonForms.tsx +89 -0
- package/src/forms/CompanyForms.tsx +133 -0
- package/src/forms/ImporterForms.tsx +20 -0
- package/src/forms/PartForms.tsx +281 -0
- package/src/forms/PurchaseOrderForms.tsx +779 -0
- package/src/forms/ReturnOrderForms.tsx +263 -0
- package/src/forms/SalesOrderForms.tsx +408 -0
- package/src/forms/StockForms.tsx +1296 -0
- package/src/forms/selectionListFields.tsx +120 -0
- package/src/functions/api.tsx +61 -0
- package/src/functions/auth.tsx +574 -0
- package/src/functions/conversion.tsx +42 -0
- package/src/functions/events.tsx +6 -0
- package/src/functions/forms.tsx +173 -0
- package/src/functions/icons.tsx +294 -0
- package/src/functions/loading.tsx +29 -0
- package/src/functions/navigation.tsx +20 -0
- package/src/functions/notifications.tsx +101 -0
- package/src/functions/tables.tsx +26 -0
- package/src/functions/uid.tsx +15 -0
- package/src/functions/urls.tsx +58 -0
- package/src/hooks/UseCalendar.tsx +178 -0
- package/src/hooks/UseDashboardItems.tsx +118 -0
- package/src/hooks/UseDataExport.tsx +125 -0
- package/src/hooks/UseDataOutput.tsx +109 -0
- package/src/hooks/UseFilter.tsx +67 -0
- package/src/hooks/UseFilterSet.tsx +24 -0
- package/src/hooks/UseForm.tsx +161 -0
- package/src/hooks/UseGenerator.tsx +92 -0
- package/src/hooks/UseImportSession.tsx +139 -0
- package/src/hooks/UseInstance.tsx +137 -0
- package/src/hooks/UseInstanceName.tsx +14 -0
- package/src/hooks/UseModal.tsx +38 -0
- package/src/hooks/UsePlaceholder.tsx +66 -0
- package/src/hooks/UsePluginPanels.tsx +123 -0
- package/src/hooks/UsePluginUIFeature.tsx +95 -0
- package/src/hooks/UsePlugins.tsx +45 -0
- package/src/hooks/UseSelectedRows.tsx +37 -0
- package/src/hooks/UseStatusCodes.tsx +50 -0
- package/src/hooks/UseTable.tsx +145 -0
- package/src/hooks/UseWizard.tsx +133 -0
- package/src/locales/ar/messages.d.ts +4 -0
- package/src/locales/ar/messages.po +10695 -0
- package/src/locales/ar/messages.ts +1 -0
- package/src/locales/bg/messages.d.ts +4 -0
- package/src/locales/bg/messages.po +10695 -0
- package/src/locales/bg/messages.ts +1 -0
- package/src/locales/cs/messages.d.ts +4 -0
- package/src/locales/cs/messages.po +10695 -0
- package/src/locales/cs/messages.ts +1 -0
- package/src/locales/da/messages.d.ts +4 -0
- package/src/locales/da/messages.po +10695 -0
- package/src/locales/da/messages.ts +1 -0
- package/src/locales/de/messages.d.ts +4 -0
- package/src/locales/de/messages.po +10695 -0
- package/src/locales/de/messages.ts +1 -0
- package/src/locales/el/messages.d.ts +4 -0
- package/src/locales/el/messages.po +10695 -0
- package/src/locales/el/messages.ts +1 -0
- package/src/locales/en/messages.d.ts +4 -0
- package/src/locales/en/messages.po +10689 -0
- package/src/locales/en/messages.ts +1 -0
- package/src/locales/es/messages.d.ts +4 -0
- package/src/locales/es/messages.po +10695 -0
- package/src/locales/es/messages.ts +1 -0
- package/src/locales/es_MX/messages.d.ts +4 -0
- package/src/locales/es_MX/messages.po +10695 -0
- package/src/locales/es_MX/messages.ts +1 -0
- package/src/locales/et/messages.d.ts +4 -0
- package/src/locales/et/messages.po +10695 -0
- package/src/locales/et/messages.ts +1 -0
- package/src/locales/fa/messages.d.ts +4 -0
- package/src/locales/fa/messages.po +10695 -0
- package/src/locales/fa/messages.ts +1 -0
- package/src/locales/fi/messages.d.ts +4 -0
- package/src/locales/fi/messages.po +10695 -0
- package/src/locales/fi/messages.ts +1 -0
- package/src/locales/fr/messages.d.ts +4 -0
- package/src/locales/fr/messages.po +10695 -0
- package/src/locales/fr/messages.ts +1 -0
- package/src/locales/he/messages.d.ts +4 -0
- package/src/locales/he/messages.po +10695 -0
- package/src/locales/he/messages.ts +1 -0
- package/src/locales/hi/messages.d.ts +4 -0
- package/src/locales/hi/messages.po +10695 -0
- package/src/locales/hi/messages.ts +1 -0
- package/src/locales/hu/messages.d.ts +4 -0
- package/src/locales/hu/messages.po +10695 -0
- package/src/locales/hu/messages.ts +1 -0
- package/src/locales/id/messages.po +10695 -0
- package/src/locales/it/messages.d.ts +4 -0
- package/src/locales/it/messages.po +10695 -0
- package/src/locales/it/messages.ts +1 -0
- package/src/locales/ja/messages.d.ts +4 -0
- package/src/locales/ja/messages.po +10695 -0
- package/src/locales/ja/messages.ts +1 -0
- package/src/locales/ko/messages.d.ts +4 -0
- package/src/locales/ko/messages.po +10695 -0
- package/src/locales/ko/messages.ts +1 -0
- package/src/locales/lt/messages.d.ts +4 -0
- package/src/locales/lt/messages.po +10695 -0
- package/src/locales/lt/messages.ts +1 -0
- package/src/locales/lv/messages.d.ts +4 -0
- package/src/locales/lv/messages.po +10695 -0
- package/src/locales/lv/messages.ts +1 -0
- package/src/locales/nl/messages.d.ts +4 -0
- package/src/locales/nl/messages.po +10695 -0
- package/src/locales/nl/messages.ts +1 -0
- package/src/locales/no/messages.d.ts +4 -0
- package/src/locales/no/messages.po +10695 -0
- package/src/locales/no/messages.ts +1 -0
- package/src/locales/pl/messages.d.ts +4 -0
- package/src/locales/pl/messages.po +10695 -0
- package/src/locales/pl/messages.ts +1 -0
- package/src/locales/pseudo-LOCALE/messages.d.ts +4 -0
- package/src/locales/pseudo-LOCALE/messages.po +8003 -0
- package/src/locales/pseudo-LOCALE/messages.ts +1 -0
- package/src/locales/pt/messages.d.ts +4 -0
- package/src/locales/pt/messages.po +10696 -0
- package/src/locales/pt/messages.ts +1 -0
- package/src/locales/pt_BR/messages.d.ts +4 -0
- package/src/locales/pt_BR/messages.po +10695 -0
- package/src/locales/pt_BR/messages.ts +1 -0
- package/src/locales/ro/messages.po +10695 -0
- package/src/locales/ro/messages.ts +1 -0
- package/src/locales/ru/messages.d.ts +4 -0
- package/src/locales/ru/messages.po +10695 -0
- package/src/locales/ru/messages.ts +1 -0
- package/src/locales/sk/messages.d.ts +4 -0
- package/src/locales/sk/messages.po +10695 -0
- package/src/locales/sk/messages.ts +1 -0
- package/src/locales/sl/messages.d.ts +4 -0
- package/src/locales/sl/messages.po +10695 -0
- package/src/locales/sl/messages.ts +1 -0
- package/src/locales/sr/messages.d.ts +4 -0
- package/src/locales/sr/messages.po +10695 -0
- package/src/locales/sr/messages.ts +1 -0
- package/src/locales/sv/messages.d.ts +4 -0
- package/src/locales/sv/messages.po +10695 -0
- package/src/locales/sv/messages.ts +1 -0
- package/src/locales/th/messages.d.ts +4 -0
- package/src/locales/th/messages.po +10695 -0
- package/src/locales/th/messages.ts +1 -0
- package/src/locales/tr/messages.d.ts +4 -0
- package/src/locales/tr/messages.po +10695 -0
- package/src/locales/tr/messages.ts +1 -0
- package/src/locales/uk/messages.d.ts +3 -0
- package/src/locales/uk/messages.po +10695 -0
- package/src/locales/uk/messages.ts +1 -0
- package/src/locales/vi/messages.d.ts +4 -0
- package/src/locales/vi/messages.po +10695 -0
- package/src/locales/vi/messages.ts +1 -0
- package/src/locales/zh_Hans/messages.d.ts +4 -0
- package/src/locales/zh_Hans/messages.po +10695 -0
- package/src/locales/zh_Hans/messages.ts +1 -0
- package/src/locales/zh_Hant/messages.d.ts +4 -0
- package/src/locales/zh_Hant/messages.po +10695 -0
- package/src/locales/zh_Hant/messages.ts +1 -0
- package/src/main.css.ts +148 -0
- package/src/main.tsx +123 -0
- package/src/pages/Auth/ChangePassword.tsx +84 -0
- package/src/pages/Auth/Layout.tsx +74 -0
- package/src/pages/Auth/LoggedIn.tsx +21 -0
- package/src/pages/Auth/Login.tsx +133 -0
- package/src/pages/Auth/Logout.tsx +16 -0
- package/src/pages/Auth/MFA.tsx +36 -0
- package/src/pages/Auth/MFASetup.tsx +38 -0
- package/src/pages/Auth/Register.tsx +28 -0
- package/src/pages/Auth/Reset.tsx +30 -0
- package/src/pages/Auth/ResetPassword.tsx +48 -0
- package/src/pages/Auth/VerifyEmail.tsx +34 -0
- package/src/pages/ErrorPage.tsx +26 -0
- package/src/pages/Index/Home.tsx +12 -0
- package/src/pages/Index/Scan.tsx +258 -0
- package/src/pages/Index/Settings/AccountSettings/AccountDetailPanel.tsx +162 -0
- package/src/pages/Index/Settings/AccountSettings/QrRegistrationForm.tsx +38 -0
- package/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx +713 -0
- package/src/pages/Index/Settings/AccountSettings/UserPanel.tsx +24 -0
- package/src/pages/Index/Settings/AccountSettings/UserThemePanel.tsx +207 -0
- package/src/pages/Index/Settings/AccountSettings/useConfirm.tsx +117 -0
- package/src/pages/Index/Settings/AdminCenter/CurrencyManagementPanel.tsx +111 -0
- package/src/pages/Index/Settings/AdminCenter/Index.tsx +251 -0
- package/src/pages/Index/Settings/AdminCenter/LabelTemplatePanel.tsx +23 -0
- package/src/pages/Index/Settings/AdminCenter/MachineManagementPanel.tsx +110 -0
- package/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx +29 -0
- package/src/pages/Index/Settings/AdminCenter/PluginManagementPanel.tsx +84 -0
- package/src/pages/Index/Settings/AdminCenter/ReportTemplatePanel.tsx +38 -0
- package/src/pages/Index/Settings/AdminCenter/StocktakePanel.tsx +31 -0
- package/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx +73 -0
- package/src/pages/Index/Settings/AdminCenter/UnitManagementPanel.tsx +74 -0
- package/src/pages/Index/Settings/AdminCenter/UserManagementPanel.tsx +49 -0
- package/src/pages/Index/Settings/SystemSettings.tsx +339 -0
- package/src/pages/Index/Settings/UserSettings.tsx +143 -0
- package/src/pages/Notifications.tsx +134 -0
- package/src/pages/build/BuildDetail.tsx +579 -0
- package/src/pages/build/BuildIndex.tsx +100 -0
- package/src/pages/company/CompanyDetail.tsx +352 -0
- package/src/pages/company/CustomerDetail.tsx +13 -0
- package/src/pages/company/ManufacturerDetail.tsx +13 -0
- package/src/pages/company/ManufacturerPartDetail.tsx +307 -0
- package/src/pages/company/SupplierDetail.tsx +13 -0
- package/src/pages/company/SupplierPartDetail.tsx +433 -0
- package/src/pages/core/CoreIndex.tsx +50 -0
- package/src/pages/core/GroupDetail.tsx +97 -0
- package/src/pages/core/UserDetail.tsx +193 -0
- package/src/pages/part/CategoryDetail.tsx +369 -0
- package/src/pages/part/PartAllocationPanel.tsx +40 -0
- package/src/pages/part/PartDetail.tsx +1071 -0
- package/src/pages/part/PartPricingPanel.tsx +155 -0
- package/src/pages/part/PartSchedulingDetail.tsx +315 -0
- package/src/pages/part/PartStocktakeDetail.tsx +285 -0
- package/src/pages/part/PartSupplierDetail.tsx +31 -0
- package/src/pages/part/pricing/BomPricingPanel.tsx +269 -0
- package/src/pages/part/pricing/PriceBreakPanel.tsx +182 -0
- package/src/pages/part/pricing/PricingOverviewPanel.tsx +338 -0
- package/src/pages/part/pricing/PricingPanel.tsx +82 -0
- package/src/pages/part/pricing/PurchaseHistoryPanel.tsx +134 -0
- package/src/pages/part/pricing/SaleHistoryPanel.tsx +95 -0
- package/src/pages/part/pricing/SupplierPricingPanel.tsx +80 -0
- package/src/pages/part/pricing/VariantPricingPanel.tsx +112 -0
- package/src/pages/purchasing/PurchaseOrderDetail.tsx +547 -0
- package/src/pages/purchasing/PurchasingIndex.tsx +131 -0
- package/src/pages/sales/ReturnOrderDetail.tsx +529 -0
- package/src/pages/sales/SalesIndex.tsx +148 -0
- package/src/pages/sales/SalesOrderDetail.tsx +593 -0
- package/src/pages/sales/SalesOrderShipmentDetail.tsx +385 -0
- package/src/pages/stock/LocationDetail.tsx +413 -0
- package/src/pages/stock/StockDetail.tsx +951 -0
- package/src/router.tsx +213 -0
- package/src/states/ApiState.tsx +85 -0
- package/src/states/IconState.tsx +94 -0
- package/src/states/LocalState.tsx +181 -0
- package/src/states/SettingsState.tsx +206 -0
- package/src/states/StatusState.tsx +55 -0
- package/src/states/UserState.tsx +202 -0
- package/src/states/states.tsx +69 -0
- package/src/tables/Column.tsx +29 -0
- package/src/tables/ColumnRenderers.tsx +320 -0
- package/src/tables/ColumnSelect.tsx +39 -0
- package/src/tables/Filter.tsx +297 -0
- package/src/tables/FilterSelectDrawer.tsx +358 -0
- package/src/tables/InvenTreeTable.tsx +750 -0
- package/src/tables/InvenTreeTableHeader.tsx +257 -0
- package/src/tables/RowActions.tsx +176 -0
- package/src/tables/RowExpansionIcon.tsx +16 -0
- package/src/tables/Search.tsx +42 -0
- package/src/tables/TableHoverCard.tsx +91 -0
- package/src/tables/bom/BomTable.tsx +590 -0
- package/src/tables/bom/UsedInTable.tsx +114 -0
- package/src/tables/build/BuildAllocatedStockTable.tsx +233 -0
- package/src/tables/build/BuildLineTable.tsx +800 -0
- package/src/tables/build/BuildOrderTable.tsx +226 -0
- package/src/tables/build/BuildOrderTestTable.tsx +265 -0
- package/src/tables/build/BuildOutputTable.tsx +599 -0
- package/src/tables/company/AddressTable.tsx +211 -0
- package/src/tables/company/CompanyTable.tsx +176 -0
- package/src/tables/company/ContactTable.tsx +182 -0
- package/src/tables/core/UserTable.tsx +88 -0
- package/src/tables/general/AttachmentTable.tsx +404 -0
- package/src/tables/general/BarcodeScanTable.tsx +124 -0
- package/src/tables/general/ExtraLineItemTable.tsx +174 -0
- package/src/tables/machine/MachineListTable.tsx +634 -0
- package/src/tables/machine/MachineTypeTable.tsx +395 -0
- package/src/tables/notifications/NotificationTable.tsx +60 -0
- package/src/tables/part/ParametricPartTable.tsx +297 -0
- package/src/tables/part/PartBuildAllocationsTable.tsx +128 -0
- package/src/tables/part/PartCategoryTable.tsx +208 -0
- package/src/tables/part/PartCategoryTemplateTable.tsx +157 -0
- package/src/tables/part/PartParameterTable.tsx +226 -0
- package/src/tables/part/PartParameterTemplateTable.tsx +168 -0
- package/src/tables/part/PartPurchaseOrdersTable.tsx +163 -0
- package/src/tables/part/PartSalesAllocationsTable.tsx +130 -0
- package/src/tables/part/PartTable.tsx +423 -0
- package/src/tables/part/PartTestTemplateTable.tsx +290 -0
- package/src/tables/part/PartThumbTable.tsx +230 -0
- package/src/tables/part/PartVariantTable.tsx +52 -0
- package/src/tables/part/RelatedPartTable.tsx +182 -0
- package/src/tables/part/SelectionListTable.tsx +134 -0
- package/src/tables/plugin/PluginErrorTable.tsx +58 -0
- package/src/tables/plugin/PluginListTable.tsx +440 -0
- package/src/tables/purchasing/ManufacturerPartParameterTable.tsx +136 -0
- package/src/tables/purchasing/ManufacturerPartTable.tsx +158 -0
- package/src/tables/purchasing/PurchaseOrderLineItemTable.tsx +424 -0
- package/src/tables/purchasing/PurchaseOrderTable.tsx +193 -0
- package/src/tables/purchasing/SupplierPartTable.tsx +281 -0
- package/src/tables/purchasing/SupplierPriceBreakTable.tsx +222 -0
- package/src/tables/sales/ReturnOrderLineItemTable.tsx +271 -0
- package/src/tables/sales/ReturnOrderTable.tsx +201 -0
- package/src/tables/sales/SalesOrderAllocationTable.tsx +330 -0
- package/src/tables/sales/SalesOrderLineItemTable.tsx +508 -0
- package/src/tables/sales/SalesOrderShipmentTable.tsx +225 -0
- package/src/tables/sales/SalesOrderTable.tsx +212 -0
- package/src/tables/settings/ApiTokenTable.tsx +203 -0
- package/src/tables/settings/BarcodeScanHistoryTable.tsx +281 -0
- package/src/tables/settings/CustomStateTable.tsx +226 -0
- package/src/tables/settings/CustomUnitsTable.tsx +125 -0
- package/src/tables/settings/ErrorTable.tsx +170 -0
- package/src/tables/settings/ExportSessionTable.tsx +60 -0
- package/src/tables/settings/FailedTasksTable.tsx +103 -0
- package/src/tables/settings/GroupTable.tsx +240 -0
- package/src/tables/settings/ImportSessionTable.tsx +175 -0
- package/src/tables/settings/PendingTasksTable.tsx +63 -0
- package/src/tables/settings/ProjectCodeTable.tsx +115 -0
- package/src/tables/settings/ScheduledTasksTable.tsx +62 -0
- package/src/tables/settings/StocktakeReportTable.tsx +111 -0
- package/src/tables/settings/TemplateTable.tsx +404 -0
- package/src/tables/settings/UserTable.tsx +329 -0
- package/src/tables/stock/InstalledItemsTable.tsx +146 -0
- package/src/tables/stock/LocationTypesTable.tsx +132 -0
- package/src/tables/stock/StockItemTable.tsx +707 -0
- package/src/tables/stock/StockItemTestResultTable.tsx +487 -0
- package/src/tables/stock/StockLocationTable.tsx +208 -0
- package/src/tables/stock/StockTrackingTable.tsx +244 -0
- package/src/theme.ts +5 -0
- package/src/views/DesktopAppView.tsx +28 -0
- package/src/views/MainView.tsx +38 -0
- package/src/views/MobileAppView.tsx +43 -0
- package/tests/baseFixtures.ts +93 -0
- package/tests/defaults.ts +18 -0
- package/tests/helpers.ts +122 -0
- package/tests/login.ts +97 -0
- package/tests/pages/pui_build.spec.ts +373 -0
- package/tests/pages/pui_company.spec.ts +40 -0
- package/tests/pages/pui_core.spec.ts +26 -0
- package/tests/pages/pui_dashboard.spec.ts +64 -0
- package/tests/pages/pui_part.spec.ts +413 -0
- package/tests/pages/pui_purchase_order.spec.ts +388 -0
- package/tests/pages/pui_sales_order.spec.ts +224 -0
- package/tests/pages/pui_scan.spec.ts +114 -0
- package/tests/pages/pui_stock.spec.ts +259 -0
- package/tests/pui_exporting.spec.ts +124 -0
- package/tests/pui_forms.spec.ts +131 -0
- package/tests/pui_general.spec.ts +60 -0
- package/tests/pui_login.spec.ts +74 -0
- package/tests/pui_modals.spec.ts +144 -0
- package/tests/pui_plugins.spec.ts +216 -0
- package/tests/pui_printing.spec.ts +149 -0
- package/tests/pui_settings.spec.ts +285 -0
- package/tests/pui_tables.spec.ts +65 -0
- package/tests/settings/selectionList.spec.ts +103 -0
- package/tests/settings.ts +54 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +13 -0
- package/tsconfig.node.json +11 -0
- package/vite-env.d.ts +11 -0
- package/vite.config.ts +98 -0
- package/vite.lib.config.ts +50 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Stack } from '@mantine/core';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { InvenTreePluginContext } from '@lib/types/Plugins';
|
|
5
|
+
import type { PluginUIFeature } from './PluginUIFeature';
|
|
6
|
+
import RemoteComponent from './RemoteComponent';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A custom panel which can be used to display plugin content.
|
|
10
|
+
*
|
|
11
|
+
* - Content is loaded dynamically (via the API) when a page is first loaded
|
|
12
|
+
* - Content can be provided from an external javascript module, or with raw HTML
|
|
13
|
+
*
|
|
14
|
+
* If content is provided from an external source, it is expected to define a function `render_panel` which will render the content.
|
|
15
|
+
* const render_panel = (element: HTMLElement, params: any) => {...}
|
|
16
|
+
*
|
|
17
|
+
* Where:
|
|
18
|
+
* - `element` is the HTML element to render the content into
|
|
19
|
+
* - `params` is the set of run-time parameters to pass to the content rendering function
|
|
20
|
+
*/
|
|
21
|
+
export default function PluginPanelContent({
|
|
22
|
+
pluginFeature,
|
|
23
|
+
pluginContext
|
|
24
|
+
}: Readonly<{
|
|
25
|
+
pluginFeature: PluginUIFeature;
|
|
26
|
+
pluginContext: InvenTreePluginContext;
|
|
27
|
+
}>): ReactNode {
|
|
28
|
+
return (
|
|
29
|
+
<Stack gap='xs'>
|
|
30
|
+
<RemoteComponent
|
|
31
|
+
source={pluginFeature.source}
|
|
32
|
+
defaultFunctionName='renderPanel'
|
|
33
|
+
context={pluginContext}
|
|
34
|
+
/>
|
|
35
|
+
</Stack>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { InvenTreePluginContext } from '@lib/types/Plugins';
|
|
2
|
+
import { useInvenTreeContext } from './PluginContext';
|
|
3
|
+
import RemoteComponent from './RemoteComponent';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Interface for the plugin admin data
|
|
7
|
+
*/
|
|
8
|
+
export interface PluginAdminInterface {
|
|
9
|
+
source: string;
|
|
10
|
+
context: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A panel which is used to display custom settings UI for a plugin.
|
|
15
|
+
*
|
|
16
|
+
* This settings panel is loaded dynamically,
|
|
17
|
+
* and requires that the plugin provides a javascript module,
|
|
18
|
+
* which exports a function `renderPluginSettings`
|
|
19
|
+
*/
|
|
20
|
+
export default function PluginSettingsPanel({
|
|
21
|
+
pluginAdmin
|
|
22
|
+
}: Readonly<{
|
|
23
|
+
pluginAdmin: PluginAdminInterface;
|
|
24
|
+
}>) {
|
|
25
|
+
const ctx: InvenTreePluginContext = useInvenTreeContext();
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<RemoteComponent
|
|
29
|
+
source={pluginAdmin.source}
|
|
30
|
+
defaultFunctionName='renderPluginSettings'
|
|
31
|
+
context={{ ...ctx, context: pluginAdmin.context }}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { generateUrl } from '../../functions/urls';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Load an external plugin source from a URL.
|
|
5
|
+
*/
|
|
6
|
+
export async function loadExternalPluginSource(source: string) {
|
|
7
|
+
source = source.trim();
|
|
8
|
+
|
|
9
|
+
// If no source is provided, clear the plugin content
|
|
10
|
+
if (!source) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const url = generateUrl(source);
|
|
15
|
+
|
|
16
|
+
const module = await import(/* @vite-ignore */ url)
|
|
17
|
+
.catch((error) => {
|
|
18
|
+
console.error(`ERR: Failed to load plugin from ${url}:`, error);
|
|
19
|
+
return null;
|
|
20
|
+
})
|
|
21
|
+
.then((module) => {
|
|
22
|
+
return module;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return module;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* Find a named function in an external plugin source.
|
|
30
|
+
*/
|
|
31
|
+
export async function findExternalPluginFunction(
|
|
32
|
+
source: string,
|
|
33
|
+
functionName: string
|
|
34
|
+
): Promise<Function | null> {
|
|
35
|
+
// The source URL may also include the function name divided by a colon
|
|
36
|
+
// otherwise the provided function name will be used
|
|
37
|
+
if (source.includes(':')) {
|
|
38
|
+
[source, functionName] = source.split(':');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const module = await loadExternalPluginSource(source);
|
|
42
|
+
|
|
43
|
+
if (module?.[functionName]) {
|
|
44
|
+
return module[functionName];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { t } from '@lingui/core/macro';
|
|
2
|
+
import { Alert, Stack, Text } from '@mantine/core';
|
|
3
|
+
import { IconExclamationCircle } from '@tabler/icons-react';
|
|
4
|
+
import {
|
|
5
|
+
forwardRef,
|
|
6
|
+
useEffect,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
useRef,
|
|
9
|
+
useState
|
|
10
|
+
} from 'react';
|
|
11
|
+
|
|
12
|
+
import type { TemplateI } from '../../tables/settings/TemplateTable';
|
|
13
|
+
import type {
|
|
14
|
+
EditorComponent,
|
|
15
|
+
PreviewAreaComponent,
|
|
16
|
+
PreviewAreaRef
|
|
17
|
+
} from '../editors/TemplateEditor/TemplateEditor';
|
|
18
|
+
import type {
|
|
19
|
+
PluginUIFuncWithoutInvenTreeContextType,
|
|
20
|
+
TemplateEditorUIFeature,
|
|
21
|
+
TemplatePreviewUIFeature
|
|
22
|
+
} from './PluginUIFeatureTypes';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Enumeration for available plugin UI feature types.
|
|
26
|
+
*/
|
|
27
|
+
export enum PluginUIFeatureType {
|
|
28
|
+
dashboard = 'dashboard',
|
|
29
|
+
panel = 'panel',
|
|
30
|
+
template_editor = 'template_editor',
|
|
31
|
+
template_preview = 'template_preview'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Type definition for a UI component which can be loaded via plugin.
|
|
36
|
+
* Ref: src/backend/InvenTree/plugin/base/ui/serializers.py:PluginUIFeatureSerializer
|
|
37
|
+
*
|
|
38
|
+
* @param plugin_name: The name of the plugin
|
|
39
|
+
* @param feature_type: The type of the UI feature (see PluginUIFeatureType)
|
|
40
|
+
* @param key: The unique key for the feature (used to identify the feature in the DOM)
|
|
41
|
+
* @param title: The title of the feature (human readable)
|
|
42
|
+
* @param description: A description of the feature (human readable, optional)
|
|
43
|
+
* @param options: Additional options for the feature (optional, depends on the feature type)
|
|
44
|
+
* @param context: Additional context data passed to the rendering function (optional)
|
|
45
|
+
* @param source: The source of the feature (must point to an accessible javascript module)
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
export interface PluginUIFeature {
|
|
49
|
+
plugin_name: string;
|
|
50
|
+
feature_type: PluginUIFeatureType;
|
|
51
|
+
key: string;
|
|
52
|
+
title: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
icon?: string;
|
|
55
|
+
options?: any;
|
|
56
|
+
context?: any;
|
|
57
|
+
source: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const getPluginTemplateEditor = (
|
|
61
|
+
func: PluginUIFuncWithoutInvenTreeContextType<TemplateEditorUIFeature>,
|
|
62
|
+
template: TemplateI
|
|
63
|
+
) =>
|
|
64
|
+
forwardRef((props, ref) => {
|
|
65
|
+
const elRef = useRef<HTMLDivElement>();
|
|
66
|
+
const [error, setError] = useState<string | undefined>(undefined);
|
|
67
|
+
|
|
68
|
+
const initialCodeRef = useRef<string>();
|
|
69
|
+
const setCodeRef = useRef<(code: string) => void>();
|
|
70
|
+
const getCodeRef = useRef<() => string>();
|
|
71
|
+
|
|
72
|
+
useImperativeHandle(ref, () => ({
|
|
73
|
+
setCode: (code) => {
|
|
74
|
+
// if the editor is not yet initialized, store the initial code in a ref to set it later
|
|
75
|
+
if (setCodeRef.current) {
|
|
76
|
+
setCodeRef.current(code);
|
|
77
|
+
} else {
|
|
78
|
+
initialCodeRef.current = code;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
getCode: () => getCodeRef.current?.()
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
let unmountHandler: (() => void) | undefined;
|
|
86
|
+
(async () => {
|
|
87
|
+
try {
|
|
88
|
+
unmountHandler = await func({
|
|
89
|
+
ref: elRef.current!,
|
|
90
|
+
registerHandlers: ({ getCode, setCode }) => {
|
|
91
|
+
setCodeRef.current = setCode;
|
|
92
|
+
getCodeRef.current = getCode;
|
|
93
|
+
|
|
94
|
+
if (initialCodeRef.current) {
|
|
95
|
+
setCode(initialCodeRef.current);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
template
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
setError(t`Error occurred while rendering the template editor.`);
|
|
102
|
+
console.error(error);
|
|
103
|
+
}
|
|
104
|
+
})();
|
|
105
|
+
|
|
106
|
+
return () => {
|
|
107
|
+
if (typeof unmountHandler === 'function') {
|
|
108
|
+
unmountHandler();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}, []);
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<Stack gap='xs' style={{ display: 'flex', flex: 1 }}>
|
|
115
|
+
{error && (
|
|
116
|
+
<Alert
|
|
117
|
+
color='red'
|
|
118
|
+
title={t`Error Loading Plugin Editor`}
|
|
119
|
+
icon={<IconExclamationCircle />}
|
|
120
|
+
>
|
|
121
|
+
<Text>{error}</Text>
|
|
122
|
+
</Alert>
|
|
123
|
+
)}
|
|
124
|
+
<div ref={elRef as any} style={{ display: 'flex', flex: 1 }} />
|
|
125
|
+
</Stack>
|
|
126
|
+
);
|
|
127
|
+
}) as EditorComponent;
|
|
128
|
+
|
|
129
|
+
export const getPluginTemplatePreview = (
|
|
130
|
+
func: PluginUIFuncWithoutInvenTreeContextType<TemplatePreviewUIFeature>,
|
|
131
|
+
template: TemplateI
|
|
132
|
+
) =>
|
|
133
|
+
forwardRef((props, ref) => {
|
|
134
|
+
const elRef = useRef<HTMLDivElement>();
|
|
135
|
+
const [error, setError] = useState<string | undefined>(undefined);
|
|
136
|
+
|
|
137
|
+
const updatePreviewRef = useRef<PreviewAreaRef['updatePreview']>();
|
|
138
|
+
|
|
139
|
+
useImperativeHandle(ref, () => ({
|
|
140
|
+
updatePreview: (...args) => updatePreviewRef.current?.(...args)
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
(async () => {
|
|
145
|
+
try {
|
|
146
|
+
func({
|
|
147
|
+
ref: elRef.current!,
|
|
148
|
+
registerHandlers: ({ updatePreview }) => {
|
|
149
|
+
updatePreviewRef.current = updatePreview;
|
|
150
|
+
},
|
|
151
|
+
template
|
|
152
|
+
});
|
|
153
|
+
} catch (error) {
|
|
154
|
+
setError(t`Error occurred while rendering the template preview.`);
|
|
155
|
+
console.error(error);
|
|
156
|
+
}
|
|
157
|
+
})();
|
|
158
|
+
}, []);
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<Stack gap='xs' style={{ display: 'flex', flex: 1 }}>
|
|
162
|
+
{error && (
|
|
163
|
+
<Alert
|
|
164
|
+
color='red'
|
|
165
|
+
title={t`Error Loading Plugin Preview`}
|
|
166
|
+
icon={<IconExclamationCircle />}
|
|
167
|
+
>
|
|
168
|
+
<Text>{error}</Text>
|
|
169
|
+
</Alert>
|
|
170
|
+
)}
|
|
171
|
+
<div ref={elRef as any} style={{ display: 'flex', flex: 1 }} />
|
|
172
|
+
</Stack>
|
|
173
|
+
);
|
|
174
|
+
}) as PreviewAreaComponent;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { ModelType } from '@lib/enums/ModelType';
|
|
2
|
+
import type { InvenTreePluginContext } from '@lib/types/Plugins';
|
|
3
|
+
import type { InvenTreeIconType } from '../../functions/icons';
|
|
4
|
+
import type { TemplateI } from '../../tables/settings/TemplateTable';
|
|
5
|
+
import type { TemplateEditorProps } from '../editors/TemplateEditor/TemplateEditor';
|
|
6
|
+
import type { PluginUIFeature } from './PluginUIFeature';
|
|
7
|
+
|
|
8
|
+
// #region Type Helpers
|
|
9
|
+
export type BaseUIFeature = {
|
|
10
|
+
featureType: string;
|
|
11
|
+
requestContext: Record<string, any>;
|
|
12
|
+
responseOptions: Record<string, any>;
|
|
13
|
+
featureContext: Record<string, any>;
|
|
14
|
+
featureReturnType: any;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type PluginUIGetFeatureType<
|
|
18
|
+
T extends BaseUIFeature,
|
|
19
|
+
ServerContext extends Record<string, unknown>
|
|
20
|
+
> = (params: {
|
|
21
|
+
featureContext: T['featureContext'];
|
|
22
|
+
inventreeContext: InvenTreePluginContext;
|
|
23
|
+
serverContext: ServerContext;
|
|
24
|
+
}) => T['featureReturnType'];
|
|
25
|
+
|
|
26
|
+
export type PluginUIFuncWithoutInvenTreeContextType<T extends BaseUIFeature> = (
|
|
27
|
+
featureContext: T['featureContext']
|
|
28
|
+
) => T['featureReturnType'];
|
|
29
|
+
|
|
30
|
+
export type PluginUIFeatureAPIResponse<T extends BaseUIFeature> = {
|
|
31
|
+
feature_type: T['featureType'];
|
|
32
|
+
source: string;
|
|
33
|
+
} & T['responseOptions'];
|
|
34
|
+
|
|
35
|
+
// #region Types
|
|
36
|
+
export type TemplateEditorUIFeature = {
|
|
37
|
+
featureType: 'template_editor';
|
|
38
|
+
requestContext: {
|
|
39
|
+
template_type: ModelType.labeltemplate | ModelType.reporttemplate;
|
|
40
|
+
template_model: ModelType;
|
|
41
|
+
};
|
|
42
|
+
responseOptions: PluginUIFeature;
|
|
43
|
+
featureContext: {
|
|
44
|
+
ref: HTMLDivElement;
|
|
45
|
+
registerHandlers: (handlers: {
|
|
46
|
+
setCode: (code: string) => void;
|
|
47
|
+
getCode: () => string;
|
|
48
|
+
}) => void;
|
|
49
|
+
template: TemplateI;
|
|
50
|
+
};
|
|
51
|
+
featureReturnType: (() => void) | undefined;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type TemplatePreviewUIFeature = {
|
|
55
|
+
featureType: 'template_preview';
|
|
56
|
+
requestContext: {
|
|
57
|
+
template_type: ModelType.labeltemplate | ModelType.reporttemplate;
|
|
58
|
+
template_model: ModelType;
|
|
59
|
+
};
|
|
60
|
+
responseOptions: {
|
|
61
|
+
key: string;
|
|
62
|
+
title: string;
|
|
63
|
+
icon: InvenTreeIconType;
|
|
64
|
+
};
|
|
65
|
+
featureContext: {
|
|
66
|
+
ref: HTMLDivElement;
|
|
67
|
+
template: TemplateI;
|
|
68
|
+
registerHandlers: (handlers: {
|
|
69
|
+
updatePreview: (
|
|
70
|
+
code: string,
|
|
71
|
+
previewItem: string,
|
|
72
|
+
saveTemplate: boolean,
|
|
73
|
+
templateEditorProps: TemplateEditorProps
|
|
74
|
+
) => void | Promise<void>;
|
|
75
|
+
}) => void;
|
|
76
|
+
};
|
|
77
|
+
featureReturnType: undefined;
|
|
78
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { t } from '@lingui/core/macro';
|
|
2
|
+
import { Alert, MantineProvider, Stack, Text } from '@mantine/core';
|
|
3
|
+
import { IconExclamationCircle } from '@tabler/icons-react';
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import type { InvenTreePluginContext } from '@lib/types/Plugins';
|
|
7
|
+
import { type Root, createRoot } from 'react-dom/client';
|
|
8
|
+
import { api, queryClient } from '../../App';
|
|
9
|
+
import { ApiProvider } from '../../contexts/ApiContext';
|
|
10
|
+
import { LanguageContext } from '../../contexts/LanguageContext';
|
|
11
|
+
import { identifierString } from '../../functions/conversion';
|
|
12
|
+
import { Boundary } from '../Boundary';
|
|
13
|
+
import { findExternalPluginFunction } from './PluginSource';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A remote component which can be used to display plugin content.
|
|
17
|
+
* Content is loaded dynamically (from an external source).
|
|
18
|
+
*
|
|
19
|
+
* @param pluginFeature: The plugin feature to render
|
|
20
|
+
* @param defaultFunctionName: The default function name to call (if not overridden by pluginFeature.source)
|
|
21
|
+
* @param pluginContext: The context to pass to the plugin function
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export default function RemoteComponent({
|
|
25
|
+
source,
|
|
26
|
+
defaultFunctionName,
|
|
27
|
+
context
|
|
28
|
+
}: Readonly<{
|
|
29
|
+
source: string;
|
|
30
|
+
defaultFunctionName: string;
|
|
31
|
+
context: InvenTreePluginContext;
|
|
32
|
+
}>) {
|
|
33
|
+
const componentRef = useRef<HTMLDivElement>();
|
|
34
|
+
const [rootElement, setRootElement] = useState<Root | null>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (componentRef.current && !rootElement) {
|
|
38
|
+
setRootElement(createRoot(componentRef.current));
|
|
39
|
+
}
|
|
40
|
+
}, [componentRef.current]);
|
|
41
|
+
|
|
42
|
+
const [renderingError, setRenderingError] = useState<string | undefined>(
|
|
43
|
+
undefined
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const sourceFile = useMemo(() => {
|
|
47
|
+
return source.split(':')[0];
|
|
48
|
+
}, [source]);
|
|
49
|
+
|
|
50
|
+
// Determine the function to call in the external plugin source
|
|
51
|
+
const functionName = useMemo(() => {
|
|
52
|
+
// The "source" string may contain a function name, e.g. "source.js:myFunction"
|
|
53
|
+
if (source.includes(':')) {
|
|
54
|
+
return source.split(':')[1];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// By default, return the default function name
|
|
58
|
+
return defaultFunctionName;
|
|
59
|
+
}, [source, defaultFunctionName]);
|
|
60
|
+
|
|
61
|
+
const reloadPluginContent = useCallback(() => {
|
|
62
|
+
if (!rootElement) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (sourceFile && functionName) {
|
|
67
|
+
findExternalPluginFunction(sourceFile, functionName)
|
|
68
|
+
.then((func) => {
|
|
69
|
+
if (!!func) {
|
|
70
|
+
try {
|
|
71
|
+
if (func.length > 1) {
|
|
72
|
+
// Support "legacy" plugin functions which call createRoot() internally
|
|
73
|
+
// Ref: https://github.com/inventree/InvenTree/pull/9439/
|
|
74
|
+
func(componentRef.current, context);
|
|
75
|
+
} else {
|
|
76
|
+
// Render the plugin component into the target element
|
|
77
|
+
// Note that we have to provide the right context(s) to the component
|
|
78
|
+
// This approach ensures that the component is rendered in the correct context tree
|
|
79
|
+
rootElement.render(
|
|
80
|
+
<ApiProvider client={queryClient} api={api}>
|
|
81
|
+
<MantineProvider
|
|
82
|
+
theme={context.theme}
|
|
83
|
+
defaultColorScheme={context.colorScheme}
|
|
84
|
+
>
|
|
85
|
+
<LanguageContext>{func(context)}</LanguageContext>
|
|
86
|
+
</MantineProvider>
|
|
87
|
+
</ApiProvider>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setRenderingError('');
|
|
92
|
+
} catch (error) {
|
|
93
|
+
setRenderingError(`${error}`);
|
|
94
|
+
console.error(error);
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
setRenderingError(`${sourceFile}:${functionName}`);
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
.catch((_error) => {
|
|
101
|
+
console.error(
|
|
102
|
+
`ERR: Failed to load remove plugin function: ${sourceFile}:${functionName}`
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
setRenderingError(
|
|
107
|
+
`${t`Invalid source or function name`} - ${sourceFile}:${functionName}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}, [componentRef, rootElement, sourceFile, functionName, context]);
|
|
111
|
+
|
|
112
|
+
// Reload the plugin content dynamically
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
reloadPluginContent();
|
|
115
|
+
}, [sourceFile, functionName, context, rootElement]);
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<Boundary
|
|
119
|
+
label={identifierString(`RemoteComponent-${sourceFile}-${functionName}`)}
|
|
120
|
+
>
|
|
121
|
+
<Stack gap='xs'>
|
|
122
|
+
{renderingError && (
|
|
123
|
+
<Alert
|
|
124
|
+
color='red'
|
|
125
|
+
title={t`Error Loading Content`}
|
|
126
|
+
icon={<IconExclamationCircle />}
|
|
127
|
+
>
|
|
128
|
+
<Text>
|
|
129
|
+
{t`Error occurred while loading plugin content`}: {renderingError}
|
|
130
|
+
</Text>
|
|
131
|
+
</Alert>
|
|
132
|
+
)}
|
|
133
|
+
{componentRef && <div ref={componentRef as any} />}
|
|
134
|
+
</Stack>
|
|
135
|
+
</Boundary>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ModelType } from '@lib/enums/ModelType';
|
|
4
|
+
import { getDetailUrl } from '../../functions/urls';
|
|
5
|
+
import { type InstanceRenderInterface, RenderInlineModel } from './Instance';
|
|
6
|
+
import { StatusRenderer } from './StatusRenderer';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Inline rendering of a single BuildOrder instance
|
|
10
|
+
*/
|
|
11
|
+
export function RenderBuildOrder(
|
|
12
|
+
props: Readonly<InstanceRenderInterface>
|
|
13
|
+
): ReactNode {
|
|
14
|
+
const { instance } = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<RenderInlineModel
|
|
18
|
+
{...props}
|
|
19
|
+
primary={instance.reference}
|
|
20
|
+
secondary={instance.title}
|
|
21
|
+
suffix={StatusRenderer({
|
|
22
|
+
status: instance.status_custom_key,
|
|
23
|
+
type: ModelType.build
|
|
24
|
+
})}
|
|
25
|
+
image={instance.part_detail?.thumbnail || instance.part_detail?.image}
|
|
26
|
+
url={props.link ? getDetailUrl(ModelType.build, instance.pk) : undefined}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* Inline rendering of a single BuildLine instance
|
|
33
|
+
*/
|
|
34
|
+
export function RenderBuildLine({
|
|
35
|
+
instance
|
|
36
|
+
}: Readonly<InstanceRenderInterface>): ReactNode {
|
|
37
|
+
return (
|
|
38
|
+
<RenderInlineModel
|
|
39
|
+
primary={instance.part_detail.full_name}
|
|
40
|
+
secondary={instance.quantity}
|
|
41
|
+
suffix={StatusRenderer({
|
|
42
|
+
status: instance.status_custom_key,
|
|
43
|
+
type: ModelType.build
|
|
44
|
+
})}
|
|
45
|
+
image={instance.part_detail.thumbnail || instance.part_detail.image}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function RenderBuildItem({
|
|
51
|
+
instance
|
|
52
|
+
}: Readonly<InstanceRenderInterface>): ReactNode {
|
|
53
|
+
return <RenderInlineModel primary={instance.pk} />;
|
|
54
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Text } from '@mantine/core';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { ModelType } from '@lib/enums/ModelType';
|
|
5
|
+
import { getDetailUrl } from '../../functions/urls';
|
|
6
|
+
import { type InstanceRenderInterface, RenderInlineModel } from './Instance';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Inline rendering of a single Address instance
|
|
10
|
+
*/
|
|
11
|
+
export function RenderAddress({
|
|
12
|
+
instance
|
|
13
|
+
}: Readonly<InstanceRenderInterface>): ReactNode {
|
|
14
|
+
const text = [
|
|
15
|
+
instance.country,
|
|
16
|
+
instance.postal_code,
|
|
17
|
+
instance.postal_city,
|
|
18
|
+
instance.province,
|
|
19
|
+
instance.line1,
|
|
20
|
+
instance.line2
|
|
21
|
+
]
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
.join(', ');
|
|
24
|
+
|
|
25
|
+
return <RenderInlineModel primary={instance.title} secondary={text} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Inline rendering of a single Company instance
|
|
30
|
+
*/
|
|
31
|
+
export function RenderCompany(
|
|
32
|
+
props: Readonly<InstanceRenderInterface>
|
|
33
|
+
): ReactNode {
|
|
34
|
+
const { instance } = props;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<RenderInlineModel
|
|
38
|
+
{...props}
|
|
39
|
+
image={instance.thumnbnail || instance.image}
|
|
40
|
+
primary={instance.name}
|
|
41
|
+
secondary={instance.description}
|
|
42
|
+
url={
|
|
43
|
+
props.link ? getDetailUrl(ModelType.company, instance.pk) : undefined
|
|
44
|
+
}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Inline rendering of a single Contact instance
|
|
51
|
+
*/
|
|
52
|
+
export function RenderContact({
|
|
53
|
+
instance
|
|
54
|
+
}: Readonly<InstanceRenderInterface>): ReactNode {
|
|
55
|
+
return <RenderInlineModel primary={instance.name} />;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Inline rendering of a single SupplierPart instance
|
|
60
|
+
*/
|
|
61
|
+
export function RenderSupplierPart(
|
|
62
|
+
props: Readonly<InstanceRenderInterface>
|
|
63
|
+
): ReactNode {
|
|
64
|
+
const { instance } = props;
|
|
65
|
+
const supplier = instance.supplier_detail ?? {};
|
|
66
|
+
const part = instance.part_detail ?? {};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<RenderInlineModel
|
|
70
|
+
{...props}
|
|
71
|
+
primary={supplier?.name}
|
|
72
|
+
secondary={instance.SKU}
|
|
73
|
+
image={
|
|
74
|
+
part?.thumbnail ?? part?.image ?? supplier?.thumbnail ?? supplier?.image
|
|
75
|
+
}
|
|
76
|
+
suffix={
|
|
77
|
+
part.full_name ? <Text size='sm'>{part.full_name}</Text> : undefined
|
|
78
|
+
}
|
|
79
|
+
url={
|
|
80
|
+
props.link
|
|
81
|
+
? getDetailUrl(ModelType.supplierpart, instance.pk)
|
|
82
|
+
: undefined
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Inline rendering of a single ManufacturerPart instance
|
|
90
|
+
*/
|
|
91
|
+
export function RenderManufacturerPart(
|
|
92
|
+
props: Readonly<InstanceRenderInterface>
|
|
93
|
+
): ReactNode {
|
|
94
|
+
const { instance } = props;
|
|
95
|
+
const part = instance.part_detail ?? {};
|
|
96
|
+
const manufacturer = instance.manufacturer_detail ?? {};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<RenderInlineModel
|
|
100
|
+
{...props}
|
|
101
|
+
primary={manufacturer.name}
|
|
102
|
+
secondary={instance.MPN}
|
|
103
|
+
suffix={
|
|
104
|
+
part.full_name ? <Text size='sm'>{part.full_name}</Text> : undefined
|
|
105
|
+
}
|
|
106
|
+
image={manufacturer?.thumnbnail ?? manufacturer.image}
|
|
107
|
+
url={
|
|
108
|
+
props.link
|
|
109
|
+
? getDetailUrl(ModelType.manufacturerpart, instance.pk)
|
|
110
|
+
: undefined
|
|
111
|
+
}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
}
|