@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.
Files changed (541) hide show
  1. package/.babelrc +8 -0
  2. package/.linguirc +55 -0
  3. package/README.md +17 -0
  4. package/index.html +15 -0
  5. package/lib/enums/ApiEndpoints.tsx +233 -0
  6. package/lib/enums/ModelType.tsx +38 -0
  7. package/lib/enums/Roles.tsx +25 -0
  8. package/lib/functions/Api.tsx +42 -0
  9. package/lib/functions/Plugins.tsx +27 -0
  10. package/lib/index.ts +11 -0
  11. package/lib/types/Auth.tsx +51 -0
  12. package/lib/types/Core.tsx +13 -0
  13. package/lib/types/Filters.tsx +69 -0
  14. package/lib/types/Forms.tsx +185 -0
  15. package/lib/types/Modals.tsx +17 -0
  16. package/lib/types/Plugins.tsx +68 -0
  17. package/lib/types/Server.tsx +8 -0
  18. package/lib/types/Settings.tsx +55 -0
  19. package/lib/types/Tables.tsx +69 -0
  20. package/lib/types/User.tsx +62 -0
  21. package/netlify.toml +22 -0
  22. package/package.json +125 -0
  23. package/playwright/global-setup.ts +45 -0
  24. package/playwright.config.ts +99 -0
  25. package/public/inventree.svg +291 -0
  26. package/src/App.tsx +35 -0
  27. package/src/assets/inventree.svg +1 -0
  28. package/src/components/Boundary.tsx +43 -0
  29. package/src/components/SplashScreen.tsx +35 -0
  30. package/src/components/barcodes/BarcodeCameraInput.tsx +207 -0
  31. package/src/components/barcodes/BarcodeInput.tsx +127 -0
  32. package/src/components/barcodes/BarcodeKeyboardInput.tsx +50 -0
  33. package/src/components/barcodes/BarcodeScanDialog.tsx +101 -0
  34. package/src/components/barcodes/BarcodeScanItem.tsx +23 -0
  35. package/src/components/barcodes/QRCode.tsx +211 -0
  36. package/src/components/buttons/ActionButton.tsx +61 -0
  37. package/src/components/buttons/AddItemButton.tsx +10 -0
  38. package/src/components/buttons/AdminButton.tsx +91 -0
  39. package/src/components/buttons/ButtonMenu.tsx +33 -0
  40. package/src/components/buttons/CopyButton.tsx +52 -0
  41. package/src/components/buttons/PrimaryActionButton.tsx +40 -0
  42. package/src/components/buttons/PrintingActions.tsx +191 -0
  43. package/src/components/buttons/RemoveRowButton.tsx +22 -0
  44. package/src/components/buttons/SSOButton.tsx +53 -0
  45. package/src/components/buttons/ScanButton.tsx +27 -0
  46. package/src/components/buttons/SegmentedIconControl.tsx +51 -0
  47. package/src/components/buttons/SplitButton.css.ts +19 -0
  48. package/src/components/buttons/SplitButton.tsx +111 -0
  49. package/src/components/buttons/SpotlightButton.tsx +22 -0
  50. package/src/components/buttons/StarredToggleButton.tsx +62 -0
  51. package/src/components/buttons/YesNoButton.tsx +42 -0
  52. package/src/components/calendar/Calendar.tsx +193 -0
  53. package/src/components/calendar/OrderCalendar.tsx +209 -0
  54. package/src/components/charts/colors.tsx +12 -0
  55. package/src/components/charts/tooltipFormatter.tsx +12 -0
  56. package/src/components/dashboard/DashboardLayout.tsx +327 -0
  57. package/src/components/dashboard/DashboardMenu.tsx +136 -0
  58. package/src/components/dashboard/DashboardWidget.tsx +82 -0
  59. package/src/components/dashboard/DashboardWidgetDrawer.tsx +130 -0
  60. package/src/components/dashboard/DashboardWidgetLibrary.tsx +189 -0
  61. package/src/components/dashboard/widgets/ColorToggleWidget.tsx +28 -0
  62. package/src/components/dashboard/widgets/GetStartedWidget.tsx +19 -0
  63. package/src/components/dashboard/widgets/LanguageSelectWidget.tsx +28 -0
  64. package/src/components/dashboard/widgets/NewsWidget.tsx +143 -0
  65. package/src/components/dashboard/widgets/QueryCountDashboardWidget.tsx +134 -0
  66. package/src/components/details/Details.tsx +514 -0
  67. package/src/components/details/DetailsBadge.tsx +20 -0
  68. package/src/components/details/DetailsImage.tsx +462 -0
  69. package/src/components/details/ItemDetails.tsx +17 -0
  70. package/src/components/editors/NotesEditor.tsx +232 -0
  71. package/src/components/editors/TemplateEditor/CodeEditor/CodeEditor.tsx +158 -0
  72. package/src/components/editors/TemplateEditor/CodeEditor/index.tsx +12 -0
  73. package/src/components/editors/TemplateEditor/PdfPreview/PdfPreview.tsx +90 -0
  74. package/src/components/editors/TemplateEditor/PdfPreview/index.tsx +12 -0
  75. package/src/components/editors/TemplateEditor/TemplateEditor.tsx +425 -0
  76. package/src/components/editors/TemplateEditor/index.tsx +3 -0
  77. package/src/components/errors/ClientError.tsx +28 -0
  78. package/src/components/errors/GenericErrorPage.tsx +73 -0
  79. package/src/components/errors/NotAuthenticated.tsx +12 -0
  80. package/src/components/errors/NotFound.tsx +12 -0
  81. package/src/components/errors/PermissionDenied.tsx +12 -0
  82. package/src/components/errors/ServerError.tsx +13 -0
  83. package/src/components/forms/ApiForm.tsx +718 -0
  84. package/src/components/forms/AuthFormOptions.tsx +39 -0
  85. package/src/components/forms/AuthenticationForm.tsx +332 -0
  86. package/src/components/forms/HostOptionsForm.tsx +96 -0
  87. package/src/components/forms/InstanceOptions.tsx +178 -0
  88. package/src/components/forms/StandaloneField.tsx +55 -0
  89. package/src/components/forms/fields/ApiFormField.tsx +281 -0
  90. package/src/components/forms/fields/ChoiceField.tsx +86 -0
  91. package/src/components/forms/fields/DateField.tsx +79 -0
  92. package/src/components/forms/fields/DependentField.tsx +91 -0
  93. package/src/components/forms/fields/IconField.tsx +353 -0
  94. package/src/components/forms/fields/NestedObjectField.tsx +45 -0
  95. package/src/components/forms/fields/RelatedModelField.tsx +339 -0
  96. package/src/components/forms/fields/TableField.tsx +275 -0
  97. package/src/components/forms/fields/TextField.tsx +81 -0
  98. package/src/components/images/ApiImage.tsx +35 -0
  99. package/src/components/images/Thumbnail.tsx +52 -0
  100. package/src/components/importer/ImportDataSelector.tsx +433 -0
  101. package/src/components/importer/ImporterColumnSelector.tsx +244 -0
  102. package/src/components/importer/ImporterDrawer.tsx +173 -0
  103. package/src/components/importer/ImporterImportProgress.tsx +45 -0
  104. package/src/components/items/ActionDropdown.tsx +290 -0
  105. package/src/components/items/ApiIcon.css.ts +13 -0
  106. package/src/components/items/ApiIcon.tsx +32 -0
  107. package/src/components/items/AttachmentLink.tsx +79 -0
  108. package/src/components/items/ColorToggle.tsx +34 -0
  109. package/src/components/items/DashboardItem.tsx +33 -0
  110. package/src/components/items/DocInfo.tsx +20 -0
  111. package/src/components/items/DocTooltip.tsx +98 -0
  112. package/src/components/items/ErrorItem.tsx +17 -0
  113. package/src/components/items/Expand.tsx +14 -0
  114. package/src/components/items/GettingStartedCarousel.css.ts +30 -0
  115. package/src/components/items/GettingStartedCarousel.tsx +49 -0
  116. package/src/components/items/InfoItem.tsx +64 -0
  117. package/src/components/items/InvenTreeLogo.tsx +24 -0
  118. package/src/components/items/LanguageSelect.tsx +43 -0
  119. package/src/components/items/LanguageToggle.tsx +37 -0
  120. package/src/components/items/MenuLinks.tsx +113 -0
  121. package/src/components/items/OnlyStaff.tsx +10 -0
  122. package/src/components/items/ProgressBar.tsx +45 -0
  123. package/src/components/items/StylishText.tsx +59 -0
  124. package/src/components/items/TitleWithDoc.tsx +26 -0
  125. package/src/components/items/UnavailableIndicator.tsx +5 -0
  126. package/src/components/items/inventree.svg +1 -0
  127. package/src/components/modals/AboutInvenTreeModal.tsx +203 -0
  128. package/src/components/modals/LicenseModal.tsx +116 -0
  129. package/src/components/modals/QrModal.tsx +21 -0
  130. package/src/components/modals/ServerInfoModal.tsx +136 -0
  131. package/src/components/nav/Alerts.tsx +130 -0
  132. package/src/components/nav/BreadcrumbList.tsx +84 -0
  133. package/src/components/nav/DetailDrawer.css.ts +6 -0
  134. package/src/components/nav/DetailDrawer.tsx +105 -0
  135. package/src/components/nav/Footer.tsx +11 -0
  136. package/src/components/nav/Header.tsx +226 -0
  137. package/src/components/nav/InstanceDetail.tsx +46 -0
  138. package/src/components/nav/Layout.tsx +85 -0
  139. package/src/components/nav/MainMenu.tsx +101 -0
  140. package/src/components/nav/NavHoverMenu.tsx +15 -0
  141. package/src/components/nav/NavigationDrawer.tsx +230 -0
  142. package/src/components/nav/NavigationTree.tsx +210 -0
  143. package/src/components/nav/NotificationDrawer.tsx +231 -0
  144. package/src/components/nav/PageDetail.tsx +171 -0
  145. package/src/components/nav/PageTitle.tsx +53 -0
  146. package/src/components/nav/SearchDrawer.tsx +598 -0
  147. package/src/components/nav/SettingsHeader.tsx +50 -0
  148. package/src/components/panels/AttachmentPanel.tsx +27 -0
  149. package/src/components/panels/NotesPanel.tsx +36 -0
  150. package/src/components/panels/Panel.tsx +15 -0
  151. package/src/components/panels/PanelGroup.css.ts +10 -0
  152. package/src/components/panels/PanelGroup.tsx +292 -0
  153. package/src/components/plugins/LocateItemButton.tsx +94 -0
  154. package/src/components/plugins/PluginContext.tsx +67 -0
  155. package/src/components/plugins/PluginDrawer.tsx +156 -0
  156. package/src/components/plugins/PluginInterface.tsx +34 -0
  157. package/src/components/plugins/PluginPanel.tsx +37 -0
  158. package/src/components/plugins/PluginSettingsPanel.tsx +34 -0
  159. package/src/components/plugins/PluginSource.tsx +48 -0
  160. package/src/components/plugins/PluginUIFeature.tsx +174 -0
  161. package/src/components/plugins/PluginUIFeatureTypes.ts +78 -0
  162. package/src/components/plugins/RemoteComponent.tsx +137 -0
  163. package/src/components/render/Build.tsx +54 -0
  164. package/src/components/render/Company.tsx +114 -0
  165. package/src/components/render/Generic.tsx +49 -0
  166. package/src/components/render/Instance.tsx +240 -0
  167. package/src/components/render/InstanceFromUrl.tsx +33 -0
  168. package/src/components/render/ModelType.tsx +293 -0
  169. package/src/components/render/Order.tsx +124 -0
  170. package/src/components/render/Part.tsx +109 -0
  171. package/src/components/render/Plugin.tsx +21 -0
  172. package/src/components/render/Report.tsx +29 -0
  173. package/src/components/render/StatusRenderer.tsx +178 -0
  174. package/src/components/render/Stock.tsx +84 -0
  175. package/src/components/render/User.tsx +42 -0
  176. package/src/components/settings/FactCollection.tsx +31 -0
  177. package/src/components/settings/FactItem.tsx +17 -0
  178. package/src/components/settings/SettingItem.tsx +176 -0
  179. package/src/components/settings/SettingList.tsx +217 -0
  180. package/src/components/wizards/OrderPartsWizard.tsx +473 -0
  181. package/src/components/wizards/WizardDrawer.tsx +188 -0
  182. package/src/contexts/ApiContext.tsx +31 -0
  183. package/src/contexts/LanguageContext.tsx +155 -0
  184. package/src/contexts/ThemeContext.tsx +58 -0
  185. package/src/contexts/colorSchema.tsx +67 -0
  186. package/src/defaults/actions.tsx +87 -0
  187. package/src/defaults/backendMappings.tsx +32 -0
  188. package/src/defaults/defaultHostList.tsx +4 -0
  189. package/src/defaults/defaults.tsx +38 -0
  190. package/src/defaults/formatters.tsx +176 -0
  191. package/src/defaults/links.tsx +193 -0
  192. package/src/defaults/templates.tsx +53 -0
  193. package/src/forms/BomForms.tsx +26 -0
  194. package/src/forms/BuildForms.tsx +615 -0
  195. package/src/forms/CommonForms.tsx +89 -0
  196. package/src/forms/CompanyForms.tsx +133 -0
  197. package/src/forms/ImporterForms.tsx +20 -0
  198. package/src/forms/PartForms.tsx +281 -0
  199. package/src/forms/PurchaseOrderForms.tsx +779 -0
  200. package/src/forms/ReturnOrderForms.tsx +263 -0
  201. package/src/forms/SalesOrderForms.tsx +408 -0
  202. package/src/forms/StockForms.tsx +1296 -0
  203. package/src/forms/selectionListFields.tsx +120 -0
  204. package/src/functions/api.tsx +61 -0
  205. package/src/functions/auth.tsx +574 -0
  206. package/src/functions/conversion.tsx +42 -0
  207. package/src/functions/events.tsx +6 -0
  208. package/src/functions/forms.tsx +173 -0
  209. package/src/functions/icons.tsx +294 -0
  210. package/src/functions/loading.tsx +29 -0
  211. package/src/functions/navigation.tsx +20 -0
  212. package/src/functions/notifications.tsx +101 -0
  213. package/src/functions/tables.tsx +26 -0
  214. package/src/functions/uid.tsx +15 -0
  215. package/src/functions/urls.tsx +58 -0
  216. package/src/hooks/UseCalendar.tsx +178 -0
  217. package/src/hooks/UseDashboardItems.tsx +118 -0
  218. package/src/hooks/UseDataExport.tsx +125 -0
  219. package/src/hooks/UseDataOutput.tsx +109 -0
  220. package/src/hooks/UseFilter.tsx +67 -0
  221. package/src/hooks/UseFilterSet.tsx +24 -0
  222. package/src/hooks/UseForm.tsx +161 -0
  223. package/src/hooks/UseGenerator.tsx +92 -0
  224. package/src/hooks/UseImportSession.tsx +139 -0
  225. package/src/hooks/UseInstance.tsx +137 -0
  226. package/src/hooks/UseInstanceName.tsx +14 -0
  227. package/src/hooks/UseModal.tsx +38 -0
  228. package/src/hooks/UsePlaceholder.tsx +66 -0
  229. package/src/hooks/UsePluginPanels.tsx +123 -0
  230. package/src/hooks/UsePluginUIFeature.tsx +95 -0
  231. package/src/hooks/UsePlugins.tsx +45 -0
  232. package/src/hooks/UseSelectedRows.tsx +37 -0
  233. package/src/hooks/UseStatusCodes.tsx +50 -0
  234. package/src/hooks/UseTable.tsx +145 -0
  235. package/src/hooks/UseWizard.tsx +133 -0
  236. package/src/locales/ar/messages.d.ts +4 -0
  237. package/src/locales/ar/messages.po +10695 -0
  238. package/src/locales/ar/messages.ts +1 -0
  239. package/src/locales/bg/messages.d.ts +4 -0
  240. package/src/locales/bg/messages.po +10695 -0
  241. package/src/locales/bg/messages.ts +1 -0
  242. package/src/locales/cs/messages.d.ts +4 -0
  243. package/src/locales/cs/messages.po +10695 -0
  244. package/src/locales/cs/messages.ts +1 -0
  245. package/src/locales/da/messages.d.ts +4 -0
  246. package/src/locales/da/messages.po +10695 -0
  247. package/src/locales/da/messages.ts +1 -0
  248. package/src/locales/de/messages.d.ts +4 -0
  249. package/src/locales/de/messages.po +10695 -0
  250. package/src/locales/de/messages.ts +1 -0
  251. package/src/locales/el/messages.d.ts +4 -0
  252. package/src/locales/el/messages.po +10695 -0
  253. package/src/locales/el/messages.ts +1 -0
  254. package/src/locales/en/messages.d.ts +4 -0
  255. package/src/locales/en/messages.po +10689 -0
  256. package/src/locales/en/messages.ts +1 -0
  257. package/src/locales/es/messages.d.ts +4 -0
  258. package/src/locales/es/messages.po +10695 -0
  259. package/src/locales/es/messages.ts +1 -0
  260. package/src/locales/es_MX/messages.d.ts +4 -0
  261. package/src/locales/es_MX/messages.po +10695 -0
  262. package/src/locales/es_MX/messages.ts +1 -0
  263. package/src/locales/et/messages.d.ts +4 -0
  264. package/src/locales/et/messages.po +10695 -0
  265. package/src/locales/et/messages.ts +1 -0
  266. package/src/locales/fa/messages.d.ts +4 -0
  267. package/src/locales/fa/messages.po +10695 -0
  268. package/src/locales/fa/messages.ts +1 -0
  269. package/src/locales/fi/messages.d.ts +4 -0
  270. package/src/locales/fi/messages.po +10695 -0
  271. package/src/locales/fi/messages.ts +1 -0
  272. package/src/locales/fr/messages.d.ts +4 -0
  273. package/src/locales/fr/messages.po +10695 -0
  274. package/src/locales/fr/messages.ts +1 -0
  275. package/src/locales/he/messages.d.ts +4 -0
  276. package/src/locales/he/messages.po +10695 -0
  277. package/src/locales/he/messages.ts +1 -0
  278. package/src/locales/hi/messages.d.ts +4 -0
  279. package/src/locales/hi/messages.po +10695 -0
  280. package/src/locales/hi/messages.ts +1 -0
  281. package/src/locales/hu/messages.d.ts +4 -0
  282. package/src/locales/hu/messages.po +10695 -0
  283. package/src/locales/hu/messages.ts +1 -0
  284. package/src/locales/id/messages.po +10695 -0
  285. package/src/locales/it/messages.d.ts +4 -0
  286. package/src/locales/it/messages.po +10695 -0
  287. package/src/locales/it/messages.ts +1 -0
  288. package/src/locales/ja/messages.d.ts +4 -0
  289. package/src/locales/ja/messages.po +10695 -0
  290. package/src/locales/ja/messages.ts +1 -0
  291. package/src/locales/ko/messages.d.ts +4 -0
  292. package/src/locales/ko/messages.po +10695 -0
  293. package/src/locales/ko/messages.ts +1 -0
  294. package/src/locales/lt/messages.d.ts +4 -0
  295. package/src/locales/lt/messages.po +10695 -0
  296. package/src/locales/lt/messages.ts +1 -0
  297. package/src/locales/lv/messages.d.ts +4 -0
  298. package/src/locales/lv/messages.po +10695 -0
  299. package/src/locales/lv/messages.ts +1 -0
  300. package/src/locales/nl/messages.d.ts +4 -0
  301. package/src/locales/nl/messages.po +10695 -0
  302. package/src/locales/nl/messages.ts +1 -0
  303. package/src/locales/no/messages.d.ts +4 -0
  304. package/src/locales/no/messages.po +10695 -0
  305. package/src/locales/no/messages.ts +1 -0
  306. package/src/locales/pl/messages.d.ts +4 -0
  307. package/src/locales/pl/messages.po +10695 -0
  308. package/src/locales/pl/messages.ts +1 -0
  309. package/src/locales/pseudo-LOCALE/messages.d.ts +4 -0
  310. package/src/locales/pseudo-LOCALE/messages.po +8003 -0
  311. package/src/locales/pseudo-LOCALE/messages.ts +1 -0
  312. package/src/locales/pt/messages.d.ts +4 -0
  313. package/src/locales/pt/messages.po +10696 -0
  314. package/src/locales/pt/messages.ts +1 -0
  315. package/src/locales/pt_BR/messages.d.ts +4 -0
  316. package/src/locales/pt_BR/messages.po +10695 -0
  317. package/src/locales/pt_BR/messages.ts +1 -0
  318. package/src/locales/ro/messages.po +10695 -0
  319. package/src/locales/ro/messages.ts +1 -0
  320. package/src/locales/ru/messages.d.ts +4 -0
  321. package/src/locales/ru/messages.po +10695 -0
  322. package/src/locales/ru/messages.ts +1 -0
  323. package/src/locales/sk/messages.d.ts +4 -0
  324. package/src/locales/sk/messages.po +10695 -0
  325. package/src/locales/sk/messages.ts +1 -0
  326. package/src/locales/sl/messages.d.ts +4 -0
  327. package/src/locales/sl/messages.po +10695 -0
  328. package/src/locales/sl/messages.ts +1 -0
  329. package/src/locales/sr/messages.d.ts +4 -0
  330. package/src/locales/sr/messages.po +10695 -0
  331. package/src/locales/sr/messages.ts +1 -0
  332. package/src/locales/sv/messages.d.ts +4 -0
  333. package/src/locales/sv/messages.po +10695 -0
  334. package/src/locales/sv/messages.ts +1 -0
  335. package/src/locales/th/messages.d.ts +4 -0
  336. package/src/locales/th/messages.po +10695 -0
  337. package/src/locales/th/messages.ts +1 -0
  338. package/src/locales/tr/messages.d.ts +4 -0
  339. package/src/locales/tr/messages.po +10695 -0
  340. package/src/locales/tr/messages.ts +1 -0
  341. package/src/locales/uk/messages.d.ts +3 -0
  342. package/src/locales/uk/messages.po +10695 -0
  343. package/src/locales/uk/messages.ts +1 -0
  344. package/src/locales/vi/messages.d.ts +4 -0
  345. package/src/locales/vi/messages.po +10695 -0
  346. package/src/locales/vi/messages.ts +1 -0
  347. package/src/locales/zh_Hans/messages.d.ts +4 -0
  348. package/src/locales/zh_Hans/messages.po +10695 -0
  349. package/src/locales/zh_Hans/messages.ts +1 -0
  350. package/src/locales/zh_Hant/messages.d.ts +4 -0
  351. package/src/locales/zh_Hant/messages.po +10695 -0
  352. package/src/locales/zh_Hant/messages.ts +1 -0
  353. package/src/main.css.ts +148 -0
  354. package/src/main.tsx +123 -0
  355. package/src/pages/Auth/ChangePassword.tsx +84 -0
  356. package/src/pages/Auth/Layout.tsx +74 -0
  357. package/src/pages/Auth/LoggedIn.tsx +21 -0
  358. package/src/pages/Auth/Login.tsx +133 -0
  359. package/src/pages/Auth/Logout.tsx +16 -0
  360. package/src/pages/Auth/MFA.tsx +36 -0
  361. package/src/pages/Auth/MFASetup.tsx +38 -0
  362. package/src/pages/Auth/Register.tsx +28 -0
  363. package/src/pages/Auth/Reset.tsx +30 -0
  364. package/src/pages/Auth/ResetPassword.tsx +48 -0
  365. package/src/pages/Auth/VerifyEmail.tsx +34 -0
  366. package/src/pages/ErrorPage.tsx +26 -0
  367. package/src/pages/Index/Home.tsx +12 -0
  368. package/src/pages/Index/Scan.tsx +258 -0
  369. package/src/pages/Index/Settings/AccountSettings/AccountDetailPanel.tsx +162 -0
  370. package/src/pages/Index/Settings/AccountSettings/QrRegistrationForm.tsx +38 -0
  371. package/src/pages/Index/Settings/AccountSettings/SecurityContent.tsx +713 -0
  372. package/src/pages/Index/Settings/AccountSettings/UserPanel.tsx +24 -0
  373. package/src/pages/Index/Settings/AccountSettings/UserThemePanel.tsx +207 -0
  374. package/src/pages/Index/Settings/AccountSettings/useConfirm.tsx +117 -0
  375. package/src/pages/Index/Settings/AdminCenter/CurrencyManagementPanel.tsx +111 -0
  376. package/src/pages/Index/Settings/AdminCenter/Index.tsx +251 -0
  377. package/src/pages/Index/Settings/AdminCenter/LabelTemplatePanel.tsx +23 -0
  378. package/src/pages/Index/Settings/AdminCenter/MachineManagementPanel.tsx +110 -0
  379. package/src/pages/Index/Settings/AdminCenter/PartParameterPanel.tsx +29 -0
  380. package/src/pages/Index/Settings/AdminCenter/PluginManagementPanel.tsx +84 -0
  381. package/src/pages/Index/Settings/AdminCenter/ReportTemplatePanel.tsx +38 -0
  382. package/src/pages/Index/Settings/AdminCenter/StocktakePanel.tsx +31 -0
  383. package/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx +73 -0
  384. package/src/pages/Index/Settings/AdminCenter/UnitManagementPanel.tsx +74 -0
  385. package/src/pages/Index/Settings/AdminCenter/UserManagementPanel.tsx +49 -0
  386. package/src/pages/Index/Settings/SystemSettings.tsx +339 -0
  387. package/src/pages/Index/Settings/UserSettings.tsx +143 -0
  388. package/src/pages/Notifications.tsx +134 -0
  389. package/src/pages/build/BuildDetail.tsx +579 -0
  390. package/src/pages/build/BuildIndex.tsx +100 -0
  391. package/src/pages/company/CompanyDetail.tsx +352 -0
  392. package/src/pages/company/CustomerDetail.tsx +13 -0
  393. package/src/pages/company/ManufacturerDetail.tsx +13 -0
  394. package/src/pages/company/ManufacturerPartDetail.tsx +307 -0
  395. package/src/pages/company/SupplierDetail.tsx +13 -0
  396. package/src/pages/company/SupplierPartDetail.tsx +433 -0
  397. package/src/pages/core/CoreIndex.tsx +50 -0
  398. package/src/pages/core/GroupDetail.tsx +97 -0
  399. package/src/pages/core/UserDetail.tsx +193 -0
  400. package/src/pages/part/CategoryDetail.tsx +369 -0
  401. package/src/pages/part/PartAllocationPanel.tsx +40 -0
  402. package/src/pages/part/PartDetail.tsx +1071 -0
  403. package/src/pages/part/PartPricingPanel.tsx +155 -0
  404. package/src/pages/part/PartSchedulingDetail.tsx +315 -0
  405. package/src/pages/part/PartStocktakeDetail.tsx +285 -0
  406. package/src/pages/part/PartSupplierDetail.tsx +31 -0
  407. package/src/pages/part/pricing/BomPricingPanel.tsx +269 -0
  408. package/src/pages/part/pricing/PriceBreakPanel.tsx +182 -0
  409. package/src/pages/part/pricing/PricingOverviewPanel.tsx +338 -0
  410. package/src/pages/part/pricing/PricingPanel.tsx +82 -0
  411. package/src/pages/part/pricing/PurchaseHistoryPanel.tsx +134 -0
  412. package/src/pages/part/pricing/SaleHistoryPanel.tsx +95 -0
  413. package/src/pages/part/pricing/SupplierPricingPanel.tsx +80 -0
  414. package/src/pages/part/pricing/VariantPricingPanel.tsx +112 -0
  415. package/src/pages/purchasing/PurchaseOrderDetail.tsx +547 -0
  416. package/src/pages/purchasing/PurchasingIndex.tsx +131 -0
  417. package/src/pages/sales/ReturnOrderDetail.tsx +529 -0
  418. package/src/pages/sales/SalesIndex.tsx +148 -0
  419. package/src/pages/sales/SalesOrderDetail.tsx +593 -0
  420. package/src/pages/sales/SalesOrderShipmentDetail.tsx +385 -0
  421. package/src/pages/stock/LocationDetail.tsx +413 -0
  422. package/src/pages/stock/StockDetail.tsx +951 -0
  423. package/src/router.tsx +213 -0
  424. package/src/states/ApiState.tsx +85 -0
  425. package/src/states/IconState.tsx +94 -0
  426. package/src/states/LocalState.tsx +181 -0
  427. package/src/states/SettingsState.tsx +206 -0
  428. package/src/states/StatusState.tsx +55 -0
  429. package/src/states/UserState.tsx +202 -0
  430. package/src/states/states.tsx +69 -0
  431. package/src/tables/Column.tsx +29 -0
  432. package/src/tables/ColumnRenderers.tsx +320 -0
  433. package/src/tables/ColumnSelect.tsx +39 -0
  434. package/src/tables/Filter.tsx +297 -0
  435. package/src/tables/FilterSelectDrawer.tsx +358 -0
  436. package/src/tables/InvenTreeTable.tsx +750 -0
  437. package/src/tables/InvenTreeTableHeader.tsx +257 -0
  438. package/src/tables/RowActions.tsx +176 -0
  439. package/src/tables/RowExpansionIcon.tsx +16 -0
  440. package/src/tables/Search.tsx +42 -0
  441. package/src/tables/TableHoverCard.tsx +91 -0
  442. package/src/tables/bom/BomTable.tsx +590 -0
  443. package/src/tables/bom/UsedInTable.tsx +114 -0
  444. package/src/tables/build/BuildAllocatedStockTable.tsx +233 -0
  445. package/src/tables/build/BuildLineTable.tsx +800 -0
  446. package/src/tables/build/BuildOrderTable.tsx +226 -0
  447. package/src/tables/build/BuildOrderTestTable.tsx +265 -0
  448. package/src/tables/build/BuildOutputTable.tsx +599 -0
  449. package/src/tables/company/AddressTable.tsx +211 -0
  450. package/src/tables/company/CompanyTable.tsx +176 -0
  451. package/src/tables/company/ContactTable.tsx +182 -0
  452. package/src/tables/core/UserTable.tsx +88 -0
  453. package/src/tables/general/AttachmentTable.tsx +404 -0
  454. package/src/tables/general/BarcodeScanTable.tsx +124 -0
  455. package/src/tables/general/ExtraLineItemTable.tsx +174 -0
  456. package/src/tables/machine/MachineListTable.tsx +634 -0
  457. package/src/tables/machine/MachineTypeTable.tsx +395 -0
  458. package/src/tables/notifications/NotificationTable.tsx +60 -0
  459. package/src/tables/part/ParametricPartTable.tsx +297 -0
  460. package/src/tables/part/PartBuildAllocationsTable.tsx +128 -0
  461. package/src/tables/part/PartCategoryTable.tsx +208 -0
  462. package/src/tables/part/PartCategoryTemplateTable.tsx +157 -0
  463. package/src/tables/part/PartParameterTable.tsx +226 -0
  464. package/src/tables/part/PartParameterTemplateTable.tsx +168 -0
  465. package/src/tables/part/PartPurchaseOrdersTable.tsx +163 -0
  466. package/src/tables/part/PartSalesAllocationsTable.tsx +130 -0
  467. package/src/tables/part/PartTable.tsx +423 -0
  468. package/src/tables/part/PartTestTemplateTable.tsx +290 -0
  469. package/src/tables/part/PartThumbTable.tsx +230 -0
  470. package/src/tables/part/PartVariantTable.tsx +52 -0
  471. package/src/tables/part/RelatedPartTable.tsx +182 -0
  472. package/src/tables/part/SelectionListTable.tsx +134 -0
  473. package/src/tables/plugin/PluginErrorTable.tsx +58 -0
  474. package/src/tables/plugin/PluginListTable.tsx +440 -0
  475. package/src/tables/purchasing/ManufacturerPartParameterTable.tsx +136 -0
  476. package/src/tables/purchasing/ManufacturerPartTable.tsx +158 -0
  477. package/src/tables/purchasing/PurchaseOrderLineItemTable.tsx +424 -0
  478. package/src/tables/purchasing/PurchaseOrderTable.tsx +193 -0
  479. package/src/tables/purchasing/SupplierPartTable.tsx +281 -0
  480. package/src/tables/purchasing/SupplierPriceBreakTable.tsx +222 -0
  481. package/src/tables/sales/ReturnOrderLineItemTable.tsx +271 -0
  482. package/src/tables/sales/ReturnOrderTable.tsx +201 -0
  483. package/src/tables/sales/SalesOrderAllocationTable.tsx +330 -0
  484. package/src/tables/sales/SalesOrderLineItemTable.tsx +508 -0
  485. package/src/tables/sales/SalesOrderShipmentTable.tsx +225 -0
  486. package/src/tables/sales/SalesOrderTable.tsx +212 -0
  487. package/src/tables/settings/ApiTokenTable.tsx +203 -0
  488. package/src/tables/settings/BarcodeScanHistoryTable.tsx +281 -0
  489. package/src/tables/settings/CustomStateTable.tsx +226 -0
  490. package/src/tables/settings/CustomUnitsTable.tsx +125 -0
  491. package/src/tables/settings/ErrorTable.tsx +170 -0
  492. package/src/tables/settings/ExportSessionTable.tsx +60 -0
  493. package/src/tables/settings/FailedTasksTable.tsx +103 -0
  494. package/src/tables/settings/GroupTable.tsx +240 -0
  495. package/src/tables/settings/ImportSessionTable.tsx +175 -0
  496. package/src/tables/settings/PendingTasksTable.tsx +63 -0
  497. package/src/tables/settings/ProjectCodeTable.tsx +115 -0
  498. package/src/tables/settings/ScheduledTasksTable.tsx +62 -0
  499. package/src/tables/settings/StocktakeReportTable.tsx +111 -0
  500. package/src/tables/settings/TemplateTable.tsx +404 -0
  501. package/src/tables/settings/UserTable.tsx +329 -0
  502. package/src/tables/stock/InstalledItemsTable.tsx +146 -0
  503. package/src/tables/stock/LocationTypesTable.tsx +132 -0
  504. package/src/tables/stock/StockItemTable.tsx +707 -0
  505. package/src/tables/stock/StockItemTestResultTable.tsx +487 -0
  506. package/src/tables/stock/StockLocationTable.tsx +208 -0
  507. package/src/tables/stock/StockTrackingTable.tsx +244 -0
  508. package/src/theme.ts +5 -0
  509. package/src/views/DesktopAppView.tsx +28 -0
  510. package/src/views/MainView.tsx +38 -0
  511. package/src/views/MobileAppView.tsx +43 -0
  512. package/tests/baseFixtures.ts +93 -0
  513. package/tests/defaults.ts +18 -0
  514. package/tests/helpers.ts +122 -0
  515. package/tests/login.ts +97 -0
  516. package/tests/pages/pui_build.spec.ts +373 -0
  517. package/tests/pages/pui_company.spec.ts +40 -0
  518. package/tests/pages/pui_core.spec.ts +26 -0
  519. package/tests/pages/pui_dashboard.spec.ts +64 -0
  520. package/tests/pages/pui_part.spec.ts +413 -0
  521. package/tests/pages/pui_purchase_order.spec.ts +388 -0
  522. package/tests/pages/pui_sales_order.spec.ts +224 -0
  523. package/tests/pages/pui_scan.spec.ts +114 -0
  524. package/tests/pages/pui_stock.spec.ts +259 -0
  525. package/tests/pui_exporting.spec.ts +124 -0
  526. package/tests/pui_forms.spec.ts +131 -0
  527. package/tests/pui_general.spec.ts +60 -0
  528. package/tests/pui_login.spec.ts +74 -0
  529. package/tests/pui_modals.spec.ts +144 -0
  530. package/tests/pui_plugins.spec.ts +216 -0
  531. package/tests/pui_printing.spec.ts +149 -0
  532. package/tests/pui_settings.spec.ts +285 -0
  533. package/tests/pui_tables.spec.ts +65 -0
  534. package/tests/settings/selectionList.spec.ts +103 -0
  535. package/tests/settings.ts +54 -0
  536. package/tsconfig.json +25 -0
  537. package/tsconfig.lib.json +13 -0
  538. package/tsconfig.node.json +11 -0
  539. package/vite-env.d.ts +11 -0
  540. package/vite.config.ts +98 -0
  541. package/vite.lib.config.ts +50 -0
@@ -0,0 +1,951 @@
1
+ import { t } from '@lingui/core/macro';
2
+ import { Accordion, Alert, Grid, Skeleton, Stack } from '@mantine/core';
3
+ import {
4
+ IconBookmark,
5
+ IconBoxPadding,
6
+ IconChecklist,
7
+ IconHistory,
8
+ IconInfoCircle,
9
+ IconPackages,
10
+ IconShoppingCart,
11
+ IconSitemap
12
+ } from '@tabler/icons-react';
13
+ import { useQuery } from '@tanstack/react-query';
14
+ import { type ReactNode, useMemo, useState } from 'react';
15
+ import { useNavigate, useParams } from 'react-router-dom';
16
+
17
+ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
18
+ import { ModelType } from '@lib/enums/ModelType';
19
+ import { UserRoles } from '@lib/enums/Roles';
20
+ import { apiUrl } from '@lib/functions/Api';
21
+ import AdminButton from '../../components/buttons/AdminButton';
22
+ import { PrintingActions } from '../../components/buttons/PrintingActions';
23
+ import {
24
+ type DetailsField,
25
+ DetailsTable
26
+ } from '../../components/details/Details';
27
+ import DetailsBadge from '../../components/details/DetailsBadge';
28
+ import { DetailsImage } from '../../components/details/DetailsImage';
29
+ import { ItemDetailsGrid } from '../../components/details/ItemDetails';
30
+ import {
31
+ ActionDropdown,
32
+ BarcodeActionDropdown,
33
+ DeleteItemAction,
34
+ DuplicateItemAction,
35
+ EditItemAction,
36
+ OptionsActionDropdown
37
+ } from '../../components/items/ActionDropdown';
38
+ import { StylishText } from '../../components/items/StylishText';
39
+ import InstanceDetail from '../../components/nav/InstanceDetail';
40
+ import NavigationTree from '../../components/nav/NavigationTree';
41
+ import { PageDetail } from '../../components/nav/PageDetail';
42
+ import AttachmentPanel from '../../components/panels/AttachmentPanel';
43
+ import NotesPanel from '../../components/panels/NotesPanel';
44
+ import type { PanelType } from '../../components/panels/Panel';
45
+ import { PanelGroup } from '../../components/panels/PanelGroup';
46
+ import LocateItemButton from '../../components/plugins/LocateItemButton';
47
+ import { StatusRenderer } from '../../components/render/StatusRenderer';
48
+ import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
49
+ import { useApi } from '../../contexts/ApiContext';
50
+ import { formatCurrency } from '../../defaults/formatters';
51
+ import {
52
+ type StockOperationProps,
53
+ useAddStockItem,
54
+ useAssignStockItem,
55
+ useCountStockItem,
56
+ useRemoveStockItem,
57
+ useStockFields,
58
+ useStockItemSerializeFields,
59
+ useTransferStockItem
60
+ } from '../../forms/StockForms';
61
+ import { InvenTreeIcon } from '../../functions/icons';
62
+ import { getDetailUrl } from '../../functions/urls';
63
+ import {
64
+ useCreateApiFormModal,
65
+ useDeleteApiFormModal,
66
+ useEditApiFormModal
67
+ } from '../../hooks/UseForm';
68
+ import { useInstance } from '../../hooks/UseInstance';
69
+ import { useGlobalSettingsState } from '../../states/SettingsState';
70
+ import { useUserState } from '../../states/UserState';
71
+ import BuildAllocatedStockTable from '../../tables/build/BuildAllocatedStockTable';
72
+ import SalesOrderAllocationTable from '../../tables/sales/SalesOrderAllocationTable';
73
+ import InstalledItemsTable from '../../tables/stock/InstalledItemsTable';
74
+ import { StockItemTable } from '../../tables/stock/StockItemTable';
75
+ import StockItemTestResultTable from '../../tables/stock/StockItemTestResultTable';
76
+ import { StockTrackingTable } from '../../tables/stock/StockTrackingTable';
77
+
78
+ export default function StockDetail() {
79
+ const { id } = useParams();
80
+
81
+ const api = useApi();
82
+ const user = useUserState();
83
+
84
+ const globalSettings = useGlobalSettingsState();
85
+
86
+ const enableExpiry = useMemo(
87
+ () => globalSettings.isSet('STOCK_ENABLE_EXPIRY'),
88
+ [globalSettings]
89
+ );
90
+
91
+ const navigate = useNavigate();
92
+
93
+ const [treeOpen, setTreeOpen] = useState(false);
94
+
95
+ const {
96
+ instance: stockitem,
97
+ refreshInstance,
98
+ refreshInstancePromise,
99
+ instanceQuery,
100
+ requestStatus
101
+ } = useInstance({
102
+ endpoint: ApiEndpoints.stock_item_list,
103
+ pk: id,
104
+ params: {
105
+ part_detail: true,
106
+ location_detail: true,
107
+ path_detail: true
108
+ }
109
+ });
110
+
111
+ const detailsPanel = useMemo(() => {
112
+ const data = { ...stockitem };
113
+ const part = stockitem?.part_detail ?? {};
114
+
115
+ data.available_stock = Math.max(0, data.quantity - data.allocated);
116
+
117
+ if (instanceQuery.isFetching) {
118
+ return <Skeleton />;
119
+ }
120
+
121
+ // Top left - core part information
122
+ const tl: DetailsField[] = [
123
+ {
124
+ name: 'part',
125
+ label: t`Base Part`,
126
+ type: 'link',
127
+ model: ModelType.part
128
+ },
129
+ {
130
+ name: 'part_detail.IPN',
131
+ label: t`IPN`,
132
+ type: 'text',
133
+ copy: true,
134
+ icon: 'part',
135
+ hidden: !part.IPN
136
+ },
137
+ {
138
+ name: 'status',
139
+ type: 'status',
140
+ label: t`Status`,
141
+ model: ModelType.stockitem
142
+ },
143
+ {
144
+ name: 'status_custom_key',
145
+ type: 'status',
146
+ label: t`Custom Status`,
147
+ model: ModelType.stockitem,
148
+ icon: 'status',
149
+ hidden:
150
+ !stockitem.status_custom_key ||
151
+ stockitem.status_custom_key == stockitem.status
152
+ },
153
+ {
154
+ type: 'text',
155
+ name: 'tests',
156
+ label: t`Completed Tests`,
157
+ icon: 'progress',
158
+ hidden: !part?.testable
159
+ },
160
+ {
161
+ type: 'text',
162
+ name: 'updated',
163
+ icon: 'calendar',
164
+ label: t`Last Updated`
165
+ },
166
+ {
167
+ type: 'text',
168
+ name: 'stocktake',
169
+ icon: 'calendar',
170
+ label: t`Last Stocktake`,
171
+ hidden: !stockitem.stocktake
172
+ }
173
+ ];
174
+
175
+ // Top right - available stock information
176
+ const tr: DetailsField[] = [
177
+ {
178
+ type: 'text',
179
+ name: 'quantity',
180
+ label: t`Quantity`
181
+ },
182
+ {
183
+ type: 'text',
184
+ name: 'serial',
185
+ label: t`Serial Number`,
186
+ hidden: !stockitem.serial
187
+ },
188
+ {
189
+ type: 'text',
190
+ name: 'available_stock',
191
+ label: t`Available`,
192
+ icon: 'stock'
193
+ },
194
+ {
195
+ type: 'text',
196
+ name: 'allocated',
197
+ label: t`Allocated to Orders`,
198
+ icon: 'tick_off',
199
+ hidden: !stockitem.allocated
200
+ },
201
+ {
202
+ type: 'text',
203
+ name: 'batch',
204
+ label: t`Batch Code`,
205
+ hidden: !stockitem.batch
206
+ }
207
+ ];
208
+
209
+ // Bottom left: location information
210
+ const bl: DetailsField[] = [
211
+ {
212
+ name: 'supplier_part',
213
+ label: t`Supplier Part`,
214
+ type: 'link',
215
+ model_field: 'SKU',
216
+ model: ModelType.supplierpart,
217
+ hidden: !stockitem.supplier_part
218
+ },
219
+ {
220
+ type: 'link',
221
+ name: 'location',
222
+ label: t`Location`,
223
+ model: ModelType.stocklocation,
224
+ hidden: !stockitem.location
225
+ },
226
+ {
227
+ type: 'link',
228
+ name: 'belongs_to',
229
+ label: t`Installed In`,
230
+ model_filters: {
231
+ part_detail: true
232
+ },
233
+ model_formatter: (model: any) => {
234
+ let text = model?.part_detail?.full_name ?? model?.name;
235
+ if (model.serial && model.quantity == 1) {
236
+ text += ` # ${model.serial}`;
237
+ }
238
+
239
+ return text;
240
+ },
241
+ icon: 'stock',
242
+ model: ModelType.stockitem,
243
+ hidden: !stockitem.belongs_to
244
+ },
245
+ {
246
+ type: 'link',
247
+ name: 'parent',
248
+ icon: 'sitemap',
249
+ label: t`Parent Item`,
250
+ model: ModelType.stockitem,
251
+ hidden: !stockitem.parent,
252
+ model_formatter: (model: any) => {
253
+ return t`Parent stock item`;
254
+ }
255
+ },
256
+ {
257
+ type: 'link',
258
+ name: 'consumed_by',
259
+ label: t`Consumed By`,
260
+ model: ModelType.build,
261
+ hidden: !stockitem.consumed_by,
262
+ icon: 'build',
263
+ model_field: 'reference'
264
+ },
265
+ {
266
+ type: 'link',
267
+ name: 'build',
268
+ label: t`Build Order`,
269
+ model: ModelType.build,
270
+ hidden: !stockitem.build,
271
+ model_field: 'reference'
272
+ },
273
+ {
274
+ type: 'link',
275
+ name: 'purchase_order',
276
+ label: t`Purchase Order`,
277
+ model: ModelType.purchaseorder,
278
+ hidden: !stockitem.purchase_order,
279
+ icon: 'purchase_orders',
280
+ model_field: 'reference'
281
+ },
282
+ {
283
+ type: 'link',
284
+ name: 'sales_order',
285
+ label: t`Sales Order`,
286
+ model: ModelType.salesorder,
287
+ hidden: !stockitem.sales_order,
288
+ icon: 'sales_orders',
289
+ model_field: 'reference'
290
+ },
291
+ {
292
+ type: 'link',
293
+ name: 'customer',
294
+ label: t`Customer`,
295
+ model: ModelType.company,
296
+ hidden: !stockitem.customer
297
+ }
298
+ ];
299
+
300
+ // Bottom right - any other information
301
+ const br: DetailsField[] = [
302
+ // Expiry date
303
+ {
304
+ type: 'date',
305
+ name: 'expiry_date',
306
+ label: t`Expiry Date`,
307
+ hidden: !enableExpiry || !stockitem.expiry_date,
308
+ icon: 'calendar'
309
+ },
310
+ // TODO: Ownership
311
+ {
312
+ type: 'text',
313
+ name: 'purchase_price',
314
+ label: t`Unit Price`,
315
+ icon: 'currency',
316
+ hidden: !stockitem.purchase_price,
317
+ value_formatter: () => {
318
+ return formatCurrency(stockitem.purchase_price, {
319
+ currency: stockitem.purchase_price_currency
320
+ });
321
+ }
322
+ },
323
+ {
324
+ type: 'text',
325
+ name: 'stock_value',
326
+ label: t`Stock Value`,
327
+ icon: 'currency',
328
+ hidden:
329
+ !stockitem.purchase_price ||
330
+ stockitem.quantity == 1 ||
331
+ stockitem.quantity == 0,
332
+ value_formatter: () => {
333
+ return formatCurrency(stockitem.purchase_price, {
334
+ currency: stockitem.purchase_price_currency,
335
+ multiplier: stockitem.quantity
336
+ });
337
+ }
338
+ },
339
+ {
340
+ type: 'text',
341
+ name: 'packaging',
342
+ icon: 'part',
343
+ label: t`Packaging`,
344
+ hidden: !stockitem.packaging
345
+ }
346
+ ];
347
+
348
+ return (
349
+ <ItemDetailsGrid>
350
+ <Grid grow>
351
+ <DetailsImage
352
+ appRole={UserRoles.part}
353
+ apiPath={ApiEndpoints.part_list}
354
+ src={
355
+ stockitem.part_detail?.image ?? stockitem?.part_detail?.thumbnail
356
+ }
357
+ pk={stockitem.part}
358
+ />
359
+ <Grid.Col span={{ base: 12, sm: 8 }}>
360
+ <DetailsTable fields={tl} item={data} />
361
+ </Grid.Col>
362
+ </Grid>
363
+ <DetailsTable fields={tr} item={data} />
364
+ <DetailsTable fields={bl} item={data} />
365
+ <DetailsTable fields={br} item={data} />
366
+ </ItemDetailsGrid>
367
+ );
368
+ }, [stockitem, instanceQuery.isFetching, enableExpiry]);
369
+
370
+ const showBuildAllocations: boolean = useMemo(() => {
371
+ // Determine if "build allocations" should be shown for this stock item
372
+ return (
373
+ stockitem?.part_detail?.component && // Must be a "component"
374
+ !stockitem?.sales_order && // Must not be assigned to a sales order
375
+ !stockitem?.belongs_to
376
+ ); // Must not be installed into another item
377
+ }, [stockitem]);
378
+
379
+ const showSalesAllocations: boolean = useMemo(() => {
380
+ return stockitem?.part_detail?.salable;
381
+ }, [stockitem]);
382
+
383
+ // API query to determine if this stock item has trackable BOM items
384
+ const trackedBomItemQuery = useQuery({
385
+ queryKey: ['tracked-bom-item', stockitem.pk, stockitem.part],
386
+ queryFn: () => {
387
+ if (
388
+ !stockitem.pk ||
389
+ !stockitem.part ||
390
+ !stockitem.part_detail?.assembly
391
+ ) {
392
+ return false;
393
+ }
394
+
395
+ return api
396
+ .get(apiUrl(ApiEndpoints.bom_list), {
397
+ params: {
398
+ part: stockitem.part,
399
+ sub_part_trackable: true,
400
+ limit: 1
401
+ }
402
+ })
403
+ .then((response) => {
404
+ if (response.status == 200) {
405
+ return response.data.count > 0;
406
+ } else {
407
+ return null;
408
+ }
409
+ })
410
+ .catch(() => {
411
+ return null;
412
+ });
413
+ }
414
+ });
415
+
416
+ const showInstalledItems: boolean = useMemo(() => {
417
+ if (stockitem?.installed_items) {
418
+ // There are installed items in this stock item
419
+ return true;
420
+ }
421
+
422
+ if (trackedBomItemQuery.data != null) {
423
+ return trackedBomItemQuery.data;
424
+ }
425
+
426
+ // Fall back to whether this is an assembly or not
427
+ return stockitem?.part_detail?.assembly;
428
+ }, [trackedBomItemQuery, stockitem]);
429
+
430
+ const stockPanels: PanelType[] = useMemo(() => {
431
+ return [
432
+ {
433
+ name: 'details',
434
+ label: t`Stock Details`,
435
+ icon: <IconInfoCircle />,
436
+ content: detailsPanel
437
+ },
438
+ {
439
+ name: 'tracking',
440
+ label: t`Stock Tracking`,
441
+ icon: <IconHistory />,
442
+ content: stockitem.pk ? (
443
+ <StockTrackingTable itemId={stockitem.pk} />
444
+ ) : (
445
+ <Skeleton />
446
+ )
447
+ },
448
+ {
449
+ name: 'allocations',
450
+ label: t`Allocations`,
451
+ icon: <IconBookmark />,
452
+ hidden:
453
+ !stockitem.in_stock ||
454
+ (!showSalesAllocations && !showBuildAllocations),
455
+ content: (
456
+ <Accordion
457
+ multiple={true}
458
+ defaultValue={['buildAllocations', 'salesAllocations']}
459
+ >
460
+ {showBuildAllocations && (
461
+ <Accordion.Item value='buildAllocations' key='buildAllocations'>
462
+ <Accordion.Control>
463
+ <StylishText size='lg'>{t`Build Order Allocations`}</StylishText>
464
+ </Accordion.Control>
465
+ <Accordion.Panel>
466
+ <BuildAllocatedStockTable
467
+ stockId={stockitem.pk}
468
+ modelField='build'
469
+ modelTarget={ModelType.build}
470
+ showBuildInfo
471
+ />
472
+ </Accordion.Panel>
473
+ </Accordion.Item>
474
+ )}
475
+ {showSalesAllocations && (
476
+ <Accordion.Item value='salesAllocations' key='salesAllocations'>
477
+ <Accordion.Control>
478
+ <StylishText size='lg'>{t`Sales Order Allocations`}</StylishText>
479
+ </Accordion.Control>
480
+ <Accordion.Panel>
481
+ <SalesOrderAllocationTable
482
+ stockId={stockitem.pk}
483
+ modelField='order'
484
+ modelTarget={ModelType.salesorder}
485
+ showOrderInfo
486
+ />
487
+ </Accordion.Panel>
488
+ </Accordion.Item>
489
+ )}
490
+ </Accordion>
491
+ )
492
+ },
493
+ {
494
+ name: 'testdata',
495
+ label: t`Test Data`,
496
+ icon: <IconChecklist />,
497
+ hidden: !stockitem?.part_detail?.testable,
498
+ content: stockitem?.pk ? (
499
+ <StockItemTestResultTable
500
+ itemId={stockitem.pk}
501
+ partId={stockitem.part}
502
+ />
503
+ ) : (
504
+ <Skeleton />
505
+ )
506
+ },
507
+ {
508
+ name: 'installed_items',
509
+ label: t`Installed Items`,
510
+ icon: <IconBoxPadding />,
511
+ hidden: !showInstalledItems,
512
+ content: <InstalledItemsTable stockItem={stockitem} />
513
+ },
514
+ {
515
+ name: 'child_items',
516
+ label: t`Child Items`,
517
+ icon: <IconSitemap />,
518
+ hidden: (stockitem?.child_items ?? 0) == 0,
519
+ content: stockitem?.pk ? (
520
+ <StockItemTable
521
+ tableName='child-stock'
522
+ params={{ ancestor: stockitem.pk }}
523
+ />
524
+ ) : (
525
+ <Skeleton />
526
+ )
527
+ },
528
+ AttachmentPanel({
529
+ model_type: ModelType.stockitem,
530
+ model_id: stockitem.pk
531
+ }),
532
+ NotesPanel({
533
+ model_type: ModelType.stockitem,
534
+ model_id: stockitem.pk
535
+ })
536
+ ];
537
+ }, [
538
+ showSalesAllocations,
539
+ showBuildAllocations,
540
+ showInstalledItems,
541
+ stockitem,
542
+ id,
543
+ user
544
+ ]);
545
+
546
+ const breadcrumbs = useMemo(
547
+ () => [
548
+ { name: t`Stock`, url: '/stock' },
549
+ ...(stockitem.location_path ?? []).map((l: any) => ({
550
+ name: l.name,
551
+ url: getDetailUrl(ModelType.stocklocation, l.pk)
552
+ }))
553
+ ],
554
+ [stockitem]
555
+ );
556
+
557
+ const editStockItemFields = useStockFields({
558
+ create: false,
559
+ stockItem: stockitem,
560
+ partId: stockitem.part
561
+ });
562
+
563
+ const editStockItem = useEditApiFormModal({
564
+ url: ApiEndpoints.stock_item_list,
565
+ pk: stockitem.pk,
566
+ title: t`Edit Stock Item`,
567
+ fields: editStockItemFields,
568
+ onFormSuccess: refreshInstance
569
+ });
570
+
571
+ const duplicateStockItemFields = useStockFields({ create: true });
572
+
573
+ const duplicateStockItem = useCreateApiFormModal({
574
+ url: ApiEndpoints.stock_item_list,
575
+ title: t`Add Stock Item`,
576
+ fields: duplicateStockItemFields,
577
+ initialData: {
578
+ ...stockitem
579
+ },
580
+ follow: true,
581
+ modelType: ModelType.stockitem
582
+ });
583
+
584
+ const preDeleteContent = useMemo(() => {
585
+ // TODO: Fill this out with information on the stock item.
586
+ // e.g. list of child items which would be deleted, etc
587
+ return undefined;
588
+ }, [stockitem]);
589
+
590
+ const deleteStockItem = useDeleteApiFormModal({
591
+ url: ApiEndpoints.stock_item_list,
592
+ pk: stockitem.pk,
593
+ title: t`Delete Stock Item`,
594
+ preFormContent: preDeleteContent,
595
+ onFormSuccess: () => {
596
+ // Redirect to the part page
597
+ navigate(getDetailUrl(ModelType.part, stockitem.part));
598
+ }
599
+ });
600
+
601
+ const stockActionProps: StockOperationProps = useMemo(() => {
602
+ return {
603
+ items: [stockitem],
604
+ model: ModelType.stockitem,
605
+ refresh: refreshInstance,
606
+ filters: {
607
+ in_stock: true
608
+ }
609
+ };
610
+ }, [stockitem]);
611
+
612
+ const countStockItem = useCountStockItem(stockActionProps);
613
+ const addStockItem = useAddStockItem(stockActionProps);
614
+ const removeStockItem = useRemoveStockItem(stockActionProps);
615
+ const transferStockItem = useTransferStockItem(stockActionProps);
616
+ const assignToCustomer = useAssignStockItem(stockActionProps);
617
+
618
+ const serializeStockFields = useStockItemSerializeFields({
619
+ partId: stockitem.part,
620
+ trackable: stockitem.part_detail?.trackable
621
+ });
622
+
623
+ const serializeStockItem = useCreateApiFormModal({
624
+ url: ApiEndpoints.stock_serialize,
625
+ pk: stockitem.pk,
626
+ title: t`Serialize Stock Item`,
627
+ fields: serializeStockFields,
628
+ initialData: {
629
+ quantity: stockitem.quantity,
630
+ destination: stockitem.location ?? stockitem.part_detail?.default_location
631
+ },
632
+ onFormSuccess: () => {
633
+ const partId = stockitem.part;
634
+ refreshInstancePromise().catch(() => {
635
+ // Part may have been deleted - redirect to the part detail page
636
+ navigate(getDetailUrl(ModelType.part, partId));
637
+ });
638
+ },
639
+ successMessage: t`Stock item serialized`
640
+ });
641
+
642
+ const returnStockItem = useCreateApiFormModal({
643
+ url: ApiEndpoints.stock_return,
644
+ pk: stockitem.pk,
645
+ title: t`Return Stock Item`,
646
+ preFormContent: (
647
+ <Alert color='blue'>
648
+ {t`Return this item into stock. This will remove the customer assignment.`}
649
+ </Alert>
650
+ ),
651
+ fields: {
652
+ location: {},
653
+ status: {},
654
+ notes: {}
655
+ },
656
+ initialData: {
657
+ location: stockitem.location ?? stockitem.part_detail?.default_location,
658
+ status: stockitem.status_custom_key ?? stockitem.status
659
+ },
660
+ successMessage: t`Item returned to stock`,
661
+ onFormSuccess: () => {
662
+ refreshInstance();
663
+ }
664
+ });
665
+
666
+ const orderPartsWizard = OrderPartsWizard({
667
+ parts: stockitem.part_detail ? [stockitem.part_detail] : []
668
+ });
669
+
670
+ const stockActions = useMemo(() => {
671
+ // Can this stock item be transferred to a different location?
672
+ const canTransfer =
673
+ user.hasChangeRole(UserRoles.stock) &&
674
+ !stockitem.sales_order &&
675
+ !stockitem.belongs_to &&
676
+ !stockitem.customer &&
677
+ !stockitem.consumed_by;
678
+
679
+ const isBuilding = stockitem.is_building;
680
+
681
+ const serial = stockitem.serial;
682
+ const serialized =
683
+ serial != null &&
684
+ serial != undefined &&
685
+ serial != '' &&
686
+ stockitem.quantity == 1;
687
+
688
+ return [
689
+ <AdminButton model={ModelType.stockitem} id={stockitem.pk} />,
690
+ <LocateItemButton stockId={stockitem.pk} />,
691
+ <BarcodeActionDropdown
692
+ model={ModelType.stockitem}
693
+ pk={stockitem.pk}
694
+ hash={stockitem?.barcode_hash}
695
+ perm={user.hasChangeRole(UserRoles.stock)}
696
+ />,
697
+ <PrintingActions
698
+ modelType={ModelType.stockitem}
699
+ items={[stockitem.pk]}
700
+ enableReports
701
+ enableLabels
702
+ />,
703
+ <ActionDropdown
704
+ tooltip={t`Stock Operations`}
705
+ icon={<IconPackages />}
706
+ actions={[
707
+ {
708
+ name: t`Count`,
709
+ tooltip: t`Count stock`,
710
+ hidden: serialized || !canTransfer || isBuilding,
711
+ icon: (
712
+ <InvenTreeIcon icon='stocktake' iconProps={{ color: 'blue' }} />
713
+ ),
714
+ onClick: () => {
715
+ stockitem.pk && countStockItem.open();
716
+ }
717
+ },
718
+ {
719
+ name: t`Add`,
720
+ tooltip: t`Add Stock`,
721
+ hidden: serialized || !canTransfer || isBuilding,
722
+ icon: <InvenTreeIcon icon='add' iconProps={{ color: 'green' }} />,
723
+ onClick: () => {
724
+ stockitem.pk && addStockItem.open();
725
+ }
726
+ },
727
+ {
728
+ name: t`Remove`,
729
+ tooltip: t`Remove Stock`,
730
+ hidden:
731
+ serialized ||
732
+ !canTransfer ||
733
+ isBuilding ||
734
+ stockitem.quantity <= 0,
735
+ icon: <InvenTreeIcon icon='remove' iconProps={{ color: 'red' }} />,
736
+ onClick: () => {
737
+ stockitem.pk && removeStockItem.open();
738
+ }
739
+ },
740
+ {
741
+ name: t`Transfer`,
742
+ tooltip: t`Transfer Stock`,
743
+ hidden: !canTransfer,
744
+ icon: (
745
+ <InvenTreeIcon icon='transfer' iconProps={{ color: 'blue' }} />
746
+ ),
747
+ onClick: () => {
748
+ stockitem.pk && transferStockItem.open();
749
+ }
750
+ },
751
+ {
752
+ name: t`Serialize`,
753
+ tooltip: t`Serialize stock`,
754
+ hidden:
755
+ isBuilding ||
756
+ serialized ||
757
+ stockitem?.quantity < 1 ||
758
+ stockitem?.part_detail?.trackable != true,
759
+ icon: <InvenTreeIcon icon='serial' iconProps={{ color: 'blue' }} />,
760
+ onClick: () => {
761
+ serializeStockItem.open();
762
+ }
763
+ },
764
+ {
765
+ name: t`Order`,
766
+ tooltip: t`Order Stock`,
767
+ hidden:
768
+ !user.hasAddRole(UserRoles.purchase_order) ||
769
+ !stockitem.part_detail?.active ||
770
+ !stockitem.part_detail?.purchaseable,
771
+ icon: <IconShoppingCart color='blue' />,
772
+ onClick: () => {
773
+ orderPartsWizard.openWizard();
774
+ }
775
+ },
776
+ {
777
+ name: t`Return`,
778
+ tooltip: t`Return from customer`,
779
+ hidden: !stockitem.customer,
780
+ icon: (
781
+ <InvenTreeIcon
782
+ icon='return_orders'
783
+ iconProps={{ color: 'blue' }}
784
+ />
785
+ ),
786
+ onClick: () => {
787
+ stockitem.pk && returnStockItem.open();
788
+ }
789
+ },
790
+ {
791
+ name: t`Assign to Customer`,
792
+ tooltip: t`Assign to a customer`,
793
+ hidden: !!stockitem.customer,
794
+ icon: (
795
+ <InvenTreeIcon icon='customer' iconProps={{ color: 'blue' }} />
796
+ ),
797
+ onClick: () => {
798
+ stockitem.pk && assignToCustomer.open();
799
+ }
800
+ }
801
+ ]}
802
+ />,
803
+ <OptionsActionDropdown
804
+ tooltip={t`Stock Item Actions`}
805
+ actions={[
806
+ DuplicateItemAction({
807
+ hidden: !user.hasAddRole(UserRoles.stock),
808
+ onClick: () => duplicateStockItem.open()
809
+ }),
810
+ EditItemAction({
811
+ hidden: !user.hasChangeRole(UserRoles.stock),
812
+ onClick: () => editStockItem.open()
813
+ }),
814
+ DeleteItemAction({
815
+ hidden: !user.hasDeleteRole(UserRoles.stock),
816
+ onClick: () => deleteStockItem.open()
817
+ })
818
+ ]}
819
+ />
820
+ ];
821
+ }, [id, stockitem, user]);
822
+
823
+ const stockBadges: ReactNode[] = useMemo(() => {
824
+ let available = (stockitem?.quantity ?? 0) - (stockitem?.allocated ?? 0);
825
+ available = Math.max(0, available);
826
+
827
+ return instanceQuery.isLoading
828
+ ? []
829
+ : [
830
+ <DetailsBadge
831
+ color='yellow'
832
+ label={t`In Production`}
833
+ visible={stockitem.is_building}
834
+ />,
835
+ <DetailsBadge
836
+ color='blue'
837
+ label={`${t`Serial Number`}: ${stockitem.serial}`}
838
+ visible={!!stockitem.serial}
839
+ key='serial'
840
+ />,
841
+ <DetailsBadge
842
+ color='blue'
843
+ label={`${t`Quantity`}: ${stockitem.quantity}`}
844
+ visible={!stockitem.serial}
845
+ key='quantity'
846
+ />,
847
+ <DetailsBadge
848
+ color='yellow'
849
+ label={`${t`Available`}: ${available}`}
850
+ visible={
851
+ stockitem.in_stock &&
852
+ !stockitem.serial &&
853
+ available != stockitem.quantity
854
+ }
855
+ key='available'
856
+ />,
857
+ <DetailsBadge
858
+ color='blue'
859
+ label={`${t`Batch Code`}: ${stockitem.batch}`}
860
+ visible={!!stockitem.batch}
861
+ key='batch'
862
+ />,
863
+ <StatusRenderer
864
+ status={stockitem.status_custom_key || stockitem.status}
865
+ type={ModelType.stockitem}
866
+ options={{
867
+ size: 'lg'
868
+ }}
869
+ key='status'
870
+ />,
871
+ <DetailsBadge
872
+ color='yellow'
873
+ label={t`Stale`}
874
+ visible={enableExpiry && stockitem.stale && !stockitem.expired}
875
+ key='stale'
876
+ />,
877
+ <DetailsBadge
878
+ color='orange'
879
+ label={t`Expired`}
880
+ visible={enableExpiry && stockitem.expired}
881
+ key='expired'
882
+ />,
883
+ <DetailsBadge
884
+ color='red'
885
+ label={t`Unavailable`}
886
+ visible={stockitem.in_stock == false}
887
+ key='unavailable'
888
+ />
889
+ ];
890
+ }, [stockitem, instanceQuery, enableExpiry]);
891
+
892
+ return (
893
+ <InstanceDetail
894
+ requiredRole={UserRoles.stock}
895
+ status={requestStatus}
896
+ loading={instanceQuery.isFetching}
897
+ >
898
+ <Stack>
899
+ {user.hasViewRole(UserRoles.stock_location) && (
900
+ <NavigationTree
901
+ title={t`Stock Locations`}
902
+ modelType={ModelType.stocklocation}
903
+ endpoint={ApiEndpoints.stock_location_tree}
904
+ opened={treeOpen}
905
+ onClose={() => setTreeOpen(false)}
906
+ selectedId={stockitem?.location}
907
+ />
908
+ )}
909
+ <PageDetail
910
+ title={t`Stock Item`}
911
+ subtitle={stockitem.part_detail?.full_name}
912
+ imageUrl={stockitem.part_detail?.thumbnail}
913
+ editAction={editStockItem.open}
914
+ editEnabled={user.hasChangePermission(ModelType.stockitem)}
915
+ badges={stockBadges}
916
+ breadcrumbs={
917
+ user.hasViewRole(UserRoles.stock_location) ? breadcrumbs : undefined
918
+ }
919
+ lastCrumb={[
920
+ {
921
+ name: stockitem.name,
922
+ url: `/stock/item/${stockitem.pk}/`
923
+ }
924
+ ]}
925
+ breadcrumbAction={() => {
926
+ setTreeOpen(true);
927
+ }}
928
+ actions={stockActions}
929
+ />
930
+ <PanelGroup
931
+ pageKey='stockitem'
932
+ panels={stockPanels}
933
+ model={ModelType.stockitem}
934
+ id={stockitem.pk}
935
+ instance={stockitem}
936
+ />
937
+ {editStockItem.modal}
938
+ {duplicateStockItem.modal}
939
+ {deleteStockItem.modal}
940
+ {countStockItem.modal}
941
+ {addStockItem.modal}
942
+ {removeStockItem.modal}
943
+ {transferStockItem.modal}
944
+ {serializeStockItem.modal}
945
+ {returnStockItem.modal}
946
+ {assignToCustomer.modal}
947
+ {orderPartsWizard.wizard}
948
+ </Stack>
949
+ </InstanceDetail>
950
+ );
951
+ }