@burdenoff/microfe-assethandler 2026.826.2 → 2026.826.4

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 (571) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +1 -1
  2. package/dist/assethandler/AssetHandlerRoot.js.map +1 -1
  3. package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
  4. package/dist/assethandler/components/ActivityTimeline.js.map +1 -1
  5. package/dist/assethandler/components/AttachmentsPanel.js.map +1 -1
  6. package/dist/assethandler/components/ChartCard.js.map +1 -1
  7. package/dist/assethandler/components/CommentsPanel.js.map +1 -1
  8. package/dist/assethandler/components/NotFoundState.js.map +1 -1
  9. package/dist/assethandler/components/Pagination.js.map +1 -1
  10. package/dist/assethandler/components/SectionHeader.js.map +1 -1
  11. package/dist/assethandler/components/StatTile.js.map +1 -1
  12. package/dist/assethandler/components/charts/BarsChart.js.map +1 -1
  13. package/dist/assethandler/components/charts/ChartParts.js.map +1 -1
  14. package/dist/assethandler/components/charts/DonutChart.js.map +1 -1
  15. package/dist/assethandler/components/charts/ProgressMeter.js.map +1 -1
  16. package/dist/assethandler/components/charts/RadialGauge.js.map +1 -1
  17. package/dist/assethandler/components/charts/Sparkline.js.map +1 -1
  18. package/dist/assethandler/components/charts/TrendChart.js.map +1 -1
  19. package/dist/assethandler/components/charts/chartTheme.js.map +1 -1
  20. package/dist/assethandler/hooks/useAssetHandlerNavigate.js.map +1 -1
  21. package/dist/assethandler/hooks/useCopy.js.map +1 -1
  22. package/dist/assethandler/hooks/useMaintenancePlans.js.map +1 -1
  23. package/dist/assethandler/ops/MaintenancePlanDialog.js.map +1 -1
  24. package/dist/assethandler/ops/NewWorkOrderDialog.js.map +1 -1
  25. package/dist/assethandler/ops/ScheduleMaintenanceDialog.js.map +1 -1
  26. package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
  27. package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
  28. package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
  29. package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
  30. package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
  31. package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
  32. package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
  33. package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
  34. package/dist/assethandler/pages/CmdbBrowserPage.js.map +1 -1
  35. package/dist/assethandler/pages/DashboardPage.js.map +1 -1
  36. package/dist/assethandler/pages/DigitalTwinPage.js.map +1 -1
  37. package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
  38. package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -1
  39. package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
  40. package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
  41. package/dist/assethandler/pages/FinanceInvoiceDetailPage.js.map +1 -1
  42. package/dist/assethandler/pages/IotDevicesPage.js.map +1 -1
  43. package/dist/assethandler/pages/ItilChangeDetailPage.js.map +1 -1
  44. package/dist/assethandler/pages/ItilChangeManagementPage.js.map +1 -1
  45. package/dist/assethandler/pages/ItilDialogs.js.map +1 -1
  46. package/dist/assethandler/pages/ItilIncidentDetailPage.js.map +1 -1
  47. package/dist/assethandler/pages/ItilIncidentManagementPage.js.map +1 -1
  48. package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
  49. package/dist/assethandler/pages/ItilProblemDetailPage.js.map +1 -1
  50. package/dist/assethandler/pages/ItilProblemManagementPage.js.map +1 -1
  51. package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
  52. package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js.map +1 -1
  53. package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.d.ts.map +1 -1
  54. package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js +1 -1
  55. package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js.map +1 -1
  56. package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js.map +1 -1
  57. package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
  58. package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
  59. package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
  60. package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
  61. package/dist/assethandler/pages/ProvenancePage.js.map +1 -1
  62. package/dist/assethandler/pages/ReportsDashboardPage.js.map +1 -1
  63. package/dist/assethandler/pages/SamLicensesPage.js.map +1 -1
  64. package/dist/assethandler/pages/SecurityComplianceDetailPage.js.map +1 -1
  65. package/dist/assethandler/pages/SecurityPolicyDetailPage.js.map +1 -1
  66. package/dist/assethandler/pages/SecuritySecurityEventDetailPage.js.map +1 -1
  67. package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
  68. package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
  69. package/dist/assethandler/pages/TransactionsTransactionListPage.js.map +1 -1
  70. package/dist/assethandler/providers/AssetHandlerProvider.js.map +1 -1
  71. package/dist/assethandler/store/assethandlerStore.js.map +1 -1
  72. package/dist/assethandler/utils/categoryPresentation.js.map +1 -1
  73. package/dist/assethandler/utils/cn.js.map +1 -1
  74. package/dist/assethandler/utils/csv.js.map +1 -1
  75. package/dist/assethandler/utils/i18n.js.map +1 -1
  76. package/dist/assethandler/utils/knowledgeBase.js.map +1 -1
  77. package/dist/assethandler/utils/meter.js.map +1 -1
  78. package/dist/assethandler/utils/money.js.map +1 -1
  79. package/dist/assethandler/utils/navigation.js.map +1 -1
  80. package/dist/assethandler/utils/printAssetTag.js.map +1 -1
  81. package/dist/assethandler/utils/toast.js.map +1 -1
  82. package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
  83. package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
  84. package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
  85. package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
  86. package/dist/node_modules/d3-array/src/descending.js.map +1 -1
  87. package/dist/node_modules/d3-array/src/max.js.map +1 -1
  88. package/dist/node_modules/d3-array/src/min.js.map +1 -1
  89. package/dist/node_modules/d3-array/src/number.js.map +1 -1
  90. package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
  91. package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
  92. package/dist/node_modules/d3-array/src/range.js.map +1 -1
  93. package/dist/node_modules/d3-array/src/sort.js.map +1 -1
  94. package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
  95. package/dist/node_modules/d3-color/src/color.js.map +1 -1
  96. package/dist/node_modules/d3-color/src/define.js.map +1 -1
  97. package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
  98. package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
  99. package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
  100. package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
  101. package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
  102. package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
  103. package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
  104. package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
  105. package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
  106. package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
  107. package/dist/node_modules/d3-format/src/identity.js.map +1 -1
  108. package/dist/node_modules/d3-format/src/locale.js.map +1 -1
  109. package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
  110. package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
  111. package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
  112. package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
  113. package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
  114. package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
  115. package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
  116. package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
  117. package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
  118. package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
  119. package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
  120. package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
  121. package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
  122. package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
  123. package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
  124. package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
  125. package/dist/node_modules/d3-path/src/path.js.map +1 -1
  126. package/dist/node_modules/d3-scale/src/band.js.map +1 -1
  127. package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
  128. package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
  129. package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
  130. package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
  131. package/dist/node_modules/d3-scale/src/init.js.map +1 -1
  132. package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
  133. package/dist/node_modules/d3-scale/src/log.js.map +1 -1
  134. package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
  135. package/dist/node_modules/d3-scale/src/number.js.map +1 -1
  136. package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
  137. package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
  138. package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
  139. package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
  140. package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
  141. package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
  142. package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
  143. package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
  144. package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
  145. package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
  146. package/dist/node_modules/d3-scale/src/time.js.map +1 -1
  147. package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
  148. package/dist/node_modules/d3-shape/src/area.js.map +1 -1
  149. package/dist/node_modules/d3-shape/src/array.js.map +1 -1
  150. package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
  151. package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
  152. package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
  153. package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
  154. package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
  155. package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
  156. package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
  157. package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
  158. package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
  159. package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
  160. package/dist/node_modules/d3-shape/src/line.js.map +1 -1
  161. package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
  162. package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
  163. package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
  164. package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
  165. package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
  166. package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
  167. package/dist/node_modules/d3-shape/src/path.js.map +1 -1
  168. package/dist/node_modules/d3-shape/src/point.js.map +1 -1
  169. package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
  170. package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
  171. package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
  172. package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
  173. package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
  174. package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
  175. package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
  176. package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
  177. package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
  178. package/dist/node_modules/d3-time/src/day.js.map +1 -1
  179. package/dist/node_modules/d3-time/src/hour.js.map +1 -1
  180. package/dist/node_modules/d3-time/src/interval.js.map +1 -1
  181. package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
  182. package/dist/node_modules/d3-time/src/minute.js.map +1 -1
  183. package/dist/node_modules/d3-time/src/month.js.map +1 -1
  184. package/dist/node_modules/d3-time/src/second.js.map +1 -1
  185. package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
  186. package/dist/node_modules/d3-time/src/week.js.map +1 -1
  187. package/dist/node_modules/d3-time/src/year.js.map +1 -1
  188. package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
  189. package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
  190. package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
  191. package/dist/node_modules/dijkstrajs/dijkstra.js.map +1 -1
  192. package/dist/node_modules/eventemitter3/index.js.map +1 -1
  193. package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
  194. package/dist/node_modules/internmap/src/index.js.map +1 -1
  195. package/dist/node_modules/lodash/_DataView.js.map +1 -1
  196. package/dist/node_modules/lodash/_Hash.js.map +1 -1
  197. package/dist/node_modules/lodash/_ListCache.js.map +1 -1
  198. package/dist/node_modules/lodash/_Map.js.map +1 -1
  199. package/dist/node_modules/lodash/_MapCache.js.map +1 -1
  200. package/dist/node_modules/lodash/_Promise.js.map +1 -1
  201. package/dist/node_modules/lodash/_Set.js.map +1 -1
  202. package/dist/node_modules/lodash/_SetCache.js.map +1 -1
  203. package/dist/node_modules/lodash/_Stack.js +2 -1
  204. package/dist/node_modules/lodash/_Stack.js.map +1 -1
  205. package/dist/node_modules/lodash/_Symbol.js.map +1 -1
  206. package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
  207. package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
  208. package/dist/node_modules/lodash/_apply.js.map +1 -1
  209. package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
  210. package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
  211. package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
  212. package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
  213. package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
  214. package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
  215. package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
  216. package/dist/node_modules/lodash/_arraySome.js.map +1 -1
  217. package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
  218. package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
  219. package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
  220. package/dist/node_modules/lodash/_baseEach.js.map +1 -1
  221. package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
  222. package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
  223. package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
  224. package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
  225. package/dist/node_modules/lodash/_baseFor.js.map +1 -1
  226. package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
  227. package/dist/node_modules/lodash/_baseGet.js.map +1 -1
  228. package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
  229. package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
  230. package/dist/node_modules/lodash/_baseGt.js.map +1 -1
  231. package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
  232. package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
  233. package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
  234. package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
  235. package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
  236. package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
  237. package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
  238. package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
  239. package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
  240. package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
  241. package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
  242. package/dist/node_modules/lodash/_baseLt.js.map +1 -1
  243. package/dist/node_modules/lodash/_baseMap.js.map +1 -1
  244. package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
  245. package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
  246. package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
  247. package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
  248. package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
  249. package/dist/node_modules/lodash/_baseRange.js.map +1 -1
  250. package/dist/node_modules/lodash/_baseRest.js.map +1 -1
  251. package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
  252. package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
  253. package/dist/node_modules/lodash/_baseSome.js.map +1 -1
  254. package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
  255. package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
  256. package/dist/node_modules/lodash/_baseToString.js.map +1 -1
  257. package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
  258. package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
  259. package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
  260. package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
  261. package/dist/node_modules/lodash/_castPath.js.map +1 -1
  262. package/dist/node_modules/lodash/_castSlice.js.map +1 -1
  263. package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
  264. package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
  265. package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
  266. package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
  267. package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
  268. package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
  269. package/dist/node_modules/lodash/_createFind.js.map +1 -1
  270. package/dist/node_modules/lodash/_createRange.js.map +1 -1
  271. package/dist/node_modules/lodash/_createSet.js.map +1 -1
  272. package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
  273. package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
  274. package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
  275. package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
  276. package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
  277. package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
  278. package/dist/node_modules/lodash/_getMapData.js.map +1 -1
  279. package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
  280. package/dist/node_modules/lodash/_getNative.js.map +1 -1
  281. package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
  282. package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
  283. package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
  284. package/dist/node_modules/lodash/_getTag.js.map +1 -1
  285. package/dist/node_modules/lodash/_getValue.js.map +1 -1
  286. package/dist/node_modules/lodash/_hasPath.js.map +1 -1
  287. package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
  288. package/dist/node_modules/lodash/_hashClear.js.map +1 -1
  289. package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
  290. package/dist/node_modules/lodash/_hashGet.js.map +1 -1
  291. package/dist/node_modules/lodash/_hashHas.js.map +1 -1
  292. package/dist/node_modules/lodash/_hashSet.js.map +1 -1
  293. package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
  294. package/dist/node_modules/lodash/_isIndex.js.map +1 -1
  295. package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
  296. package/dist/node_modules/lodash/_isKey.js.map +1 -1
  297. package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
  298. package/dist/node_modules/lodash/_isMasked.js.map +1 -1
  299. package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
  300. package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
  301. package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
  302. package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
  303. package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
  304. package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
  305. package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
  306. package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
  307. package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
  308. package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
  309. package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
  310. package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
  311. package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
  312. package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
  313. package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
  314. package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
  315. package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
  316. package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
  317. package/dist/node_modules/lodash/_objectToString.js.map +1 -1
  318. package/dist/node_modules/lodash/_overArg.js.map +1 -1
  319. package/dist/node_modules/lodash/_overRest.js.map +1 -1
  320. package/dist/node_modules/lodash/_root.js.map +1 -1
  321. package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
  322. package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
  323. package/dist/node_modules/lodash/_setToArray.js.map +1 -1
  324. package/dist/node_modules/lodash/_setToString.js.map +1 -1
  325. package/dist/node_modules/lodash/_shortOut.js.map +1 -1
  326. package/dist/node_modules/lodash/_stackClear.js.map +1 -1
  327. package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
  328. package/dist/node_modules/lodash/_stackGet.js.map +1 -1
  329. package/dist/node_modules/lodash/_stackHas.js.map +1 -1
  330. package/dist/node_modules/lodash/_stackSet.js.map +1 -1
  331. package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
  332. package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
  333. package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
  334. package/dist/node_modules/lodash/_toKey.js.map +1 -1
  335. package/dist/node_modules/lodash/_toSource.js.map +1 -1
  336. package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
  337. package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
  338. package/dist/node_modules/lodash/constant.js.map +1 -1
  339. package/dist/node_modules/lodash/debounce.js.map +1 -1
  340. package/dist/node_modules/lodash/eq.js.map +1 -1
  341. package/dist/node_modules/lodash/every.js.map +1 -1
  342. package/dist/node_modules/lodash/find.js.map +1 -1
  343. package/dist/node_modules/lodash/findIndex.js.map +1 -1
  344. package/dist/node_modules/lodash/flatMap.js.map +1 -1
  345. package/dist/node_modules/lodash/get.js.map +1 -1
  346. package/dist/node_modules/lodash/hasIn.js.map +1 -1
  347. package/dist/node_modules/lodash/identity.js.map +1 -1
  348. package/dist/node_modules/lodash/isArguments.js.map +1 -1
  349. package/dist/node_modules/lodash/isArray.js.map +1 -1
  350. package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
  351. package/dist/node_modules/lodash/isBoolean.js.map +1 -1
  352. package/dist/node_modules/lodash/isBuffer.js.map +1 -1
  353. package/dist/node_modules/lodash/isEqual.js.map +1 -1
  354. package/dist/node_modules/lodash/isFunction.js.map +1 -1
  355. package/dist/node_modules/lodash/isLength.js.map +1 -1
  356. package/dist/node_modules/lodash/isNaN.js.map +1 -1
  357. package/dist/node_modules/lodash/isNil.js.map +1 -1
  358. package/dist/node_modules/lodash/isNumber.js.map +1 -1
  359. package/dist/node_modules/lodash/isObject.js.map +1 -1
  360. package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
  361. package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
  362. package/dist/node_modules/lodash/isString.js.map +1 -1
  363. package/dist/node_modules/lodash/isSymbol.js.map +1 -1
  364. package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
  365. package/dist/node_modules/lodash/keys.js.map +1 -1
  366. package/dist/node_modules/lodash/last.js.map +1 -1
  367. package/dist/node_modules/lodash/map.js.map +1 -1
  368. package/dist/node_modules/lodash/mapValues.js.map +1 -1
  369. package/dist/node_modules/lodash/max.js.map +1 -1
  370. package/dist/node_modules/lodash/maxBy.js.map +1 -1
  371. package/dist/node_modules/lodash/memoize.js.map +1 -1
  372. package/dist/node_modules/lodash/min.js.map +1 -1
  373. package/dist/node_modules/lodash/minBy.js.map +1 -1
  374. package/dist/node_modules/lodash/noop.js.map +1 -1
  375. package/dist/node_modules/lodash/now.js.map +1 -1
  376. package/dist/node_modules/lodash/property.js.map +1 -1
  377. package/dist/node_modules/lodash/range.js.map +1 -1
  378. package/dist/node_modules/lodash/some.js.map +1 -1
  379. package/dist/node_modules/lodash/sortBy.js.map +1 -1
  380. package/dist/node_modules/lodash/stubArray.js.map +1 -1
  381. package/dist/node_modules/lodash/stubFalse.js.map +1 -1
  382. package/dist/node_modules/lodash/throttle.js.map +1 -1
  383. package/dist/node_modules/lodash/toFinite.js.map +1 -1
  384. package/dist/node_modules/lodash/toInteger.js.map +1 -1
  385. package/dist/node_modules/lodash/toNumber.js.map +1 -1
  386. package/dist/node_modules/lodash/toString.js.map +1 -1
  387. package/dist/node_modules/lodash/uniqBy.js.map +1 -1
  388. package/dist/node_modules/lodash/upperFirst.js.map +1 -1
  389. package/dist/node_modules/object-assign/index.js.map +1 -1
  390. package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
  391. package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
  392. package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
  393. package/dist/node_modules/prop-types/index.js.map +1 -1
  394. package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
  395. package/dist/node_modules/prop-types/lib/has.js.map +1 -1
  396. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  397. package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  398. package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
  399. package/dist/node_modules/qrcode/lib/browser.js.map +1 -1
  400. package/dist/node_modules/qrcode/lib/can-promise.js.map +1 -1
  401. package/dist/node_modules/qrcode/lib/core/alignment-pattern.js.map +1 -1
  402. package/dist/node_modules/qrcode/lib/core/alphanumeric-data.js.map +1 -1
  403. package/dist/node_modules/qrcode/lib/core/bit-buffer.js.map +1 -1
  404. package/dist/node_modules/qrcode/lib/core/bit-matrix.js.map +1 -1
  405. package/dist/node_modules/qrcode/lib/core/byte-data.js.map +1 -1
  406. package/dist/node_modules/qrcode/lib/core/error-correction-code.js.map +1 -1
  407. package/dist/node_modules/qrcode/lib/core/error-correction-level.js.map +1 -1
  408. package/dist/node_modules/qrcode/lib/core/finder-pattern.js.map +1 -1
  409. package/dist/node_modules/qrcode/lib/core/format-info.js.map +1 -1
  410. package/dist/node_modules/qrcode/lib/core/galois-field.js.map +1 -1
  411. package/dist/node_modules/qrcode/lib/core/kanji-data.js.map +1 -1
  412. package/dist/node_modules/qrcode/lib/core/mask-pattern.js.map +1 -1
  413. package/dist/node_modules/qrcode/lib/core/mode.js.map +1 -1
  414. package/dist/node_modules/qrcode/lib/core/numeric-data.js.map +1 -1
  415. package/dist/node_modules/qrcode/lib/core/polynomial.js.map +1 -1
  416. package/dist/node_modules/qrcode/lib/core/qrcode.js.map +1 -1
  417. package/dist/node_modules/qrcode/lib/core/reed-solomon-encoder.js.map +1 -1
  418. package/dist/node_modules/qrcode/lib/core/regex.js +1 -1
  419. package/dist/node_modules/qrcode/lib/core/regex.js.map +1 -1
  420. package/dist/node_modules/qrcode/lib/core/segments.js.map +1 -1
  421. package/dist/node_modules/qrcode/lib/core/utils.js.map +1 -1
  422. package/dist/node_modules/qrcode/lib/core/version-check.js.map +1 -1
  423. package/dist/node_modules/qrcode/lib/core/version.js.map +1 -1
  424. package/dist/node_modules/qrcode/lib/renderer/canvas.js.map +1 -1
  425. package/dist/node_modules/qrcode/lib/renderer/svg-tag.js.map +1 -1
  426. package/dist/node_modules/qrcode/lib/renderer/utils.js.map +1 -1
  427. package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
  428. package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
  429. package/dist/node_modules/react-is/index.js.map +1 -1
  430. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  431. package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
  432. package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
  433. package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
  434. package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
  435. package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
  436. package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
  437. package/dist/node_modules/recharts/es6/cartesian/Area.js +13 -13
  438. package/dist/node_modules/recharts/es6/cartesian/Area.js.map +1 -1
  439. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  440. package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
  441. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  442. package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
  443. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  444. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
  445. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
  446. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -1
  447. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  448. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
  449. package/dist/node_modules/recharts/es6/cartesian/Line.js +10 -10
  450. package/dist/node_modules/recharts/es6/cartesian/Line.js.map +1 -1
  451. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  452. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
  453. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  454. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
  455. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  456. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
  457. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  458. package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
  459. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  460. package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
  461. package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
  462. package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
  463. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  464. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
  465. package/dist/node_modules/recharts/es6/chart/AreaChart.js.map +1 -1
  466. package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
  467. package/dist/node_modules/recharts/es6/chart/LineChart.js.map +1 -1
  468. package/dist/node_modules/recharts/es6/chart/PieChart.js.map +1 -1
  469. package/dist/node_modules/recharts/es6/chart/RadialBarChart.js.map +1 -1
  470. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  471. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
  472. package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
  473. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  474. package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
  475. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  476. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
  477. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  478. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
  479. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  480. package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
  481. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  482. package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
  483. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  484. package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
  485. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  486. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
  487. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  488. package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
  489. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  490. package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
  491. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  492. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
  493. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  494. package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
  495. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  496. package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
  497. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  498. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
  499. package/dist/node_modules/recharts/es6/polar/Pie.js +13 -13
  500. package/dist/node_modules/recharts/es6/polar/Pie.js.map +1 -1
  501. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
  502. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js.map +1 -1
  503. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
  504. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js.map +1 -1
  505. package/dist/node_modules/recharts/es6/polar/RadialBar.js +6 -6
  506. package/dist/node_modules/recharts/es6/polar/RadialBar.js.map +1 -1
  507. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  508. package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
  509. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  510. package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
  511. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  512. package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
  513. package/dist/node_modules/recharts/es6/shape/Polygon.js +4 -4
  514. package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -1
  515. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  516. package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
  517. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  518. package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
  519. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  520. package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
  521. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  522. package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
  523. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  524. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
  525. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  526. package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
  527. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  528. package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
  529. package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
  530. package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
  531. package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
  532. package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
  533. package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
  534. package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
  535. package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
  536. package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
  537. package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
  538. package/dist/node_modules/recharts/es6/util/PolarUtils.js +1 -1
  539. package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
  540. package/dist/node_modules/recharts/es6/util/RadialBarUtils.js +1 -1
  541. package/dist/node_modules/recharts/es6/util/RadialBarUtils.js.map +1 -1
  542. package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
  543. package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
  544. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  545. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
  546. package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
  547. package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
  548. package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
  549. package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
  550. package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
  551. package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
  552. package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
  553. package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
  554. package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
  555. package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
  556. package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
  557. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  558. package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
  559. package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
  560. package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
  561. package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
  562. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
  563. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  564. package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
  565. package/dist/services/createSandboxAssistantTransport.js.map +1 -1
  566. package/dist/utils/pageContext.js.map +1 -1
  567. package/package.json +4 -4
  568. package/dist/generated/global-operations.d.ts +0 -2
  569. package/dist/generated/global-operations.d.ts.map +0 -1
  570. package/dist/generated/global-types.d.ts +0 -23527
  571. package/dist/generated/global-types.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MaintenancePlanDialog.js","names":[],"sources":["../../../src/assethandler/ops/MaintenancePlanDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport {\n PLAN_PRIORITIES,\n PLAN_TYPES,\n type MaintenancePlan,\n useMaintenancePlans,\n} from '../hooks/useMaintenancePlans';\n\n/**\n * Create or edit a recurring maintenance plan (BOFF-6031).\n *\n * The one rule this form has to get right: a plan needs AT LEAST ONE interval.\n * The backend refuses a plan without one — such a plan can never come due, which\n * is the exact gap the feature closes — so the form says so up front rather than\n * letting someone fill in eight fields and be rejected on submit.\n *\n * Only the four backend plan types are offered. The one-off \"Schedule\n * Maintenance\" dialog also lists CALIBRATION and EMERGENCY, which a free-form\n * MaintenanceRecord.type accepts but a plan does not.\n */\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n/** `<input type=\"date\">` wants YYYY-MM-DD; the API speaks ISO-8601. */\nconst toDateInput = (iso: string | null): string => (iso ? iso.slice(0, 10) : '');\n\nconst numberOrNull = (raw: string): number | null => {\n const trimmed = raw.trim();\n if (trimmed === '') return null;\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) ? parsed : null;\n};\n\nconst checklistTasks = (plan?: MaintenancePlan | null): string[] => {\n const tasks = (plan?.checklistTemplate ?? [])\n .map((item) => (typeof item?.task === 'string' ? item.task : ''))\n .filter((task) => task !== '');\n return tasks.length > 0 ? tasks : [''];\n};\n\n/**\n * The dialog is a thin shell; the form below is REMOUNTED per plan via `key`.\n *\n * That is what keeps the fields correct when you edit one plan, close, then edit\n * another. Re-seeding the same mounted form from an effect would do the same job\n * but through a cascade of setState calls during render — which React (and this\n * repo's lint) rightly rejects. A fresh mount reads its initial state straight\n * from props, with no synchronisation to get wrong.\n */\nexport function MaintenancePlanDialog({\n open,\n onOpenChange,\n plan,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Present when editing; absent when creating. */\n plan?: MaintenancePlan | null;\n}) {\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n {open && (\n <MaintenancePlanForm\n key={plan?.id ?? 'new'}\n plan={plan ?? null}\n onOpenChange={onOpenChange}\n />\n )}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nfunction MaintenancePlanForm({\n plan,\n onOpenChange,\n}: {\n plan: MaintenancePlan | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n const { createPlan, updatePlan, busy } = useMaintenancePlans();\n const isEdit = Boolean(plan);\n\n const [assetId, setAssetId] = useState(plan?.assetId ?? '');\n const [title, setTitle] = useState(plan?.title ?? '');\n const [description, setDescription] = useState(plan?.description ?? '');\n const [type, setType] = useState<string>(plan?.type ?? 'PREVENTIVE');\n const [priority, setPriority] = useState<string>(plan?.priority ?? 'MEDIUM');\n const [intervalDays, setIntervalDays] = useState(\n plan?.intervalDays != null ? String(plan.intervalDays) : ''\n );\n const [intervalMeter, setIntervalMeter] = useState(\n plan?.intervalMeter != null ? String(plan.intervalMeter) : ''\n );\n const [startAt, setStartAt] = useState(toDateInput(plan?.startAt ?? null));\n const [startMeter, setStartMeter] = useState(\n plan?.startMeter != null ? String(plan.startMeter) : ''\n );\n const [leadTimeDays, setLeadTimeDays] = useState(\n plan?.leadTimeDays != null ? String(plan.leadTimeDays) : ''\n );\n const [estimatedCost, setEstimatedCost] = useState(\n plan?.estimatedCost != null ? String(plan.estimatedCost) : ''\n );\n const [checklist, setChecklist] = useState<string[]>(checklistTasks(plan));\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const handleSubmit = () => {\n if (!isEdit && !assetId) {\n notify.warning('Asset required', 'Pick the machine this plan is for.');\n return;\n }\n if (!title.trim()) {\n notify.warning('Title required', 'Give the plan a name, e.g. \"250-hour tractor service\".');\n return;\n }\n const days = numberOrNull(intervalDays);\n const meter = numberOrNull(intervalMeter);\n if (days === null && meter === null) {\n notify.warning(\n 'This plan needs an interval',\n 'Set a day interval, a usage interval, or both — otherwise it can never come due.'\n );\n return;\n }\n\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n\n const input = {\n title: title.trim(),\n description: description.trim() || null,\n type,\n priority,\n intervalDays: days,\n intervalMeter: meter,\n startAt: startAt ? new Date(startAt).toISOString() : null,\n startMeter: numberOrNull(startMeter),\n leadTimeDays: numberOrNull(leadTimeDays),\n estimatedCost: numberOrNull(estimatedCost),\n checklistTemplate: cleanedChecklist,\n };\n\n const done = () => onOpenChange(false);\n if (isEdit && plan) {\n void updatePlan({ variables: { id: plan.id, input } }).then(done);\n } else {\n void createPlan({ variables: { input: { ...input, assetId } } }).then(done);\n }\n };\n\n return (\n <>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {isEdit ? 'Edit maintenance plan' : 'New maintenance plan'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n A recurring schedule. When it falls due it raises a maintenance job, and completing that\n job starts the next cycle.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4\">\n {!isEdit && (\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., 250-hour tractor service\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"What does this service involve?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={setType}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PLAN_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={setPriority}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PLAN_PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken p-4\">\n <p className=\"text-sm font-medium text-text-primary\">How often? *</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n Set at least one. With both, the plan comes due at whichever arrives first — the way a\n service book reads &ldquo;every 90 days or 250 hours&rdquo;.\n </p>\n <div className=\"mt-3 grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Every N days</Label>\n <Input\n type=\"number\"\n min={1}\n placeholder=\"90\"\n value={intervalDays}\n onChange={(e) => setIntervalDays(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Every N usage units</Label>\n <Input\n type=\"number\"\n min={1}\n placeholder=\"250\"\n value={intervalMeter}\n onChange={(e) => setIntervalMeter(e.target.value)}\n />\n <p className=\"text-xs text-text-tertiary\">\n Counts against the asset&rsquo;s usage meter. Assets without one never come due this\n way.\n </p>\n </div>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Start counting from</Label>\n <Input type=\"date\" value={startAt} onChange={(e) => setStartAt(e.target.value)} />\n <p className=\"text-xs text-text-tertiary\">Defaults to today.</p>\n </div>\n <div className=\"space-y-2\">\n <Label>Meter at start</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"e.g. 1200\"\n value={startMeter}\n onChange={(e) => setStartMeter(e.target.value)}\n />\n {/*\n This writes the PLAN's anchor, not the asset's meter. Its placeholder used\n to read \"Current reading\", which made it look like the field where you\n record the tractor's hours — type 1200 there and the plan anchors at 1200,\n computes a next-due of 1450, and then never comes due because the ASSET's\n meter is still empty. Two inputs that looked identical and behaved\n completely differently (BOFF-6032).\n */}\n <p className=\"text-xs text-text-tertiary\">\n Where this plan starts counting from — not the asset&rsquo;s reading. Record that on\n the asset itself.\n </p>\n </div>\n <div className=\"space-y-2\">\n <Label>Raise work N days early</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0\"\n value={leadTimeDays}\n onChange={(e) => setLeadTimeDays(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <Label>Estimated cost</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0.00\"\n value={estimatedCost}\n onChange={(e) => setEstimatedCost(e.target.value)}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label>Checklist template</Label>\n <p className=\"text-xs text-text-tertiary\">\n Copied onto every job this plan raises, so the procedure travels with the schedule.\n </p>\n {checklist.map((task, index) => (\n <div key={index} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Step ${index + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(index, e.target.value)}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => removeChecklistItem(index)}\n aria-label={`Remove step ${index + 1}`}\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n ))}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 size-4\" /> Add step\n </Button>\n </div>\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={busy}>\n {busy && <Loader2 className=\"mr-2 size-4 animate-spin\" />}\n {isEdit ? 'Save plan' : 'Create plan'}\n </Button>\n </ResponsiveDialogFooter>\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MaintenancePlanDialog.js","names":[],"sources":["../../../src/assethandler/ops/MaintenancePlanDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport {\n PLAN_PRIORITIES,\n PLAN_TYPES,\n type MaintenancePlan,\n useMaintenancePlans,\n} from '../hooks/useMaintenancePlans';\n\n/**\n * Create or edit a recurring maintenance plan (BOFF-6031).\n *\n * The one rule this form has to get right: a plan needs AT LEAST ONE interval.\n * The backend refuses a plan without one — such a plan can never come due, which\n * is the exact gap the feature closes — so the form says so up front rather than\n * letting someone fill in eight fields and be rejected on submit.\n *\n * Only the four backend plan types are offered. The one-off \"Schedule\n * Maintenance\" dialog also lists CALIBRATION and EMERGENCY, which a free-form\n * MaintenanceRecord.type accepts but a plan does not.\n */\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n/** `<input type=\"date\">` wants YYYY-MM-DD; the API speaks ISO-8601. */\nconst toDateInput = (iso: string | null): string => (iso ? iso.slice(0, 10) : '');\n\nconst numberOrNull = (raw: string): number | null => {\n const trimmed = raw.trim();\n if (trimmed === '') return null;\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) ? parsed : null;\n};\n\nconst checklistTasks = (plan?: MaintenancePlan | null): string[] => {\n const tasks = (plan?.checklistTemplate ?? [])\n .map((item) => (typeof item?.task === 'string' ? item.task : ''))\n .filter((task) => task !== '');\n return tasks.length > 0 ? tasks : [''];\n};\n\n/**\n * The dialog is a thin shell; the form below is REMOUNTED per plan via `key`.\n *\n * That is what keeps the fields correct when you edit one plan, close, then edit\n * another. Re-seeding the same mounted form from an effect would do the same job\n * but through a cascade of setState calls during render — which React (and this\n * repo's lint) rightly rejects. A fresh mount reads its initial state straight\n * from props, with no synchronisation to get wrong.\n */\nexport function MaintenancePlanDialog({\n open,\n onOpenChange,\n plan,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Present when editing; absent when creating. */\n plan?: MaintenancePlan | null;\n}) {\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n {open && (\n <MaintenancePlanForm\n key={plan?.id ?? 'new'}\n plan={plan ?? null}\n onOpenChange={onOpenChange}\n />\n )}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nfunction MaintenancePlanForm({\n plan,\n onOpenChange,\n}: {\n plan: MaintenancePlan | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n const { createPlan, updatePlan, busy } = useMaintenancePlans();\n const isEdit = Boolean(plan);\n\n const [assetId, setAssetId] = useState(plan?.assetId ?? '');\n const [title, setTitle] = useState(plan?.title ?? '');\n const [description, setDescription] = useState(plan?.description ?? '');\n const [type, setType] = useState<string>(plan?.type ?? 'PREVENTIVE');\n const [priority, setPriority] = useState<string>(plan?.priority ?? 'MEDIUM');\n const [intervalDays, setIntervalDays] = useState(\n plan?.intervalDays != null ? String(plan.intervalDays) : ''\n );\n const [intervalMeter, setIntervalMeter] = useState(\n plan?.intervalMeter != null ? String(plan.intervalMeter) : ''\n );\n const [startAt, setStartAt] = useState(toDateInput(plan?.startAt ?? null));\n const [startMeter, setStartMeter] = useState(\n plan?.startMeter != null ? String(plan.startMeter) : ''\n );\n const [leadTimeDays, setLeadTimeDays] = useState(\n plan?.leadTimeDays != null ? String(plan.leadTimeDays) : ''\n );\n const [estimatedCost, setEstimatedCost] = useState(\n plan?.estimatedCost != null ? String(plan.estimatedCost) : ''\n );\n const [checklist, setChecklist] = useState<string[]>(checklistTasks(plan));\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const handleSubmit = () => {\n if (!isEdit && !assetId) {\n notify.warning('Asset required', 'Pick the machine this plan is for.');\n return;\n }\n if (!title.trim()) {\n notify.warning('Title required', 'Give the plan a name, e.g. \"250-hour tractor service\".');\n return;\n }\n const days = numberOrNull(intervalDays);\n const meter = numberOrNull(intervalMeter);\n if (days === null && meter === null) {\n notify.warning(\n 'This plan needs an interval',\n 'Set a day interval, a usage interval, or both — otherwise it can never come due.'\n );\n return;\n }\n\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n\n const input = {\n title: title.trim(),\n description: description.trim() || null,\n type,\n priority,\n intervalDays: days,\n intervalMeter: meter,\n startAt: startAt ? new Date(startAt).toISOString() : null,\n startMeter: numberOrNull(startMeter),\n leadTimeDays: numberOrNull(leadTimeDays),\n estimatedCost: numberOrNull(estimatedCost),\n checklistTemplate: cleanedChecklist,\n };\n\n const done = () => onOpenChange(false);\n if (isEdit && plan) {\n void updatePlan({ variables: { id: plan.id, input } }).then(done);\n } else {\n void createPlan({ variables: { input: { ...input, assetId } } }).then(done);\n }\n };\n\n return (\n <>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {isEdit ? 'Edit maintenance plan' : 'New maintenance plan'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n A recurring schedule. When it falls due it raises a maintenance job, and completing that\n job starts the next cycle.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4\">\n {!isEdit && (\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., 250-hour tractor service\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"What does this service involve?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={setType}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PLAN_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={setPriority}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PLAN_PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken p-4\">\n <p className=\"text-sm font-medium text-text-primary\">How often? *</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n Set at least one. With both, the plan comes due at whichever arrives first — the way a\n service book reads &ldquo;every 90 days or 250 hours&rdquo;.\n </p>\n <div className=\"mt-3 grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Every N days</Label>\n <Input\n type=\"number\"\n min={1}\n placeholder=\"90\"\n value={intervalDays}\n onChange={(e) => setIntervalDays(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Every N usage units</Label>\n <Input\n type=\"number\"\n min={1}\n placeholder=\"250\"\n value={intervalMeter}\n onChange={(e) => setIntervalMeter(e.target.value)}\n />\n <p className=\"text-xs text-text-tertiary\">\n Counts against the asset&rsquo;s usage meter. Assets without one never come due this\n way.\n </p>\n </div>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Start counting from</Label>\n <Input type=\"date\" value={startAt} onChange={(e) => setStartAt(e.target.value)} />\n <p className=\"text-xs text-text-tertiary\">Defaults to today.</p>\n </div>\n <div className=\"space-y-2\">\n <Label>Meter at start</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"e.g. 1200\"\n value={startMeter}\n onChange={(e) => setStartMeter(e.target.value)}\n />\n {/*\n This writes the PLAN's anchor, not the asset's meter. Its placeholder used\n to read \"Current reading\", which made it look like the field where you\n record the tractor's hours — type 1200 there and the plan anchors at 1200,\n computes a next-due of 1450, and then never comes due because the ASSET's\n meter is still empty. Two inputs that looked identical and behaved\n completely differently (BOFF-6032).\n */}\n <p className=\"text-xs text-text-tertiary\">\n Where this plan starts counting from — not the asset&rsquo;s reading. Record that on\n the asset itself.\n </p>\n </div>\n <div className=\"space-y-2\">\n <Label>Raise work N days early</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0\"\n value={leadTimeDays}\n onChange={(e) => setLeadTimeDays(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <Label>Estimated cost</Label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0.00\"\n value={estimatedCost}\n onChange={(e) => setEstimatedCost(e.target.value)}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label>Checklist template</Label>\n <p className=\"text-xs text-text-tertiary\">\n Copied onto every job this plan raises, so the procedure travels with the schedule.\n </p>\n {checklist.map((task, index) => (\n <div key={index} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Step ${index + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(index, e.target.value)}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => removeChecklistItem(index)}\n aria-label={`Remove step ${index + 1}`}\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n ))}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 size-4\" /> Add step\n </Button>\n </div>\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={busy}>\n {busy && <Loader2 className=\"mr-2 size-4 animate-spin\" />}\n {isEdit ? 'Save plan' : 'Create plan'}\n </Button>\n </ResponsiveDialogFooter>\n </>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NewWorkOrderDialog.js","names":[],"sources":["../../../src/assethandler/ops/NewWorkOrderDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n/**\n * Reusable \"New Work Order\" create dialog, wired to the real createWorkOrder\n * mutation (wspace-assethandler-svc). Used by the Operations Hub.\n */\nconst CREATE_WORK_ORDER_MUTATION = gql`\n mutation AssetHandlerCreateWorkOrder($input: CreateWorkOrderInput!) {\n createWorkOrder(input: $input) {\n id\n title\n }\n }\n`;\n\ninterface CreateWorkOrderResult {\n createWorkOrder: { id: string; title: string };\n}\n\nconst WORK_ORDER_TYPES = ['CORRECTIVE', 'PREVENTIVE', 'PREDICTIVE', 'EMERGENCY'] as const;\nconst WORK_ORDER_STATUSES = [\n 'DRAFT',\n 'SCHEDULED',\n 'APPROVED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'CANCELLED',\n] as const;\nconst PRIORITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nexport function NewWorkOrderDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [assetId, setAssetId] = useState('');\n const [assignedTo, setAssignedTo] = useState('');\n const [type, setType] = useState<(typeof WORK_ORDER_TYPES)[number]>('CORRECTIVE');\n const [priority, setPriority] = useState<(typeof PRIORITIES)[number]>('MEDIUM');\n const [status, setStatus] = useState<(typeof WORK_ORDER_STATUSES)[number]>('DRAFT');\n const [checklist, setChecklist] = useState<string[]>(['']);\n\n const reset = () => {\n setTitle('');\n setDescription('');\n setAssetId('');\n setAssignedTo('');\n setType('CORRECTIVE');\n setPriority('MEDIUM');\n setStatus('DRAFT');\n setChecklist(['']);\n };\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const [createWorkOrder, { loading }] = useMutation<CreateWorkOrderResult>(\n CREATE_WORK_ORDER_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Work order created', `${data.createWorkOrder.title} was raised.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create work order', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!title.trim()) {\n notify.warning('Title required', 'Give the work order a title.');\n return;\n }\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n void createWorkOrder({\n variables: {\n input: {\n title: title.trim(),\n description: description.trim() || null,\n assetId: assetId || null,\n assignedTo: assignedTo.trim() || null,\n type,\n priority,\n status,\n checklist: cleanedChecklist,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Work Order</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Raise a work order when an asset needs repair, inspection or attention.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., Replace worn drive belt\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"Describe the work required\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Unassigned\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Assigned To</Label>\n <Input\n placeholder=\"e.g., Facilities team\"\n value={assignedTo}\n onChange={(e) => setAssignedTo(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WORK_ORDER_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={(v) => setPriority(v as typeof priority)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WORK_ORDER_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Checklist</Label>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add task\n </Button>\n </div>\n <div className=\"space-y-2\">\n {checklist.map((task, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Task ${i + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(i, e.target.value)}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => removeChecklistItem(i)}\n disabled={checklist.length === 1}\n aria-label=\"Remove task\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Work Order'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NewWorkOrderDialog.js","names":[],"sources":["../../../src/assethandler/ops/NewWorkOrderDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n/**\n * Reusable \"New Work Order\" create dialog, wired to the real createWorkOrder\n * mutation (wspace-assethandler-svc). Used by the Operations Hub.\n */\nconst CREATE_WORK_ORDER_MUTATION = gql`\n mutation AssetHandlerCreateWorkOrder($input: CreateWorkOrderInput!) {\n createWorkOrder(input: $input) {\n id\n title\n }\n }\n`;\n\ninterface CreateWorkOrderResult {\n createWorkOrder: { id: string; title: string };\n}\n\nconst WORK_ORDER_TYPES = ['CORRECTIVE', 'PREVENTIVE', 'PREDICTIVE', 'EMERGENCY'] as const;\nconst WORK_ORDER_STATUSES = [\n 'DRAFT',\n 'SCHEDULED',\n 'APPROVED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'CANCELLED',\n] as const;\nconst PRIORITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nexport function NewWorkOrderDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [assetId, setAssetId] = useState('');\n const [assignedTo, setAssignedTo] = useState('');\n const [type, setType] = useState<(typeof WORK_ORDER_TYPES)[number]>('CORRECTIVE');\n const [priority, setPriority] = useState<(typeof PRIORITIES)[number]>('MEDIUM');\n const [status, setStatus] = useState<(typeof WORK_ORDER_STATUSES)[number]>('DRAFT');\n const [checklist, setChecklist] = useState<string[]>(['']);\n\n const reset = () => {\n setTitle('');\n setDescription('');\n setAssetId('');\n setAssignedTo('');\n setType('CORRECTIVE');\n setPriority('MEDIUM');\n setStatus('DRAFT');\n setChecklist(['']);\n };\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const [createWorkOrder, { loading }] = useMutation<CreateWorkOrderResult>(\n CREATE_WORK_ORDER_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Work order created', `${data.createWorkOrder.title} was raised.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create work order', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!title.trim()) {\n notify.warning('Title required', 'Give the work order a title.');\n return;\n }\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n void createWorkOrder({\n variables: {\n input: {\n title: title.trim(),\n description: description.trim() || null,\n assetId: assetId || null,\n assignedTo: assignedTo.trim() || null,\n type,\n priority,\n status,\n checklist: cleanedChecklist,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Work Order</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Raise a work order when an asset needs repair, inspection or attention.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., Replace worn drive belt\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"Describe the work required\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Unassigned\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Assigned To</Label>\n <Input\n placeholder=\"e.g., Facilities team\"\n value={assignedTo}\n onChange={(e) => setAssignedTo(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WORK_ORDER_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={(v) => setPriority(v as typeof priority)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {WORK_ORDER_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Checklist</Label>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add task\n </Button>\n </div>\n <div className=\"space-y-2\">\n {checklist.map((task, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Task ${i + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(i, e.target.value)}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => removeChecklistItem(i)}\n disabled={checklist.length === 1}\n aria-label=\"Remove task\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Work Order'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScheduleMaintenanceDialog.js","names":[],"sources":["../../../src/assethandler/ops/ScheduleMaintenanceDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n/**\n * Reusable \"Schedule Maintenance\" create dialog. Wired to the real\n * createMaintenanceRecord mutation (wspace-assethandler-svc). Shared by the\n * Maintenance Scheduler and Maintenance Calendar pages so both entry points\n * write through one contract.\n *\n * Reuse note: a wspace-calendar-svc CalendarEvent projection is deliberately\n * deferred — createEvent requires a calendarId that the AssetHandler MFE has no\n * handle on. The Maintenance Calendar therefore renders the real\n * maintenanceRecords (scheduledAt) rather than shared-platform CalendarEvents.\n */\nconst CREATE_MAINTENANCE_RECORD_MUTATION = gql`\n mutation AssetHandlerCreateMaintenanceRecord($input: CreateMaintenanceRecordInput!) {\n createMaintenanceRecord(input: $input) {\n id\n title\n }\n }\n`;\n\ninterface CreateMaintenanceRecordResult {\n createMaintenanceRecord: { id: string; title: string };\n}\n\n// Maintenance `type` is a free-form String on the backend; these are the\n// canonical categories the product exposes in the UI.\nconst MAINTENANCE_TYPES = [\n 'PREVENTIVE',\n 'CORRECTIVE',\n 'INSPECTION',\n 'CALIBRATION',\n 'EMERGENCY',\n] as const;\nconst PRIORITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nexport function ScheduleMaintenanceDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n\n const [assetId, setAssetId] = useState('');\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [type, setType] = useState<(typeof MAINTENANCE_TYPES)[number]>('PREVENTIVE');\n const [priority, setPriority] = useState<(typeof PRIORITIES)[number]>('MEDIUM');\n const [scheduledAt, setScheduledAt] = useState('');\n const [estimatedCost, setEstimatedCost] = useState('');\n const [checklist, setChecklist] = useState<string[]>(['']);\n\n const reset = () => {\n setAssetId('');\n setTitle('');\n setDescription('');\n setType('PREVENTIVE');\n setPriority('MEDIUM');\n setScheduledAt('');\n setEstimatedCost('');\n setChecklist(['']);\n };\n\n const [createMaintenanceRecord, { loading }] = useMutation<CreateMaintenanceRecordResult>(\n CREATE_MAINTENANCE_RECORD_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Maintenance scheduled', `${data.createMaintenanceRecord.title} was added.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not schedule maintenance', error.message),\n }\n );\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const handleSubmit = () => {\n if (!assetId) {\n notify.warning('Asset required', 'Pick the asset this maintenance is for.');\n return;\n }\n if (!title.trim()) {\n notify.warning('Title required', 'Give the maintenance job a title.');\n return;\n }\n const parsedCost = Number(estimatedCost);\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n void createMaintenanceRecord({\n variables: {\n input: {\n assetId,\n title: title.trim(),\n description: description.trim() || null,\n type,\n status: 'SCHEDULED',\n priority,\n scheduledAt: scheduledAt ? new Date(scheduledAt).toISOString() : null,\n estimatedCost:\n estimatedCost.trim() !== '' && Number.isFinite(parsedCost) ? parsedCost : null,\n checklist: cleanedChecklist,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Schedule Maintenance</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Plan a maintenance job against an asset, with its own checklist and cost estimate.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., Quarterly HVAC service\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"What does this job involve?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {MAINTENANCE_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={(v) => setPriority(v as typeof priority)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Estimated Cost</Label>\n <Input\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n placeholder=\"e.g., 500\"\n value={estimatedCost}\n onChange={(e) => setEstimatedCost(e.target.value)}\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Scheduled Date</Label>\n <Input\n type=\"date\"\n value={scheduledAt}\n onChange={(e) => setScheduledAt(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Checklist</Label>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add task\n </Button>\n </div>\n <div className=\"space-y-2\">\n {checklist.map((task, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Task ${i + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(i, e.target.value)}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => removeChecklistItem(i)}\n disabled={checklist.length === 1}\n aria-label=\"Remove task\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Scheduling…' : 'Schedule Maintenance'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ScheduleMaintenanceDialog.js","names":[],"sources":["../../../src/assethandler/ops/ScheduleMaintenanceDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { Loader2, Plus, X } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n/**\n * Reusable \"Schedule Maintenance\" create dialog. Wired to the real\n * createMaintenanceRecord mutation (wspace-assethandler-svc). Shared by the\n * Maintenance Scheduler and Maintenance Calendar pages so both entry points\n * write through one contract.\n *\n * Reuse note: a wspace-calendar-svc CalendarEvent projection is deliberately\n * deferred — createEvent requires a calendarId that the AssetHandler MFE has no\n * handle on. The Maintenance Calendar therefore renders the real\n * maintenanceRecords (scheduledAt) rather than shared-platform CalendarEvents.\n */\nconst CREATE_MAINTENANCE_RECORD_MUTATION = gql`\n mutation AssetHandlerCreateMaintenanceRecord($input: CreateMaintenanceRecordInput!) {\n createMaintenanceRecord(input: $input) {\n id\n title\n }\n }\n`;\n\ninterface CreateMaintenanceRecordResult {\n createMaintenanceRecord: { id: string; title: string };\n}\n\n// Maintenance `type` is a free-form String on the backend; these are the\n// canonical categories the product exposes in the UI.\nconst MAINTENANCE_TYPES = [\n 'PREVENTIVE',\n 'CORRECTIVE',\n 'INSPECTION',\n 'CALIBRATION',\n 'EMERGENCY',\n] as const;\nconst PRIORITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nexport function ScheduleMaintenanceDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const { assets } = useAssetHandlerStore();\n\n const [assetId, setAssetId] = useState('');\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [type, setType] = useState<(typeof MAINTENANCE_TYPES)[number]>('PREVENTIVE');\n const [priority, setPriority] = useState<(typeof PRIORITIES)[number]>('MEDIUM');\n const [scheduledAt, setScheduledAt] = useState('');\n const [estimatedCost, setEstimatedCost] = useState('');\n const [checklist, setChecklist] = useState<string[]>(['']);\n\n const reset = () => {\n setAssetId('');\n setTitle('');\n setDescription('');\n setType('PREVENTIVE');\n setPriority('MEDIUM');\n setScheduledAt('');\n setEstimatedCost('');\n setChecklist(['']);\n };\n\n const [createMaintenanceRecord, { loading }] = useMutation<CreateMaintenanceRecordResult>(\n CREATE_MAINTENANCE_RECORD_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Maintenance scheduled', `${data.createMaintenanceRecord.title} was added.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not schedule maintenance', error.message),\n }\n );\n\n const setChecklistItem = (index: number, value: string) =>\n setChecklist((prev) => prev.map((task, i) => (i === index ? value : task)));\n const addChecklistItem = () => setChecklist((prev) => [...prev, '']);\n const removeChecklistItem = (index: number) =>\n setChecklist((prev) => (prev.length === 1 ? prev : prev.filter((_, i) => i !== index)));\n\n const handleSubmit = () => {\n if (!assetId) {\n notify.warning('Asset required', 'Pick the asset this maintenance is for.');\n return;\n }\n if (!title.trim()) {\n notify.warning('Title required', 'Give the maintenance job a title.');\n return;\n }\n const parsedCost = Number(estimatedCost);\n const cleanedChecklist = checklist\n .map((task) => task.trim())\n .filter((task) => task !== '')\n .map((task) => ({ task, completed: false }));\n void createMaintenanceRecord({\n variables: {\n input: {\n assetId,\n title: title.trim(),\n description: description.trim() || null,\n type,\n status: 'SCHEDULED',\n priority,\n scheduledAt: scheduledAt ? new Date(scheduledAt).toISOString() : null,\n estimatedCost:\n estimatedCost.trim() !== '' && Number.isFinite(parsedCost) ? parsedCost : null,\n checklist: cleanedChecklist,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Schedule Maintenance</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Plan a maintenance job against an asset, with its own checklist and cost estimate.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.name}\n {asset.assetTag ? ` · ${asset.assetTag}` : ''}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input\n placeholder=\"e.g., Quarterly HVAC service\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description</Label>\n <Textarea\n placeholder=\"What does this job involve?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {MAINTENANCE_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Priority</Label>\n <Select value={priority} onValueChange={(v) => setPriority(v as typeof priority)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PRIORITIES.map((p) => (\n <SelectItem key={p} value={p}>\n {humanize(p)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Estimated Cost</Label>\n <Input\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n placeholder=\"e.g., 500\"\n value={estimatedCost}\n onChange={(e) => setEstimatedCost(e.target.value)}\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Scheduled Date</Label>\n <Input\n type=\"date\"\n value={scheduledAt}\n onChange={(e) => setScheduledAt(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Checklist</Label>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={addChecklistItem}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add task\n </Button>\n </div>\n <div className=\"space-y-2\">\n {checklist.map((task, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder={`Task ${i + 1}`}\n value={task}\n onChange={(e) => setChecklistItem(i, e.target.value)}\n />\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => removeChecklistItem(i)}\n disabled={checklist.length === 1}\n aria-label=\"Remove task\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Scheduling…' : 'Schedule Maintenance'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AiPredictionsPage.js","names":[],"sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"sourcesContent":["import type React from 'react';\nimport { BrainCircuit, Plus, Wrench, Loader2, BarChart3 } from 'lucide-react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n ChartCard,\n DonutChart,\n BarsChart,\n RadialGauge,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst AI_PREDICTIONS_QUERY = gql`\n query AssetHandlerAiPredictions {\n aiPredictions {\n id\n assetId\n predictionType\n score\n confidence\n recommendation\n features\n status\n generatedAt\n modelVersion\n }\n }\n`;\n\nconst REQUEST_AI_PREDICTION_MUTATION = gql`\n mutation AssetHandlerRequestAiPrediction($input: RequestAIPredictionInput!) {\n requestAIPrediction(input: $input) {\n id\n }\n }\n`;\n\ninterface AiPrediction {\n id: string;\n assetId: string;\n predictionType: string;\n score: number;\n confidence: number;\n recommendation: string;\n features: Record<string, unknown> | null;\n status: string;\n generatedAt: string;\n modelVersion: string;\n}\n\nconst PREDICTION_TYPES = [\n { value: 'maintenance-risk', label: 'Maintenance risk' },\n { value: 'failure-forecast', label: 'Failure forecast' },\n { value: 'utilization-forecast', label: 'Utilization forecast' },\n { value: 'anomaly-detection', label: 'Anomaly detection' },\n { value: 'end-of-life', label: 'End-of-life projection' },\n] as const;\n\nconst humanizePredictionType = (value: string): string =>\n PREDICTION_TYPES.find((t) => t.value === value)?.label ?? value.replace(/-/g, ' ');\n\ntype RiskBand = 'high' | 'medium' | 'low';\n\nfunction riskBandOf(score: number): {\n band: RiskBand;\n label: string;\n tone: 'danger' | 'warning' | 'success';\n} {\n if (score >= 0.66) return { band: 'high', label: 'High', tone: 'danger' };\n if (score >= 0.33) return { band: 'medium', label: 'Medium', tone: 'warning' };\n return { band: 'low', label: 'Low', tone: 'success' };\n}\n\n/** Extract numeric feature importances from the backend `features` JSONObject. */\nfunction featureBars(\n features: Record<string, unknown> | null | undefined\n): { name: string; importance: number }[] {\n if (!features) return [];\n return Object.entries(features)\n .map(([name, value]) => ({\n name,\n importance: typeof value === 'number' ? value : Number(value),\n }))\n .filter((f) => Number.isFinite(f.importance))\n .sort((a, b) => b.importance - a.importance)\n .slice(0, 8);\n}\n\nfunction RunPredictionDialog({\n open,\n onOpenChange,\n onRun,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onRun: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [assetId, setAssetId] = useState('');\n const [predictionType, setPredictionType] =\n useState<(typeof PREDICTION_TYPES)[number]['value']>('maintenance-risk');\n\n const [requestPrediction, { loading: requesting }] = useMutation(REQUEST_AI_PREDICTION_MUTATION, {\n onCompleted: () => {\n notify.success('Prediction requested', 'The model result will appear shortly.');\n onOpenChange(false);\n onRun();\n },\n onError: (error) => notify.error('Could not run prediction', error.message),\n });\n\n const handleRun = (event: React.FormEvent) => {\n event.preventDefault();\n if (!assetId) {\n notify.warning('Asset required', 'Select an asset to run a prediction against.');\n return;\n }\n void requestPrediction({ variables: { input: { assetId, predictionType } } });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Run Prediction</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Pick an asset and a model to forecast failure risk and get a recommended action.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-4\" onSubmit={handleRun}>\n <div className=\"space-y-2\">\n <Label>Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.assetTag} — {asset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Prediction Type</Label>\n <Select\n value={predictionType}\n onValueChange={(v) => setPredictionType(v as typeof predictionType)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={requesting}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={requesting}>\n {requesting ? 'Running…' : 'Run Prediction'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function AiPredictionsPage() {\n const assets = useAssetHandlerStore((s) => s.assets);\n const navigate = useAssetHandlerNavigate();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [typeFilter, setTypeFilter] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ aiPredictions: AiPrediction[] }>(\n AI_PREDICTIONS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const predictions = useMemo(() => data?.aiPredictions ?? [], [data?.aiPredictions]);\n\n const assetLabelById = useMemo(() => {\n const map = new Map<string, string>();\n for (const a of assets) map.set(a.id, `${a.assetTag} — ${a.name}`);\n return map;\n }, [assets]);\n\n const labelFor = (assetId: string): string =>\n assetLabelById.get(assetId) ?? `Asset ${assetId.slice(0, 8)}`;\n\n const sorted = useMemo(() => {\n const list =\n typeFilter === 'ALL'\n ? predictions\n : predictions.filter((p) => p.predictionType === typeFilter);\n return [...list].sort((a, b) => b.score - a.score);\n }, [predictions, typeFilter]);\n\n const riskMix = useMemo<DonutSlice[]>(() => {\n const counts: Record<RiskBand, number> = { high: 0, medium: 0, low: 0 };\n for (const p of predictions) counts[riskBandOf(p.score).band] += 1;\n const order: { band: RiskBand; label: string }[] = [\n { band: 'high', label: 'High' },\n { band: 'medium', label: 'Medium' },\n { band: 'low', label: 'Low' },\n ];\n return order\n .filter((o) => counts[o.band] > 0)\n .map((o, i) => ({ name: o.label, value: counts[o.band], color: seriesColor(i) }));\n }, [predictions]);\n\n // Feature importance is shown for the highest-risk prediction that carries features.\n const featureFocus = useMemo(() => {\n const withFeatures = sorted.find((p) => featureBars(p.features).length > 0);\n return withFeatures ?? null;\n }, [sorted]);\n const focusBars = featureBars(featureFocus?.features);\n\n const pagination = usePagination(sorted, { pageSize: 6, resetKey: typeFilter });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={BrainCircuit}\n title=\"AI Predictions\"\n description=\"Forecast failures before they happen and prioritise which assets to service next.\"\n actions={\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Run Prediction\n </Button>\n }\n />\n <PagePurpose>\n Pick an asset and a model to get a risk score, confidence level and a concrete\n recommendation — so you can schedule preventive maintenance instead of reacting to\n breakdowns.\n </PagePurpose>\n\n <RunPredictionDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onRun={() => void refetch()}\n />\n\n {predictions.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Risk distribution\" subtitle=\"Predicted failure risk across assets\">\n <DonutChart\n data={riskMix}\n height={210}\n centerLabel=\"Assets\"\n centerValue={predictions.length}\n ariaLabel=\"Risk distribution across predictions\"\n />\n </ChartCard>\n <ChartCard\n title=\"Feature importance\"\n subtitle={\n featureFocus\n ? `Top drivers · ${labelFor(featureFocus.assetId)}`\n : 'Model feature drivers'\n }\n icon={BarChart3}\n >\n {focusBars.length > 0 ? (\n <BarsChart\n data={focusBars}\n xKey=\"name\"\n series={[{ key: 'importance', label: 'Importance' }]}\n orientation=\"horizontal\"\n height={210}\n categoryWidth={140}\n ariaLabel=\"Feature importance\"\n />\n ) : (\n <div className=\"flex h-[210px] items-center justify-center px-4 text-center text-sm text-text-secondary\">\n Feature importance appears here once a model returns feature drivers.\n </div>\n )}\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Predicted failure risk per asset\n </h3>\n <div className=\"w-full sm:w-64\">\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Prediction type\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All prediction types</SelectItem>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {loading && predictions.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-56 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && sorted.length === 0 ? (\n <IllustratedEmptyState\n illustration={typeFilter === 'ALL' ? 'empty-data' : 'empty-search'}\n title={\n typeFilter === 'ALL' ? 'No AI predictions available yet' : 'No predictions of this type'\n }\n description={\n typeFilter === 'ALL'\n ? 'Run a prediction to generate a risk score and recommendation.'\n : 'Try a different prediction type or run a new prediction.'\n }\n />\n ) : null}\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {pagination.pageItems.map((prediction, index) => {\n const risk = riskBandOf(prediction.score);\n const isTop = index === 0 && pagination.page === 1 && risk.band === 'high';\n const pending = prediction.status && prediction.status.toLowerCase() !== 'completed';\n const confidencePct = Math.round(prediction.confidence * 100);\n return (\n <GlassCard\n key={prediction.id}\n treatment=\"glass\"\n glow={isTop}\n className={cn('border-border-seam', isTop && 'ring-1 ring-status-error-border')}\n >\n <div className=\"flex h-full flex-col gap-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigate(`/assets/${prediction.assetId}`)}\n className=\"truncate text-left text-sm font-semibold text-text-primary hover:underline\"\n >\n {labelFor(prediction.assetId)}\n </button>\n <p className=\"text-xs text-text-secondary\">\n {humanizePredictionType(prediction.predictionType)}\n </p>\n </div>\n {pending ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <Loader2 className=\"h-3 w-3 motion-safe:animate-spin\" />\n Processing\n </span>\n ) : null}\n </div>\n\n <div className=\"flex items-center gap-3\">\n <div className=\"w-[120px] shrink-0\">\n <RadialGauge\n value={prediction.score * 100}\n tone={risk.tone}\n label={risk.label}\n height={110}\n format={(v) => `${Math.round(v)}%`}\n ariaLabel={`${risk.label} risk, ${Math.round(prediction.score * 100)} percent`}\n />\n </div>\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-xs text-text-secondary\">Confidence</p>\n <div className=\"flex items-center gap-2\">\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${confidencePct}%` }}\n />\n </div>\n <span className=\"text-xs font-medium tabular-nums text-text-primary\">\n {confidencePct}%\n </span>\n </div>\n </div>\n </div>\n\n <p className=\"flex-1 text-sm text-text-secondary\">{prediction.recommendation}</p>\n\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3\">\n <span className=\"truncate text-xs text-text-muted\">\n {prediction.modelVersion} ·{' '}\n {new Date(prediction.generatedAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate('/maintenance/maintenance-scheduler')}\n >\n <Wrench className=\"mr-1.5 h-3.5 w-3.5\" />\n Schedule\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {sorted.length > 0 ? (\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"predictions\"\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AiPredictionsPage.js","names":[],"sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"sourcesContent":["import type React from 'react';\nimport { BrainCircuit, Plus, Wrench, Loader2, BarChart3 } from 'lucide-react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n ChartCard,\n DonutChart,\n BarsChart,\n RadialGauge,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst AI_PREDICTIONS_QUERY = gql`\n query AssetHandlerAiPredictions {\n aiPredictions {\n id\n assetId\n predictionType\n score\n confidence\n recommendation\n features\n status\n generatedAt\n modelVersion\n }\n }\n`;\n\nconst REQUEST_AI_PREDICTION_MUTATION = gql`\n mutation AssetHandlerRequestAiPrediction($input: RequestAIPredictionInput!) {\n requestAIPrediction(input: $input) {\n id\n }\n }\n`;\n\ninterface AiPrediction {\n id: string;\n assetId: string;\n predictionType: string;\n score: number;\n confidence: number;\n recommendation: string;\n features: Record<string, unknown> | null;\n status: string;\n generatedAt: string;\n modelVersion: string;\n}\n\nconst PREDICTION_TYPES = [\n { value: 'maintenance-risk', label: 'Maintenance risk' },\n { value: 'failure-forecast', label: 'Failure forecast' },\n { value: 'utilization-forecast', label: 'Utilization forecast' },\n { value: 'anomaly-detection', label: 'Anomaly detection' },\n { value: 'end-of-life', label: 'End-of-life projection' },\n] as const;\n\nconst humanizePredictionType = (value: string): string =>\n PREDICTION_TYPES.find((t) => t.value === value)?.label ?? value.replace(/-/g, ' ');\n\ntype RiskBand = 'high' | 'medium' | 'low';\n\nfunction riskBandOf(score: number): {\n band: RiskBand;\n label: string;\n tone: 'danger' | 'warning' | 'success';\n} {\n if (score >= 0.66) return { band: 'high', label: 'High', tone: 'danger' };\n if (score >= 0.33) return { band: 'medium', label: 'Medium', tone: 'warning' };\n return { band: 'low', label: 'Low', tone: 'success' };\n}\n\n/** Extract numeric feature importances from the backend `features` JSONObject. */\nfunction featureBars(\n features: Record<string, unknown> | null | undefined\n): { name: string; importance: number }[] {\n if (!features) return [];\n return Object.entries(features)\n .map(([name, value]) => ({\n name,\n importance: typeof value === 'number' ? value : Number(value),\n }))\n .filter((f) => Number.isFinite(f.importance))\n .sort((a, b) => b.importance - a.importance)\n .slice(0, 8);\n}\n\nfunction RunPredictionDialog({\n open,\n onOpenChange,\n onRun,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onRun: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [assetId, setAssetId] = useState('');\n const [predictionType, setPredictionType] =\n useState<(typeof PREDICTION_TYPES)[number]['value']>('maintenance-risk');\n\n const [requestPrediction, { loading: requesting }] = useMutation(REQUEST_AI_PREDICTION_MUTATION, {\n onCompleted: () => {\n notify.success('Prediction requested', 'The model result will appear shortly.');\n onOpenChange(false);\n onRun();\n },\n onError: (error) => notify.error('Could not run prediction', error.message),\n });\n\n const handleRun = (event: React.FormEvent) => {\n event.preventDefault();\n if (!assetId) {\n notify.warning('Asset required', 'Select an asset to run a prediction against.');\n return;\n }\n void requestPrediction({ variables: { input: { assetId, predictionType } } });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Run Prediction</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Pick an asset and a model to forecast failure risk and get a recommended action.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-4\" onSubmit={handleRun}>\n <div className=\"space-y-2\">\n <Label>Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.assetTag} — {asset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Prediction Type</Label>\n <Select\n value={predictionType}\n onValueChange={(v) => setPredictionType(v as typeof predictionType)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={requesting}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={requesting}>\n {requesting ? 'Running…' : 'Run Prediction'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function AiPredictionsPage() {\n const assets = useAssetHandlerStore((s) => s.assets);\n const navigate = useAssetHandlerNavigate();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [typeFilter, setTypeFilter] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ aiPredictions: AiPrediction[] }>(\n AI_PREDICTIONS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const predictions = useMemo(() => data?.aiPredictions ?? [], [data?.aiPredictions]);\n\n const assetLabelById = useMemo(() => {\n const map = new Map<string, string>();\n for (const a of assets) map.set(a.id, `${a.assetTag} — ${a.name}`);\n return map;\n }, [assets]);\n\n const labelFor = (assetId: string): string =>\n assetLabelById.get(assetId) ?? `Asset ${assetId.slice(0, 8)}`;\n\n const sorted = useMemo(() => {\n const list =\n typeFilter === 'ALL'\n ? predictions\n : predictions.filter((p) => p.predictionType === typeFilter);\n return [...list].sort((a, b) => b.score - a.score);\n }, [predictions, typeFilter]);\n\n const riskMix = useMemo<DonutSlice[]>(() => {\n const counts: Record<RiskBand, number> = { high: 0, medium: 0, low: 0 };\n for (const p of predictions) counts[riskBandOf(p.score).band] += 1;\n const order: { band: RiskBand; label: string }[] = [\n { band: 'high', label: 'High' },\n { band: 'medium', label: 'Medium' },\n { band: 'low', label: 'Low' },\n ];\n return order\n .filter((o) => counts[o.band] > 0)\n .map((o, i) => ({ name: o.label, value: counts[o.band], color: seriesColor(i) }));\n }, [predictions]);\n\n // Feature importance is shown for the highest-risk prediction that carries features.\n const featureFocus = useMemo(() => {\n const withFeatures = sorted.find((p) => featureBars(p.features).length > 0);\n return withFeatures ?? null;\n }, [sorted]);\n const focusBars = featureBars(featureFocus?.features);\n\n const pagination = usePagination(sorted, { pageSize: 6, resetKey: typeFilter });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={BrainCircuit}\n title=\"AI Predictions\"\n description=\"Forecast failures before they happen and prioritise which assets to service next.\"\n actions={\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Run Prediction\n </Button>\n }\n />\n <PagePurpose>\n Pick an asset and a model to get a risk score, confidence level and a concrete\n recommendation — so you can schedule preventive maintenance instead of reacting to\n breakdowns.\n </PagePurpose>\n\n <RunPredictionDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onRun={() => void refetch()}\n />\n\n {predictions.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Risk distribution\" subtitle=\"Predicted failure risk across assets\">\n <DonutChart\n data={riskMix}\n height={210}\n centerLabel=\"Assets\"\n centerValue={predictions.length}\n ariaLabel=\"Risk distribution across predictions\"\n />\n </ChartCard>\n <ChartCard\n title=\"Feature importance\"\n subtitle={\n featureFocus\n ? `Top drivers · ${labelFor(featureFocus.assetId)}`\n : 'Model feature drivers'\n }\n icon={BarChart3}\n >\n {focusBars.length > 0 ? (\n <BarsChart\n data={focusBars}\n xKey=\"name\"\n series={[{ key: 'importance', label: 'Importance' }]}\n orientation=\"horizontal\"\n height={210}\n categoryWidth={140}\n ariaLabel=\"Feature importance\"\n />\n ) : (\n <div className=\"flex h-[210px] items-center justify-center px-4 text-center text-sm text-text-secondary\">\n Feature importance appears here once a model returns feature drivers.\n </div>\n )}\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Predicted failure risk per asset\n </h3>\n <div className=\"w-full sm:w-64\">\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Prediction type\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All prediction types</SelectItem>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {loading && predictions.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-56 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && sorted.length === 0 ? (\n <IllustratedEmptyState\n illustration={typeFilter === 'ALL' ? 'empty-data' : 'empty-search'}\n title={\n typeFilter === 'ALL' ? 'No AI predictions available yet' : 'No predictions of this type'\n }\n description={\n typeFilter === 'ALL'\n ? 'Run a prediction to generate a risk score and recommendation.'\n : 'Try a different prediction type or run a new prediction.'\n }\n />\n ) : null}\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {pagination.pageItems.map((prediction, index) => {\n const risk = riskBandOf(prediction.score);\n const isTop = index === 0 && pagination.page === 1 && risk.band === 'high';\n const pending = prediction.status && prediction.status.toLowerCase() !== 'completed';\n const confidencePct = Math.round(prediction.confidence * 100);\n return (\n <GlassCard\n key={prediction.id}\n treatment=\"glass\"\n glow={isTop}\n className={cn('border-border-seam', isTop && 'ring-1 ring-status-error-border')}\n >\n <div className=\"flex h-full flex-col gap-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigate(`/assets/${prediction.assetId}`)}\n className=\"truncate text-left text-sm font-semibold text-text-primary hover:underline\"\n >\n {labelFor(prediction.assetId)}\n </button>\n <p className=\"text-xs text-text-secondary\">\n {humanizePredictionType(prediction.predictionType)}\n </p>\n </div>\n {pending ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <Loader2 className=\"h-3 w-3 motion-safe:animate-spin\" />\n Processing\n </span>\n ) : null}\n </div>\n\n <div className=\"flex items-center gap-3\">\n <div className=\"w-[120px] shrink-0\">\n <RadialGauge\n value={prediction.score * 100}\n tone={risk.tone}\n label={risk.label}\n height={110}\n format={(v) => `${Math.round(v)}%`}\n ariaLabel={`${risk.label} risk, ${Math.round(prediction.score * 100)} percent`}\n />\n </div>\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-xs text-text-secondary\">Confidence</p>\n <div className=\"flex items-center gap-2\">\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${confidencePct}%` }}\n />\n </div>\n <span className=\"text-xs font-medium tabular-nums text-text-primary\">\n {confidencePct}%\n </span>\n </div>\n </div>\n </div>\n\n <p className=\"flex-1 text-sm text-text-secondary\">{prediction.recommendation}</p>\n\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3\">\n <span className=\"truncate text-xs text-text-muted\">\n {prediction.modelVersion} ·{' '}\n {new Date(prediction.generatedAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate('/maintenance/maintenance-scheduler')}\n >\n <Wrench className=\"mr-1.5 h-3.5 w-3.5\" />\n Schedule\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {sorted.length > 0 ? (\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"predictions\"\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}