@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.
- package/dist/_virtual/_rolldown/runtime.js +1 -1
- package/dist/assethandler/AssetHandlerRoot.js.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
- package/dist/assethandler/components/ActivityTimeline.js.map +1 -1
- package/dist/assethandler/components/AttachmentsPanel.js.map +1 -1
- package/dist/assethandler/components/ChartCard.js.map +1 -1
- package/dist/assethandler/components/CommentsPanel.js.map +1 -1
- package/dist/assethandler/components/NotFoundState.js.map +1 -1
- package/dist/assethandler/components/Pagination.js.map +1 -1
- package/dist/assethandler/components/SectionHeader.js.map +1 -1
- package/dist/assethandler/components/StatTile.js.map +1 -1
- package/dist/assethandler/components/charts/BarsChart.js.map +1 -1
- package/dist/assethandler/components/charts/ChartParts.js.map +1 -1
- package/dist/assethandler/components/charts/DonutChart.js.map +1 -1
- package/dist/assethandler/components/charts/ProgressMeter.js.map +1 -1
- package/dist/assethandler/components/charts/RadialGauge.js.map +1 -1
- package/dist/assethandler/components/charts/Sparkline.js.map +1 -1
- package/dist/assethandler/components/charts/TrendChart.js.map +1 -1
- package/dist/assethandler/components/charts/chartTheme.js.map +1 -1
- package/dist/assethandler/hooks/useAssetHandlerNavigate.js.map +1 -1
- package/dist/assethandler/hooks/useCopy.js.map +1 -1
- package/dist/assethandler/hooks/useMaintenancePlans.js.map +1 -1
- package/dist/assethandler/ops/MaintenancePlanDialog.js.map +1 -1
- package/dist/assethandler/ops/NewWorkOrderDialog.js.map +1 -1
- package/dist/assethandler/ops/ScheduleMaintenanceDialog.js.map +1 -1
- package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
- package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
- package/dist/assethandler/pages/CmdbBrowserPage.js.map +1 -1
- package/dist/assethandler/pages/DashboardPage.js.map +1 -1
- package/dist/assethandler/pages/DigitalTwinPage.js.map +1 -1
- package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
- package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceInvoiceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/IotDevicesPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilDialogs.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemManagementPage.js.map +1 -1
- package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.d.ts.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenancePlansPage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
- package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
- package/dist/assethandler/pages/ProvenancePage.js.map +1 -1
- package/dist/assethandler/pages/ReportsDashboardPage.js.map +1 -1
- package/dist/assethandler/pages/SamLicensesPage.js.map +1 -1
- package/dist/assethandler/pages/SecurityComplianceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecurityPolicyDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityEventDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionListPage.js.map +1 -1
- package/dist/assethandler/providers/AssetHandlerProvider.js.map +1 -1
- package/dist/assethandler/store/assethandlerStore.js.map +1 -1
- package/dist/assethandler/utils/categoryPresentation.js.map +1 -1
- package/dist/assethandler/utils/cn.js.map +1 -1
- package/dist/assethandler/utils/csv.js.map +1 -1
- package/dist/assethandler/utils/i18n.js.map +1 -1
- package/dist/assethandler/utils/knowledgeBase.js.map +1 -1
- package/dist/assethandler/utils/meter.js.map +1 -1
- package/dist/assethandler/utils/money.js.map +1 -1
- package/dist/assethandler/utils/navigation.js.map +1 -1
- package/dist/assethandler/utils/printAssetTag.js.map +1 -1
- package/dist/assethandler/utils/toast.js.map +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
- package/dist/node_modules/d3-array/src/ascending.js.map +1 -1
- package/dist/node_modules/d3-array/src/bisect.js.map +1 -1
- package/dist/node_modules/d3-array/src/bisector.js.map +1 -1
- package/dist/node_modules/d3-array/src/descending.js.map +1 -1
- package/dist/node_modules/d3-array/src/max.js.map +1 -1
- package/dist/node_modules/d3-array/src/min.js.map +1 -1
- package/dist/node_modules/d3-array/src/number.js.map +1 -1
- package/dist/node_modules/d3-array/src/quantile.js.map +1 -1
- package/dist/node_modules/d3-array/src/quickselect.js.map +1 -1
- package/dist/node_modules/d3-array/src/range.js.map +1 -1
- package/dist/node_modules/d3-array/src/sort.js.map +1 -1
- package/dist/node_modules/d3-array/src/ticks.js.map +1 -1
- package/dist/node_modules/d3-color/src/color.js.map +1 -1
- package/dist/node_modules/d3-color/src/define.js.map +1 -1
- package/dist/node_modules/d3-format/src/defaultLocale.js.map +1 -1
- package/dist/node_modules/d3-format/src/exponent.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatDecimal.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatGroup.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatNumerals.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatPrefixAuto.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatRounded.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatSpecifier.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatTrim.js.map +1 -1
- package/dist/node_modules/d3-format/src/formatTypes.js.map +1 -1
- package/dist/node_modules/d3-format/src/identity.js.map +1 -1
- package/dist/node_modules/d3-format/src/locale.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionFixed.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionPrefix.js.map +1 -1
- package/dist/node_modules/d3-format/src/precisionRound.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/array.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/basis.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/basisClosed.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/color.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/date.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/number.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/numberArray.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/object.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/piecewise.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/rgb.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/round.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/string.js.map +1 -1
- package/dist/node_modules/d3-interpolate/src/value.js.map +1 -1
- package/dist/node_modules/d3-path/src/path.js.map +1 -1
- package/dist/node_modules/d3-scale/src/band.js.map +1 -1
- package/dist/node_modules/d3-scale/src/constant.js.map +1 -1
- package/dist/node_modules/d3-scale/src/continuous.js.map +1 -1
- package/dist/node_modules/d3-scale/src/diverging.js.map +1 -1
- package/dist/node_modules/d3-scale/src/identity.js.map +1 -1
- package/dist/node_modules/d3-scale/src/init.js.map +1 -1
- package/dist/node_modules/d3-scale/src/linear.js.map +1 -1
- package/dist/node_modules/d3-scale/src/log.js.map +1 -1
- package/dist/node_modules/d3-scale/src/nice.js.map +1 -1
- package/dist/node_modules/d3-scale/src/number.js.map +1 -1
- package/dist/node_modules/d3-scale/src/ordinal.js.map +1 -1
- package/dist/node_modules/d3-scale/src/pow.js.map +1 -1
- package/dist/node_modules/d3-scale/src/quantile.js.map +1 -1
- package/dist/node_modules/d3-scale/src/quantize.js.map +1 -1
- package/dist/node_modules/d3-scale/src/radial.js.map +1 -1
- package/dist/node_modules/d3-scale/src/sequential.js.map +1 -1
- package/dist/node_modules/d3-scale/src/sequentialQuantile.js.map +1 -1
- package/dist/node_modules/d3-scale/src/symlog.js.map +1 -1
- package/dist/node_modules/d3-scale/src/threshold.js.map +1 -1
- package/dist/node_modules/d3-scale/src/tickFormat.js.map +1 -1
- package/dist/node_modules/d3-scale/src/time.js.map +1 -1
- package/dist/node_modules/d3-scale/src/utcTime.js.map +1 -1
- package/dist/node_modules/d3-shape/src/area.js.map +1 -1
- package/dist/node_modules/d3-shape/src/array.js.map +1 -1
- package/dist/node_modules/d3-shape/src/constant.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basis.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basisClosed.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/basisOpen.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/bump.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/linear.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/linearClosed.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/monotone.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/natural.js.map +1 -1
- package/dist/node_modules/d3-shape/src/curve/step.js.map +1 -1
- package/dist/node_modules/d3-shape/src/line.js.map +1 -1
- package/dist/node_modules/d3-shape/src/noop.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/expand.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/none.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/silhouette.js.map +1 -1
- package/dist/node_modules/d3-shape/src/offset/wiggle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/order/none.js.map +1 -1
- package/dist/node_modules/d3-shape/src/path.js.map +1 -1
- package/dist/node_modules/d3-shape/src/point.js.map +1 -1
- package/dist/node_modules/d3-shape/src/stack.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/circle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/cross.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/diamond.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/square.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/star.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/triangle.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol/wye.js.map +1 -1
- package/dist/node_modules/d3-shape/src/symbol.js.map +1 -1
- package/dist/node_modules/d3-time/src/day.js.map +1 -1
- package/dist/node_modules/d3-time/src/hour.js.map +1 -1
- package/dist/node_modules/d3-time/src/interval.js.map +1 -1
- package/dist/node_modules/d3-time/src/millisecond.js.map +1 -1
- package/dist/node_modules/d3-time/src/minute.js.map +1 -1
- package/dist/node_modules/d3-time/src/month.js.map +1 -1
- package/dist/node_modules/d3-time/src/second.js.map +1 -1
- package/dist/node_modules/d3-time/src/ticks.js.map +1 -1
- package/dist/node_modules/d3-time/src/week.js.map +1 -1
- package/dist/node_modules/d3-time/src/year.js.map +1 -1
- package/dist/node_modules/d3-time-format/src/defaultLocale.js.map +1 -1
- package/dist/node_modules/d3-time-format/src/locale.js.map +1 -1
- package/dist/node_modules/decimal.js-light/decimal.js.map +1 -1
- package/dist/node_modules/dijkstrajs/dijkstra.js.map +1 -1
- package/dist/node_modules/eventemitter3/index.js.map +1 -1
- package/dist/node_modules/fast-equals/dist/es/index.js.map +1 -1
- package/dist/node_modules/internmap/src/index.js.map +1 -1
- package/dist/node_modules/lodash/_DataView.js.map +1 -1
- package/dist/node_modules/lodash/_Hash.js.map +1 -1
- package/dist/node_modules/lodash/_ListCache.js.map +1 -1
- package/dist/node_modules/lodash/_Map.js.map +1 -1
- package/dist/node_modules/lodash/_MapCache.js.map +1 -1
- package/dist/node_modules/lodash/_Promise.js.map +1 -1
- package/dist/node_modules/lodash/_Set.js.map +1 -1
- package/dist/node_modules/lodash/_SetCache.js.map +1 -1
- package/dist/node_modules/lodash/_Stack.js +2 -1
- package/dist/node_modules/lodash/_Stack.js.map +1 -1
- package/dist/node_modules/lodash/_Symbol.js.map +1 -1
- package/dist/node_modules/lodash/_Uint8Array.js.map +1 -1
- package/dist/node_modules/lodash/_WeakMap.js.map +1 -1
- package/dist/node_modules/lodash/_apply.js.map +1 -1
- package/dist/node_modules/lodash/_arrayEvery.js.map +1 -1
- package/dist/node_modules/lodash/_arrayFilter.js.map +1 -1
- package/dist/node_modules/lodash/_arrayIncludes.js.map +1 -1
- package/dist/node_modules/lodash/_arrayIncludesWith.js.map +1 -1
- package/dist/node_modules/lodash/_arrayLikeKeys.js.map +1 -1
- package/dist/node_modules/lodash/_arrayMap.js.map +1 -1
- package/dist/node_modules/lodash/_arrayPush.js.map +1 -1
- package/dist/node_modules/lodash/_arraySome.js.map +1 -1
- package/dist/node_modules/lodash/_asciiToArray.js.map +1 -1
- package/dist/node_modules/lodash/_assocIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_baseAssignValue.js.map +1 -1
- package/dist/node_modules/lodash/_baseEach.js.map +1 -1
- package/dist/node_modules/lodash/_baseEvery.js.map +1 -1
- package/dist/node_modules/lodash/_baseExtremum.js.map +1 -1
- package/dist/node_modules/lodash/_baseFindIndex.js.map +1 -1
- package/dist/node_modules/lodash/_baseFlatten.js.map +1 -1
- package/dist/node_modules/lodash/_baseFor.js.map +1 -1
- package/dist/node_modules/lodash/_baseForOwn.js.map +1 -1
- package/dist/node_modules/lodash/_baseGet.js.map +1 -1
- package/dist/node_modules/lodash/_baseGetAllKeys.js.map +1 -1
- package/dist/node_modules/lodash/_baseGetTag.js.map +1 -1
- package/dist/node_modules/lodash/_baseGt.js.map +1 -1
- package/dist/node_modules/lodash/_baseHasIn.js.map +1 -1
- package/dist/node_modules/lodash/_baseIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsArguments.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsEqual.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsEqualDeep.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsMatch.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsNaN.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsNative.js.map +1 -1
- package/dist/node_modules/lodash/_baseIsTypedArray.js.map +1 -1
- package/dist/node_modules/lodash/_baseIteratee.js.map +1 -1
- package/dist/node_modules/lodash/_baseKeys.js.map +1 -1
- package/dist/node_modules/lodash/_baseLt.js.map +1 -1
- package/dist/node_modules/lodash/_baseMap.js.map +1 -1
- package/dist/node_modules/lodash/_baseMatches.js.map +1 -1
- package/dist/node_modules/lodash/_baseMatchesProperty.js.map +1 -1
- package/dist/node_modules/lodash/_baseOrderBy.js.map +1 -1
- package/dist/node_modules/lodash/_baseProperty.js.map +1 -1
- package/dist/node_modules/lodash/_basePropertyDeep.js.map +1 -1
- package/dist/node_modules/lodash/_baseRange.js.map +1 -1
- package/dist/node_modules/lodash/_baseRest.js.map +1 -1
- package/dist/node_modules/lodash/_baseSetToString.js.map +1 -1
- package/dist/node_modules/lodash/_baseSlice.js.map +1 -1
- package/dist/node_modules/lodash/_baseSome.js.map +1 -1
- package/dist/node_modules/lodash/_baseSortBy.js.map +1 -1
- package/dist/node_modules/lodash/_baseTimes.js.map +1 -1
- package/dist/node_modules/lodash/_baseToString.js.map +1 -1
- package/dist/node_modules/lodash/_baseTrim.js.map +1 -1
- package/dist/node_modules/lodash/_baseUnary.js.map +1 -1
- package/dist/node_modules/lodash/_baseUniq.js.map +1 -1
- package/dist/node_modules/lodash/_cacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_castPath.js.map +1 -1
- package/dist/node_modules/lodash/_castSlice.js.map +1 -1
- package/dist/node_modules/lodash/_compareAscending.js.map +1 -1
- package/dist/node_modules/lodash/_compareMultiple.js.map +1 -1
- package/dist/node_modules/lodash/_coreJsData.js.map +1 -1
- package/dist/node_modules/lodash/_createBaseEach.js.map +1 -1
- package/dist/node_modules/lodash/_createBaseFor.js.map +1 -1
- package/dist/node_modules/lodash/_createCaseFirst.js.map +1 -1
- package/dist/node_modules/lodash/_createFind.js.map +1 -1
- package/dist/node_modules/lodash/_createRange.js.map +1 -1
- package/dist/node_modules/lodash/_createSet.js.map +1 -1
- package/dist/node_modules/lodash/_defineProperty.js.map +1 -1
- package/dist/node_modules/lodash/_equalArrays.js.map +1 -1
- package/dist/node_modules/lodash/_equalByTag.js.map +1 -1
- package/dist/node_modules/lodash/_equalObjects.js.map +1 -1
- package/dist/node_modules/lodash/_freeGlobal.js.map +1 -1
- package/dist/node_modules/lodash/_getAllKeys.js.map +1 -1
- package/dist/node_modules/lodash/_getMapData.js.map +1 -1
- package/dist/node_modules/lodash/_getMatchData.js.map +1 -1
- package/dist/node_modules/lodash/_getNative.js.map +1 -1
- package/dist/node_modules/lodash/_getPrototype.js.map +1 -1
- package/dist/node_modules/lodash/_getRawTag.js.map +1 -1
- package/dist/node_modules/lodash/_getSymbols.js.map +1 -1
- package/dist/node_modules/lodash/_getTag.js.map +1 -1
- package/dist/node_modules/lodash/_getValue.js.map +1 -1
- package/dist/node_modules/lodash/_hasPath.js.map +1 -1
- package/dist/node_modules/lodash/_hasUnicode.js.map +1 -1
- package/dist/node_modules/lodash/_hashClear.js.map +1 -1
- package/dist/node_modules/lodash/_hashDelete.js.map +1 -1
- package/dist/node_modules/lodash/_hashGet.js.map +1 -1
- package/dist/node_modules/lodash/_hashHas.js.map +1 -1
- package/dist/node_modules/lodash/_hashSet.js.map +1 -1
- package/dist/node_modules/lodash/_isFlattenable.js.map +1 -1
- package/dist/node_modules/lodash/_isIndex.js.map +1 -1
- package/dist/node_modules/lodash/_isIterateeCall.js.map +1 -1
- package/dist/node_modules/lodash/_isKey.js.map +1 -1
- package/dist/node_modules/lodash/_isKeyable.js.map +1 -1
- package/dist/node_modules/lodash/_isMasked.js.map +1 -1
- package/dist/node_modules/lodash/_isPrototype.js.map +1 -1
- package/dist/node_modules/lodash/_isStrictComparable.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheClear.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheDelete.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheGet.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_listCacheSet.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheClear.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheDelete.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheGet.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_mapCacheSet.js.map +1 -1
- package/dist/node_modules/lodash/_mapToArray.js.map +1 -1
- package/dist/node_modules/lodash/_matchesStrictComparable.js.map +1 -1
- package/dist/node_modules/lodash/_memoizeCapped.js.map +1 -1
- package/dist/node_modules/lodash/_nativeCreate.js.map +1 -1
- package/dist/node_modules/lodash/_nativeKeys.js.map +1 -1
- package/dist/node_modules/lodash/_nodeUtil.js.map +1 -1
- package/dist/node_modules/lodash/_objectToString.js.map +1 -1
- package/dist/node_modules/lodash/_overArg.js.map +1 -1
- package/dist/node_modules/lodash/_overRest.js.map +1 -1
- package/dist/node_modules/lodash/_root.js.map +1 -1
- package/dist/node_modules/lodash/_setCacheAdd.js.map +1 -1
- package/dist/node_modules/lodash/_setCacheHas.js.map +1 -1
- package/dist/node_modules/lodash/_setToArray.js.map +1 -1
- package/dist/node_modules/lodash/_setToString.js.map +1 -1
- package/dist/node_modules/lodash/_shortOut.js.map +1 -1
- package/dist/node_modules/lodash/_stackClear.js.map +1 -1
- package/dist/node_modules/lodash/_stackDelete.js.map +1 -1
- package/dist/node_modules/lodash/_stackGet.js.map +1 -1
- package/dist/node_modules/lodash/_stackHas.js.map +1 -1
- package/dist/node_modules/lodash/_stackSet.js.map +1 -1
- package/dist/node_modules/lodash/_strictIndexOf.js.map +1 -1
- package/dist/node_modules/lodash/_stringToArray.js.map +1 -1
- package/dist/node_modules/lodash/_stringToPath.js.map +1 -1
- package/dist/node_modules/lodash/_toKey.js.map +1 -1
- package/dist/node_modules/lodash/_toSource.js.map +1 -1
- package/dist/node_modules/lodash/_trimmedEndIndex.js.map +1 -1
- package/dist/node_modules/lodash/_unicodeToArray.js.map +1 -1
- package/dist/node_modules/lodash/constant.js.map +1 -1
- package/dist/node_modules/lodash/debounce.js.map +1 -1
- package/dist/node_modules/lodash/eq.js.map +1 -1
- package/dist/node_modules/lodash/every.js.map +1 -1
- package/dist/node_modules/lodash/find.js.map +1 -1
- package/dist/node_modules/lodash/findIndex.js.map +1 -1
- package/dist/node_modules/lodash/flatMap.js.map +1 -1
- package/dist/node_modules/lodash/get.js.map +1 -1
- package/dist/node_modules/lodash/hasIn.js.map +1 -1
- package/dist/node_modules/lodash/identity.js.map +1 -1
- package/dist/node_modules/lodash/isArguments.js.map +1 -1
- package/dist/node_modules/lodash/isArray.js.map +1 -1
- package/dist/node_modules/lodash/isArrayLike.js.map +1 -1
- package/dist/node_modules/lodash/isBoolean.js.map +1 -1
- package/dist/node_modules/lodash/isBuffer.js.map +1 -1
- package/dist/node_modules/lodash/isEqual.js.map +1 -1
- package/dist/node_modules/lodash/isFunction.js.map +1 -1
- package/dist/node_modules/lodash/isLength.js.map +1 -1
- package/dist/node_modules/lodash/isNaN.js.map +1 -1
- package/dist/node_modules/lodash/isNil.js.map +1 -1
- package/dist/node_modules/lodash/isNumber.js.map +1 -1
- package/dist/node_modules/lodash/isObject.js.map +1 -1
- package/dist/node_modules/lodash/isObjectLike.js.map +1 -1
- package/dist/node_modules/lodash/isPlainObject.js.map +1 -1
- package/dist/node_modules/lodash/isString.js.map +1 -1
- package/dist/node_modules/lodash/isSymbol.js.map +1 -1
- package/dist/node_modules/lodash/isTypedArray.js.map +1 -1
- package/dist/node_modules/lodash/keys.js.map +1 -1
- package/dist/node_modules/lodash/last.js.map +1 -1
- package/dist/node_modules/lodash/map.js.map +1 -1
- package/dist/node_modules/lodash/mapValues.js.map +1 -1
- package/dist/node_modules/lodash/max.js.map +1 -1
- package/dist/node_modules/lodash/maxBy.js.map +1 -1
- package/dist/node_modules/lodash/memoize.js.map +1 -1
- package/dist/node_modules/lodash/min.js.map +1 -1
- package/dist/node_modules/lodash/minBy.js.map +1 -1
- package/dist/node_modules/lodash/noop.js.map +1 -1
- package/dist/node_modules/lodash/now.js.map +1 -1
- package/dist/node_modules/lodash/property.js.map +1 -1
- package/dist/node_modules/lodash/range.js.map +1 -1
- package/dist/node_modules/lodash/some.js.map +1 -1
- package/dist/node_modules/lodash/sortBy.js.map +1 -1
- package/dist/node_modules/lodash/stubArray.js.map +1 -1
- package/dist/node_modules/lodash/stubFalse.js.map +1 -1
- package/dist/node_modules/lodash/throttle.js.map +1 -1
- package/dist/node_modules/lodash/toFinite.js.map +1 -1
- package/dist/node_modules/lodash/toInteger.js.map +1 -1
- package/dist/node_modules/lodash/toNumber.js.map +1 -1
- package/dist/node_modules/lodash/toString.js.map +1 -1
- package/dist/node_modules/lodash/uniqBy.js.map +1 -1
- package/dist/node_modules/lodash/upperFirst.js.map +1 -1
- package/dist/node_modules/object-assign/index.js.map +1 -1
- package/dist/node_modules/prop-types/checkPropTypes.js.map +1 -1
- package/dist/node_modules/prop-types/factoryWithThrowingShims.js.map +1 -1
- package/dist/node_modules/prop-types/factoryWithTypeCheckers.js.map +1 -1
- package/dist/node_modules/prop-types/index.js.map +1 -1
- package/dist/node_modules/prop-types/lib/ReactPropTypesSecret.js.map +1 -1
- package/dist/node_modules/prop-types/lib/has.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.development.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
- package/dist/node_modules/prop-types/node_modules/react-is/index.js.map +1 -1
- package/dist/node_modules/qrcode/lib/browser.js.map +1 -1
- package/dist/node_modules/qrcode/lib/can-promise.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/alignment-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/alphanumeric-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/bit-buffer.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/bit-matrix.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/byte-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/error-correction-code.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/error-correction-level.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/finder-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/format-info.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/galois-field.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/kanji-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/mask-pattern.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/mode.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/numeric-data.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/polynomial.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/qrcode.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/reed-solomon-encoder.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/regex.js +1 -1
- package/dist/node_modules/qrcode/lib/core/regex.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/segments.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/utils.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/version-check.js.map +1 -1
- package/dist/node_modules/qrcode/lib/core/version.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/canvas.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/svg-tag.js.map +1 -1
- package/dist/node_modules/qrcode/lib/renderer/utils.js.map +1 -1
- package/dist/node_modules/react-is/cjs/react-is.development.js.map +1 -1
- package/dist/node_modules/react-is/cjs/react-is.production.min.js.map +1 -1
- package/dist/node_modules/react-is/index.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
- package/dist/node_modules/react-smooth/es6/Animate.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/AnimateManager.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/configUpdate.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/easing.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/setRafTimeout.js.map +1 -1
- package/dist/node_modules/react-smooth/es6/util.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Area.js +13 -13
- package/dist/node_modules/recharts/es6/cartesian/Area.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
- package/dist/node_modules/recharts/es6/cartesian/Bar.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
- package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
- package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
- package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
- package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/Line.js +10 -10
- package/dist/node_modules/recharts/es6/cartesian/Line.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
- package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
- package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/getEquidistantTicks.js.map +1 -1
- package/dist/node_modules/recharts/es6/cartesian/getTicks.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
- package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/AreaChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/LineChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/PieChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/RadialBarChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
- package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Cell.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
- package/dist/node_modules/recharts/es6/component/Cursor.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
- package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
- package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Label.js +14 -14
- package/dist/node_modules/recharts/es6/component/Label.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
- package/dist/node_modules/recharts/es6/component/LabelList.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
- package/dist/node_modules/recharts/es6/component/Legend.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
- package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Text.js +2 -2
- package/dist/node_modules/recharts/es6/component/Text.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
- package/dist/node_modules/recharts/es6/component/Tooltip.js.map +1 -1
- package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
- package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js.map +1 -1
- package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
- package/dist/node_modules/recharts/es6/container/Layer.js.map +1 -1
- package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
- package/dist/node_modules/recharts/es6/container/Surface.js.map +1 -1
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
- package/dist/node_modules/recharts/es6/context/chartLayoutContext.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/Pie.js +13 -13
- package/dist/node_modules/recharts/es6/polar/Pie.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
- package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
- package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js.map +1 -1
- package/dist/node_modules/recharts/es6/polar/RadialBar.js +6 -6
- package/dist/node_modules/recharts/es6/polar/RadialBar.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Cross.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Curve.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Dot.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Polygon.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Rectangle.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Sector.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
- package/dist/node_modules/recharts/es6/shape/Symbols.js.map +1 -1
- package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
- package/dist/node_modules/recharts/es6/shape/Trapezoid.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
- package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/BarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/CartesianUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ChartUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/CssPrefixUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DOMUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DataUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/DetectReferenceElementsDomain.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/Events.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/Global.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/IfOverflowMatches.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/LogUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/PolarUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/RadialBarUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/RadialBarUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ReactUtils.js +1 -1
- package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
- package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/ShallowEqual.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/TickUtils.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/calculateViewBox.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getCursorPoints.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getCursorRectangle.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/cursor/getRadialCursorPoints.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/getEveryNthWithCondition.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/getLegendProps.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/isDomainSpecifiedByUser.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/payload/getUniqPayload.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/tooltip/translate.js.map +1 -1
- package/dist/node_modules/recharts/es6/util/types.js +1 -1
- package/dist/node_modules/recharts/es6/util/types.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/getNiceTickValues.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/util/arithmetic.js.map +1 -1
- package/dist/node_modules/recharts-scale/es6/util/utils.js.map +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
- package/dist/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +4 -4
- package/dist/generated/global-operations.d.ts +0 -2
- package/dist/generated/global-operations.d.ts.map +0 -1
- package/dist/generated/global-types.d.ts +0 -23527
- package/dist/generated/global-types.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IotDevicesPage.js","names":[],"sources":["../../../src/assethandler/pages/IotDevicesPage.tsx"],"sourcesContent":["import {\n Cpu,\n Plus,\n Search,\n Radio,\n Router,\n ToggleRight,\n MapPin,\n Wifi,\n WifiOff,\n Activity,\n LayoutGrid,\n Table as TableIcon,\n ExternalLink,\n type LucideIcon,\n} from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\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 { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Pagination,\n usePagination,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n} from '../components';\nimport { notify } from '../utils/toast';\nimport { cn } from '../utils/cn';\n\nconst IOT_DEVICES_QUERY = gql`\n query AssetHandlerIoTDevices {\n iotDevices {\n id\n deviceId\n name\n type\n protocol\n status\n assetId\n updatedAt\n }\n }\n`;\n\nconst REGISTER_IOT_DEVICE_MUTATION = gql`\n mutation AssetHandlerRegisterIoTDevice($input: RegisterIoTDeviceInput!) {\n registerIoTDevice(input: $input) {\n id\n deviceId\n }\n }\n`;\n\ninterface IoTDevice {\n id: string;\n deviceId: string;\n name: string;\n type: string;\n protocol: string;\n status: string;\n assetId: string | null;\n updatedAt: string;\n}\n\ninterface RegisterIoTDeviceResult {\n registerIoTDevice: { id: string; deviceId: string };\n}\n\nconst DEVICE_TYPES = ['SENSOR', 'GATEWAY', 'ACTUATOR', 'TRACKER', 'CONTROLLER'] as const;\nconst PROTOCOLS = ['MQTT', 'COAP', 'HTTP', 'MODBUS', 'ZIGBEE', 'LORAWAN'] as const;\nconst DEVICE_STATUSES = ['ONLINE', 'OFFLINE', 'DEGRADED', 'PROVISIONING'] as const;\n\ntype Tone = 'success' | 'warning' | 'error' | 'info' | 'neutral';\n\nconst TONE_PILL: Record<Tone, string> = {\n success: 'bg-status-success-subtle text-status-success-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n error: 'bg-status-error-subtle text-status-error-text',\n info: 'bg-status-info-subtle text-status-info-text',\n neutral: 'bg-status-neutral-bg-subtle text-status-neutral-text',\n};\n\nconst statusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'online') return 'success';\n if (s === 'degraded') return 'warning';\n if (s === 'provisioning') return 'info';\n return 'neutral';\n};\n\nconst TYPE_ICON: Record<string, LucideIcon> = {\n SENSOR: Radio,\n GATEWAY: Router,\n ACTUATOR: ToggleRight,\n TRACKER: MapPin,\n CONTROLLER: Cpu,\n};\n\nconst humanize = (value: string) => value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();\n\nfunction relativeTime(iso: string): string {\n const then = new Date(iso).getTime();\n if (!Number.isFinite(then)) return '—';\n const diff = Date.now() - then;\n const mins = Math.round(diff / 60000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.round(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n const days = Math.round(hrs / 24);\n if (days < 30) return `${days}d ago`;\n return new Date(iso).toLocaleDateString();\n}\n\nfunction StatusPill({ status }: { status: string }) {\n const s = status.toLowerCase();\n const tone = statusTone(status);\n const Icon = s === 'online' ? Wifi : s === 'offline' ? WifiOff : Activity;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',\n TONE_PILL[tone]\n )}\n >\n <Icon className=\"h-3 w-3\" aria-hidden=\"true\" />\n {s}\n </span>\n );\n}\n\nfunction RegisterDeviceDialog({\n open,\n onOpenChange,\n onRegistered,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onRegistered: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [deviceId, setDeviceId] = useState('');\n const [name, setName] = useState('');\n const [type, setType] = useState<(typeof DEVICE_TYPES)[number]>('SENSOR');\n const [protocol, setProtocol] = useState<(typeof PROTOCOLS)[number]>('MQTT');\n const [status, setStatus] = useState<(typeof DEVICE_STATUSES)[number]>('PROVISIONING');\n const [assetId, setAssetId] = useState('');\n\n const reset = () => {\n setDeviceId('');\n setName('');\n setType('SENSOR');\n setProtocol('MQTT');\n setStatus('PROVISIONING');\n setAssetId('');\n };\n\n const [registerDevice, { loading }] = useMutation<RegisterIoTDeviceResult>(\n REGISTER_IOT_DEVICE_MUTATION,\n {\n onCompleted: (data) => {\n notify.success('Device registered', `${data.registerIoTDevice.deviceId} is now tracked.`);\n reset();\n onOpenChange(false);\n onRegistered();\n },\n onError: (error) => notify.error('Could not register device', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!deviceId.trim() || !name.trim()) {\n notify.warning('Missing details', 'Device ID and name are required.');\n return;\n }\n void registerDevice({\n variables: {\n input: {\n deviceId: deviceId.trim(),\n name: name.trim(),\n type,\n protocol,\n status,\n assetId: assetId || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Register IoT Device</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Onboard a connected device and optionally link it to an asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Device ID *</Label>\n <Input\n placeholder=\"e.g., dev-8821\"\n value={deviceId}\n onChange={(e) => setDeviceId(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input value={name} onChange={(e) => setName(e.target.value)} />\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 {DEVICE_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {t}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Protocol</Label>\n <Select value={protocol} onValueChange={(v) => setProtocol(v as typeof protocol)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PROTOCOLS.map((p) => (\n <SelectItem key={p} value={p}>\n {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 {DEVICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Linked Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Unlinked\" />\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>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? 'Registering…' : 'Register device'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function IotDevicesPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [view, setView] = useState<'grid' | 'table'>('grid');\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<string>('all');\n const navigate = useAssetHandlerNavigate();\n const assets = useAssetHandlerStore((s) => s.assets);\n\n const { data, loading, refetch } = useQuery<{ iotDevices: IoTDevice[] }>(IOT_DEVICES_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const devices = useMemo(() => data?.iotDevices ?? [], [data]);\n\n const assetById = useMemo(() => {\n const map = new Map<string, { assetTag: string; name: string }>();\n for (const a of assets) map.set(a.id, { assetTag: a.assetTag, name: a.name });\n return map;\n }, [assets]);\n\n // ─── Fleet health (real counts) ───\n const counts = useMemo(() => {\n const byStatus = { online: 0, offline: 0, degraded: 0, provisioning: 0 };\n for (const d of devices) {\n const s = d.status.toLowerCase();\n if (s === 'online') byStatus.online += 1;\n else if (s === 'degraded') byStatus.degraded += 1;\n else if (s === 'provisioning') byStatus.provisioning += 1;\n else byStatus.offline += 1;\n }\n return byStatus;\n }, [devices]);\n\n const statusDonut = useMemo(() => {\n const order: { key: keyof typeof counts; label: string; color: string }[] = [\n { key: 'online', label: 'Online', color: 'var(--color-status-success-bg)' },\n { key: 'offline', label: 'Offline', color: 'var(--color-status-neutral-bg)' },\n { key: 'degraded', label: 'Degraded', color: 'var(--color-status-warning-bg)' },\n { key: 'provisioning', label: 'Provisioning', color: 'var(--color-status-info-bg)' },\n ];\n return order\n .filter((o) => counts[o.key] > 0)\n .map((o) => ({ name: o.label, value: counts[o.key], color: o.color }));\n }, [counts]);\n\n const typeBars = useMemo(() => {\n const map = new Map<string, number>();\n for (const d of devices) map.set(d.type, (map.get(d.type) ?? 0) + 1);\n return [...map.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([type, value]) => ({ name: humanize(type), count: value }));\n }, [devices]);\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n return devices.filter((d) => {\n if (statusFilter !== 'all' && d.status.toLowerCase() !== statusFilter) return false;\n if (!q) return true;\n return d.deviceId.toLowerCase().includes(q) || d.name.toLowerCase().includes(q);\n });\n }, [devices, search, statusFilter]);\n\n const pagination = usePagination(filtered, {\n pageSize: view === 'grid' ? 12 : 15,\n resetKey: `${search}|${statusFilter}|${view}`,\n });\n\n const resolveAsset = (assetId: string | null) => (assetId ? assetById.get(assetId) : undefined);\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-xs font-semibold uppercase tracking-wider text-text-muted\">\n IoT Devices / Connected Assets\n </p>\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Cpu className=\"h-6 w-6\" /> <GradientText>IoT Devices</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Monitor the health of every connected sensor and gateway across your estate.\n </p>\n </div>\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Register Device\n </Button>\n </div>\n <PagePurpose>\n See the connected sensors and smart devices attached to your assets in one place. Monitor\n their health and telemetry, confirm they are reporting, and send commands — so you catch a\n failing sensor (and the asset behind it) before it causes downtime.\n </PagePurpose>\n\n <RegisterDeviceDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onRegistered={() => void refetch()}\n />\n\n {/* ─── Fleet health KPIs ─── */}\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatTile label=\"Total Devices\" value={devices.length} icon={Cpu} hero />\n <StatTile label=\"Online\" value={counts.online} icon={Wifi} deltaTone=\"positive\" />\n <StatTile\n label=\"Offline\"\n value={counts.offline}\n icon={WifiOff}\n deltaTone={counts.offline > 0 ? 'negative' : 'neutral'}\n />\n <StatTile\n label=\"Degraded\"\n value={counts.degraded + counts.provisioning}\n icon={Activity}\n deltaTone={counts.degraded > 0 ? 'negative' : 'neutral'}\n />\n </div>\n\n {/* ─── Analytics band ─── */}\n {devices.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Fleet status\" subtitle=\"Live device distribution\" icon={Activity}>\n <DonutChart\n data={statusDonut}\n height={220}\n centerLabel=\"devices\"\n centerValue={devices.length}\n ariaLabel=\"IoT device status distribution\"\n />\n </ChartCard>\n <ChartCard title=\"Devices by type\" subtitle=\"Fleet composition\" icon={Cpu}>\n <BarsChart\n data={typeBars}\n xKey=\"name\"\n orientation=\"horizontal\"\n categoryWidth={110}\n height={220}\n series={[{ key: 'count', label: 'Devices' }]}\n ariaLabel=\"IoT devices by type\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n {/* ─── Controls ─── */}\n {devices.length > 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\" />\n <Input\n className=\"pl-9\"\n placeholder=\"Search by device id or name…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[160px]\">\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n {DEVICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s.toLowerCase()}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div className=\"flex items-center gap-1 rounded-lg border border-border-seam p-1\">\n <Button\n variant={view === 'grid' ? 'default' : 'ghost'}\n size=\"icon\"\n aria-label=\"Grid view\"\n aria-pressed={view === 'grid'}\n onClick={() => setView('grid')}\n >\n <LayoutGrid className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={view === 'table' ? 'default' : 'ghost'}\n size=\"icon\"\n aria-label=\"Table view\"\n aria-pressed={view === 'table'}\n onClick={() => setView('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </GlassCard>\n ) : null}\n\n {/* ─── Loading / Empty ─── */}\n {loading && devices.length === 0 ? (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <div key={i} className=\"h-32 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {!loading && devices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No IoT devices found\"\n description=\"Register a connected device to start monitoring its telemetry.\"\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Register device\n </Button>\n }\n />\n ) : null}\n\n {devices.length > 0 && filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching devices\"\n description=\"Adjust your search or status filter to see devices.\"\n />\n ) : null}\n\n {/* ─── Grid view ─── */}\n {filtered.length > 0 && view === 'grid' ? (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <GlassCard key={device.id} treatment=\"metric\" className=\"border-border-seam\">\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=\"flex min-w-0 items-center gap-2\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-primary/10 text-accent-primary\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold\" title={device.name}>\n {device.name}\n </p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n <StatusPill status={device.status} />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"rounded-full bg-status-neutral-bg-subtle px-2 py-0.5 font-medium text-status-neutral-text\">\n {humanize(device.type)}\n </span>\n <span className=\"rounded-full bg-status-info-subtle px-2 py-0.5 font-medium text-status-info-text\">\n {device.protocol}\n </span>\n </div>\n\n <div className=\"mt-auto space-y-1 border-t border-border-seam pt-2 text-xs text-text-secondary\">\n <div className=\"flex items-center justify-between gap-2\">\n <span>Last seen</span>\n <span className=\"tabular-nums\">{relativeTime(device.updatedAt)}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>Asset</span>\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 truncate font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n title={`${asset.assetTag} — ${asset.name}`}\n >\n <span className=\"truncate\">{asset.assetTag}</span>\n <ExternalLink className=\"h-3 w-3 shrink-0\" />\n </button>\n ) : (\n <span className=\"text-text-muted\">Unlinked</span>\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n );\n })}\n </div>\n ) : null}\n\n {/* ─── Table view ─── */}\n {filtered.length > 0 && view === 'table' ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-xs uppercase tracking-wide text-text-secondary\">\n <th className=\"p-3 text-left font-semibold\">Device</th>\n <th className=\"p-3 text-left font-semibold\">Type</th>\n <th className=\"p-3 text-left font-semibold\">Protocol</th>\n <th className=\"p-3 text-left font-semibold\">Status</th>\n <th className=\"p-3 text-left font-semibold\">Last Seen</th>\n <th className=\"p-3 text-left font-semibold\">Asset</th>\n </tr>\n </thead>\n <tbody>\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <tr\n key={device.id}\n className=\"border-b border-border-seam hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3\">\n <div className=\"flex items-center gap-2\">\n <Icon className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{device.name}</p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n </td>\n <td className=\"p-3\">{humanize(device.type)}</td>\n <td className=\"p-3\">\n <span className=\"rounded-full bg-status-info-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n {device.protocol}\n </span>\n </td>\n <td className=\"p-3\">\n <StatusPill status={device.status} />\n </td>\n <td className=\"p-3 text-text-secondary tabular-nums\">\n {relativeTime(device.updatedAt)}\n </td>\n <td className=\"p-3\">\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n >\n {asset.assetTag}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <span className=\"text-text-muted\">Unlinked</span>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {/* Mobile card list */}\n <div className=\"divide-y divide-border-seam md:hidden\">\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <div key={device.id} className=\"space-y-2 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{device.name}</p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n <StatusPill status={device.status} />\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>\n {humanize(device.type)} · {device.protocol}\n </span>\n <span className=\"tabular-nums\">{relativeTime(device.updatedAt)}</span>\n </div>\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n >\n {asset.assetTag} — {asset.name}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <span className=\"text-xs text-text-muted\">Unlinked</span>\n )}\n </div>\n );\n })}\n </div>\n </GlassCard>\n ) : null}\n\n {filtered.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=\"devices\"\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IotDevicesPage.js","names":[],"sources":["../../../src/assethandler/pages/IotDevicesPage.tsx"],"sourcesContent":["import {\n Cpu,\n Plus,\n Search,\n Radio,\n Router,\n ToggleRight,\n MapPin,\n Wifi,\n WifiOff,\n Activity,\n LayoutGrid,\n Table as TableIcon,\n ExternalLink,\n type LucideIcon,\n} from 'lucide-react';\nimport { useMemo, useState } from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\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 { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Pagination,\n usePagination,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n} from '../components';\nimport { notify } from '../utils/toast';\nimport { cn } from '../utils/cn';\n\nconst IOT_DEVICES_QUERY = gql`\n query AssetHandlerIoTDevices {\n iotDevices {\n id\n deviceId\n name\n type\n protocol\n status\n assetId\n updatedAt\n }\n }\n`;\n\nconst REGISTER_IOT_DEVICE_MUTATION = gql`\n mutation AssetHandlerRegisterIoTDevice($input: RegisterIoTDeviceInput!) {\n registerIoTDevice(input: $input) {\n id\n deviceId\n }\n }\n`;\n\ninterface IoTDevice {\n id: string;\n deviceId: string;\n name: string;\n type: string;\n protocol: string;\n status: string;\n assetId: string | null;\n updatedAt: string;\n}\n\ninterface RegisterIoTDeviceResult {\n registerIoTDevice: { id: string; deviceId: string };\n}\n\nconst DEVICE_TYPES = ['SENSOR', 'GATEWAY', 'ACTUATOR', 'TRACKER', 'CONTROLLER'] as const;\nconst PROTOCOLS = ['MQTT', 'COAP', 'HTTP', 'MODBUS', 'ZIGBEE', 'LORAWAN'] as const;\nconst DEVICE_STATUSES = ['ONLINE', 'OFFLINE', 'DEGRADED', 'PROVISIONING'] as const;\n\ntype Tone = 'success' | 'warning' | 'error' | 'info' | 'neutral';\n\nconst TONE_PILL: Record<Tone, string> = {\n success: 'bg-status-success-subtle text-status-success-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n error: 'bg-status-error-subtle text-status-error-text',\n info: 'bg-status-info-subtle text-status-info-text',\n neutral: 'bg-status-neutral-bg-subtle text-status-neutral-text',\n};\n\nconst statusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'online') return 'success';\n if (s === 'degraded') return 'warning';\n if (s === 'provisioning') return 'info';\n return 'neutral';\n};\n\nconst TYPE_ICON: Record<string, LucideIcon> = {\n SENSOR: Radio,\n GATEWAY: Router,\n ACTUATOR: ToggleRight,\n TRACKER: MapPin,\n CONTROLLER: Cpu,\n};\n\nconst humanize = (value: string) => value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();\n\nfunction relativeTime(iso: string): string {\n const then = new Date(iso).getTime();\n if (!Number.isFinite(then)) return '—';\n const diff = Date.now() - then;\n const mins = Math.round(diff / 60000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.round(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n const days = Math.round(hrs / 24);\n if (days < 30) return `${days}d ago`;\n return new Date(iso).toLocaleDateString();\n}\n\nfunction StatusPill({ status }: { status: string }) {\n const s = status.toLowerCase();\n const tone = statusTone(status);\n const Icon = s === 'online' ? Wifi : s === 'offline' ? WifiOff : Activity;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',\n TONE_PILL[tone]\n )}\n >\n <Icon className=\"h-3 w-3\" aria-hidden=\"true\" />\n {s}\n </span>\n );\n}\n\nfunction RegisterDeviceDialog({\n open,\n onOpenChange,\n onRegistered,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onRegistered: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [deviceId, setDeviceId] = useState('');\n const [name, setName] = useState('');\n const [type, setType] = useState<(typeof DEVICE_TYPES)[number]>('SENSOR');\n const [protocol, setProtocol] = useState<(typeof PROTOCOLS)[number]>('MQTT');\n const [status, setStatus] = useState<(typeof DEVICE_STATUSES)[number]>('PROVISIONING');\n const [assetId, setAssetId] = useState('');\n\n const reset = () => {\n setDeviceId('');\n setName('');\n setType('SENSOR');\n setProtocol('MQTT');\n setStatus('PROVISIONING');\n setAssetId('');\n };\n\n const [registerDevice, { loading }] = useMutation<RegisterIoTDeviceResult>(\n REGISTER_IOT_DEVICE_MUTATION,\n {\n onCompleted: (data) => {\n notify.success('Device registered', `${data.registerIoTDevice.deviceId} is now tracked.`);\n reset();\n onOpenChange(false);\n onRegistered();\n },\n onError: (error) => notify.error('Could not register device', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!deviceId.trim() || !name.trim()) {\n notify.warning('Missing details', 'Device ID and name are required.');\n return;\n }\n void registerDevice({\n variables: {\n input: {\n deviceId: deviceId.trim(),\n name: name.trim(),\n type,\n protocol,\n status,\n assetId: assetId || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Register IoT Device</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Onboard a connected device and optionally link it to an asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Device ID *</Label>\n <Input\n placeholder=\"e.g., dev-8821\"\n value={deviceId}\n onChange={(e) => setDeviceId(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input value={name} onChange={(e) => setName(e.target.value)} />\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 {DEVICE_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {t}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Protocol</Label>\n <Select value={protocol} onValueChange={(v) => setProtocol(v as typeof protocol)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PROTOCOLS.map((p) => (\n <SelectItem key={p} value={p}>\n {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 {DEVICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Linked Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Unlinked\" />\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>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? 'Registering…' : 'Register device'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function IotDevicesPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [view, setView] = useState<'grid' | 'table'>('grid');\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<string>('all');\n const navigate = useAssetHandlerNavigate();\n const assets = useAssetHandlerStore((s) => s.assets);\n\n const { data, loading, refetch } = useQuery<{ iotDevices: IoTDevice[] }>(IOT_DEVICES_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const devices = useMemo(() => data?.iotDevices ?? [], [data]);\n\n const assetById = useMemo(() => {\n const map = new Map<string, { assetTag: string; name: string }>();\n for (const a of assets) map.set(a.id, { assetTag: a.assetTag, name: a.name });\n return map;\n }, [assets]);\n\n // ─── Fleet health (real counts) ───\n const counts = useMemo(() => {\n const byStatus = { online: 0, offline: 0, degraded: 0, provisioning: 0 };\n for (const d of devices) {\n const s = d.status.toLowerCase();\n if (s === 'online') byStatus.online += 1;\n else if (s === 'degraded') byStatus.degraded += 1;\n else if (s === 'provisioning') byStatus.provisioning += 1;\n else byStatus.offline += 1;\n }\n return byStatus;\n }, [devices]);\n\n const statusDonut = useMemo(() => {\n const order: { key: keyof typeof counts; label: string; color: string }[] = [\n { key: 'online', label: 'Online', color: 'var(--color-status-success-bg)' },\n { key: 'offline', label: 'Offline', color: 'var(--color-status-neutral-bg)' },\n { key: 'degraded', label: 'Degraded', color: 'var(--color-status-warning-bg)' },\n { key: 'provisioning', label: 'Provisioning', color: 'var(--color-status-info-bg)' },\n ];\n return order\n .filter((o) => counts[o.key] > 0)\n .map((o) => ({ name: o.label, value: counts[o.key], color: o.color }));\n }, [counts]);\n\n const typeBars = useMemo(() => {\n const map = new Map<string, number>();\n for (const d of devices) map.set(d.type, (map.get(d.type) ?? 0) + 1);\n return [...map.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([type, value]) => ({ name: humanize(type), count: value }));\n }, [devices]);\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n return devices.filter((d) => {\n if (statusFilter !== 'all' && d.status.toLowerCase() !== statusFilter) return false;\n if (!q) return true;\n return d.deviceId.toLowerCase().includes(q) || d.name.toLowerCase().includes(q);\n });\n }, [devices, search, statusFilter]);\n\n const pagination = usePagination(filtered, {\n pageSize: view === 'grid' ? 12 : 15,\n resetKey: `${search}|${statusFilter}|${view}`,\n });\n\n const resolveAsset = (assetId: string | null) => (assetId ? assetById.get(assetId) : undefined);\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <p className=\"text-xs font-semibold uppercase tracking-wider text-text-muted\">\n IoT Devices / Connected Assets\n </p>\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Cpu className=\"h-6 w-6\" /> <GradientText>IoT Devices</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Monitor the health of every connected sensor and gateway across your estate.\n </p>\n </div>\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Register Device\n </Button>\n </div>\n <PagePurpose>\n See the connected sensors and smart devices attached to your assets in one place. Monitor\n their health and telemetry, confirm they are reporting, and send commands — so you catch a\n failing sensor (and the asset behind it) before it causes downtime.\n </PagePurpose>\n\n <RegisterDeviceDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onRegistered={() => void refetch()}\n />\n\n {/* ─── Fleet health KPIs ─── */}\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatTile label=\"Total Devices\" value={devices.length} icon={Cpu} hero />\n <StatTile label=\"Online\" value={counts.online} icon={Wifi} deltaTone=\"positive\" />\n <StatTile\n label=\"Offline\"\n value={counts.offline}\n icon={WifiOff}\n deltaTone={counts.offline > 0 ? 'negative' : 'neutral'}\n />\n <StatTile\n label=\"Degraded\"\n value={counts.degraded + counts.provisioning}\n icon={Activity}\n deltaTone={counts.degraded > 0 ? 'negative' : 'neutral'}\n />\n </div>\n\n {/* ─── Analytics band ─── */}\n {devices.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Fleet status\" subtitle=\"Live device distribution\" icon={Activity}>\n <DonutChart\n data={statusDonut}\n height={220}\n centerLabel=\"devices\"\n centerValue={devices.length}\n ariaLabel=\"IoT device status distribution\"\n />\n </ChartCard>\n <ChartCard title=\"Devices by type\" subtitle=\"Fleet composition\" icon={Cpu}>\n <BarsChart\n data={typeBars}\n xKey=\"name\"\n orientation=\"horizontal\"\n categoryWidth={110}\n height={220}\n series={[{ key: 'count', label: 'Devices' }]}\n ariaLabel=\"IoT devices by type\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n {/* ─── Controls ─── */}\n {devices.length > 0 ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\" />\n <Input\n className=\"pl-9\"\n placeholder=\"Search by device id or name…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[160px]\">\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n {DEVICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s.toLowerCase()}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div className=\"flex items-center gap-1 rounded-lg border border-border-seam p-1\">\n <Button\n variant={view === 'grid' ? 'default' : 'ghost'}\n size=\"icon\"\n aria-label=\"Grid view\"\n aria-pressed={view === 'grid'}\n onClick={() => setView('grid')}\n >\n <LayoutGrid className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={view === 'table' ? 'default' : 'ghost'}\n size=\"icon\"\n aria-label=\"Table view\"\n aria-pressed={view === 'table'}\n onClick={() => setView('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </GlassCard>\n ) : null}\n\n {/* ─── Loading / Empty ─── */}\n {loading && devices.length === 0 ? (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {Array.from({ length: 8 }).map((_, i) => (\n <div key={i} className=\"h-32 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {!loading && devices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No IoT devices found\"\n description=\"Register a connected device to start monitoring its telemetry.\"\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Register device\n </Button>\n }\n />\n ) : null}\n\n {devices.length > 0 && filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching devices\"\n description=\"Adjust your search or status filter to see devices.\"\n />\n ) : null}\n\n {/* ─── Grid view ─── */}\n {filtered.length > 0 && view === 'grid' ? (\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <GlassCard key={device.id} treatment=\"metric\" className=\"border-border-seam\">\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=\"flex min-w-0 items-center gap-2\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-primary/10 text-accent-primary\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate font-semibold\" title={device.name}>\n {device.name}\n </p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n <StatusPill status={device.status} />\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"rounded-full bg-status-neutral-bg-subtle px-2 py-0.5 font-medium text-status-neutral-text\">\n {humanize(device.type)}\n </span>\n <span className=\"rounded-full bg-status-info-subtle px-2 py-0.5 font-medium text-status-info-text\">\n {device.protocol}\n </span>\n </div>\n\n <div className=\"mt-auto space-y-1 border-t border-border-seam pt-2 text-xs text-text-secondary\">\n <div className=\"flex items-center justify-between gap-2\">\n <span>Last seen</span>\n <span className=\"tabular-nums\">{relativeTime(device.updatedAt)}</span>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <span>Asset</span>\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 truncate font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n title={`${asset.assetTag} — ${asset.name}`}\n >\n <span className=\"truncate\">{asset.assetTag}</span>\n <ExternalLink className=\"h-3 w-3 shrink-0\" />\n </button>\n ) : (\n <span className=\"text-text-muted\">Unlinked</span>\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n );\n })}\n </div>\n ) : null}\n\n {/* ─── Table view ─── */}\n {filtered.length > 0 && view === 'table' ? (\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-xs uppercase tracking-wide text-text-secondary\">\n <th className=\"p-3 text-left font-semibold\">Device</th>\n <th className=\"p-3 text-left font-semibold\">Type</th>\n <th className=\"p-3 text-left font-semibold\">Protocol</th>\n <th className=\"p-3 text-left font-semibold\">Status</th>\n <th className=\"p-3 text-left font-semibold\">Last Seen</th>\n <th className=\"p-3 text-left font-semibold\">Asset</th>\n </tr>\n </thead>\n <tbody>\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <tr\n key={device.id}\n className=\"border-b border-border-seam hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3\">\n <div className=\"flex items-center gap-2\">\n <Icon className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{device.name}</p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n </td>\n <td className=\"p-3\">{humanize(device.type)}</td>\n <td className=\"p-3\">\n <span className=\"rounded-full bg-status-info-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n {device.protocol}\n </span>\n </td>\n <td className=\"p-3\">\n <StatusPill status={device.status} />\n </td>\n <td className=\"p-3 text-text-secondary tabular-nums\">\n {relativeTime(device.updatedAt)}\n </td>\n <td className=\"p-3\">\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n >\n {asset.assetTag}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <span className=\"text-text-muted\">Unlinked</span>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n {/* Mobile card list */}\n <div className=\"divide-y divide-border-seam md:hidden\">\n {pagination.pageItems.map((device) => {\n const Icon = TYPE_ICON[device.type] ?? Cpu;\n const asset = resolveAsset(device.assetId);\n return (\n <div key={device.id} className=\"space-y-2 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{device.name}</p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {device.deviceId}\n </p>\n </div>\n </div>\n <StatusPill status={device.status} />\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>\n {humanize(device.type)} · {device.protocol}\n </span>\n <span className=\"tabular-nums\">{relativeTime(device.updatedAt)}</span>\n </div>\n {asset ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n onClick={() => navigate('/assets/' + device.assetId)}\n >\n {asset.assetTag} — {asset.name}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <span className=\"text-xs text-text-muted\">Unlinked</span>\n )}\n </div>\n );\n })}\n </div>\n </GlassCard>\n ) : null}\n\n {filtered.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=\"devices\"\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ItilChangeDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/ItilChangeDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n Label,\n Textarea,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle, XCircle } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport { AttachmentsPanel, CommentsPanel, ActivityTimeline, NotFoundState } from '../components';\n\nconst CHANGE_QUERY = gql`\n query AssetHandlerChangeRequest($id: ID!) {\n changeRequest(id: $id) {\n id\n title\n description\n type\n status\n risk\n requestedBy\n assignedTo\n affectedAssets\n scheduledStart\n scheduledEnd\n approvals\n createdAt\n }\n }\n`;\n\nconst APPROVE_CHANGE_MUTATION = gql`\n mutation AssetHandlerApproveChangeRequest($id: ID!) {\n approveChangeRequest(id: $id) {\n id\n status\n }\n }\n`;\n\nconst REJECT_CHANGE_MUTATION = gql`\n mutation AssetHandlerRejectChangeRequest($id: ID!, $reason: String) {\n rejectChangeRequest(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\ninterface ChangeApproval {\n name?: string | null;\n status?: string | null;\n date?: string | null;\n}\n\ninterface ChangeRecord {\n id: string;\n title: string;\n description: string;\n type: string;\n status: string;\n risk: string;\n requestedBy: string;\n assignedTo?: string | null;\n affectedAssets: string[];\n scheduledStart?: string | null;\n scheduledEnd?: string | null;\n approvals?: ChangeApproval[] | null;\n createdAt: string;\n}\n\ninterface ChangeQueryResult {\n changeRequest: ChangeRecord | null;\n}\n\nconst riskColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nconst formatDate = (value?: string | null) => (value ? new Date(value).toLocaleString() : '—');\n\nexport function ItilChangeDetailPage() {\n const navigate = useAssetHandlerNavigate();\n const { changeId } = useParams<{ changeId: string }>();\n const { assets } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<ChangeQueryResult>(CHANGE_QUERY, {\n variables: { id: changeId ?? '' },\n skip: !changeId,\n fetchPolicy: 'cache-and-network',\n });\n\n const [showReject, setShowReject] = useState(false);\n const [reason, setReason] = useState('');\n\n const [approveChange, { loading: approving }] = useMutation(APPROVE_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Change approved', 'The change request has been approved.');\n void refetch();\n },\n onError: (error) => notify.error('Could not approve change', error.message),\n });\n\n const [rejectChange, { loading: rejecting }] = useMutation(REJECT_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Change rejected', 'The change request has been rejected.');\n setShowReject(false);\n setReason('');\n void refetch();\n },\n onError: (error) => notify.error('Could not reject change', error.message),\n });\n\n if (loading && !data) {\n return (\n <div className=\"space-y-3 p-6\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-10 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n );\n }\n\n const raw = data?.changeRequest;\n if (!raw) {\n return (\n <NotFoundState\n entityLabel=\"Change request\"\n description=\"This change may have been completed or removed. Return to change management to find it.\"\n backLabel=\"Back to changes\"\n onBack={() => navigate('/itil/change-management')}\n />\n );\n }\n\n const change = {\n ...raw,\n status: raw.status.toLowerCase(),\n risk: raw.risk.toLowerCase(),\n type: raw.type.toLowerCase(),\n };\n const approvals = raw.approvals ?? [];\n const affectedAssetDetails = assets.filter((a) => raw.affectedAssets.includes(a.id));\n const isDecided =\n change.status === 'approved' || change.status === 'completed' || change.status === 'rejected';\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Go back\"\n onClick={() => navigate('/itil/change-management')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{change.id}</GradientText>\n </h1>\n <Badge\n variant={change.type === 'emergency' ? 'destructive' : 'outline'}\n className=\"capitalize\"\n >\n {change.type}\n </Badge>\n <Badge variant={riskColors[change.risk] ?? 'outline'}>Risk: {change.risk}</Badge>\n <Badge variant=\"outline\">{change.status.replace(/_/g, ' ')}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{change.title}</p>\n </div>\n </div>\n {!isDecided ? (\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowReject(true)}>\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void approveChange({ variables: { id: change.id } })}\n disabled={approving}\n >\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Approve\n </Button>\n </div>\n ) : null}\n </div>\n\n <PagePurpose>\n The full record of a single planned change: what is changing, its risk and schedule, which\n assets it touches, and where it stands in the approval chain. Use this page to approve,\n reject or track a change so it lands safely in its agreed window.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-change-detail\"\n steps={[\n {\n id: 'approve',\n label: 'Approve or reject this change',\n description: 'Sign off on the change once you have reviewed its risk.',\n done: isDecided,\n },\n {\n id: 'assets',\n label: 'Review affected assets',\n description: 'Confirm the blast radius before the change window.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'calendar',\n label: 'Check the maintenance calendar',\n description: 'Make sure the schedule does not clash with other work.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Change Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{change.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Scheduled Start</span>\n <p className=\"font-medium\">{formatDate(change.scheduledStart)}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Scheduled End</span>\n <p className=\"font-medium\">{formatDate(change.scheduledEnd)}</p>\n </div>\n </div>\n <Separator />\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary mb-2\">Affected Assets</h4>\n {affectedAssetDetails.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No linked assets on record.</p>\n ) : (\n <div className=\"space-y-2\">\n {affectedAssetDetails.map((a) => (\n <div\n key={a.id}\n className=\"flex items-center justify-between rounded border p-2\"\n >\n <div>\n <p className=\"text-sm font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetTag}</p>\n </div>\n <Badge variant=\"outline\">{a.status.replace(/_/g, ' ')}</Badge>\n </div>\n ))}\n </div>\n )}\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Properties</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd className=\"font-medium capitalize\">{change.type}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Risk</dt>\n <dd>\n <Badge variant={riskColors[change.risk] ?? 'outline'}>{change.risk}</Badge>\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Badge variant=\"outline\">{change.status.replace(/_/g, ' ')}</Badge>\n </dd>\n </div>\n <Separator />\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Requested By</dt>\n <dd className=\"text-xs\">{change.requestedBy}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Assigned To</dt>\n <dd className=\"text-xs\">{change.assignedTo || 'Unassigned'}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-xs\">{new Date(change.createdAt).toLocaleDateString()}</dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Approvals</CardTitle>\n </CardHeader>\n <CardContent>\n {approvals.length === 0 ? (\n <p className=\"text-sm text-text-secondary text-center py-4\">No approvals yet</p>\n ) : (\n <div className=\"space-y-2\">\n {approvals.map((approval, i) => (\n <div key={i} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"flex items-center gap-2\">\n {approval.status === 'approved' ? (\n <CheckCircle className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <XCircle className=\"h-4 w-4 text-status-error-text\" />\n )}\n <span className=\"text-sm\">{approval.name ?? 'Approver'}</span>\n </div>\n <span className=\"text-xs text-text-secondary\">\n {approval.date ? new Date(approval.date).toLocaleDateString() : '—'}\n </span>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n\n <AttachmentsPanel entityType=\"assethandler-change-request\" entityId={change.id} />\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <CommentsPanel entityType=\"assethandler-change-request\" entityId={change.id} />\n <ActivityTimeline resourceId={change.id} />\n </div>\n\n {/* Reject dialog */}\n <ResponsiveDialog open={showReject} onOpenChange={setShowReject}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Reject change request</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Give a reason so the requester understands why this change was declined.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-2\">\n <Label>Reason</Label>\n <Textarea\n placeholder=\"Why is this change being rejected?\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={3}\n />\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setShowReject(false)} disabled={rejecting}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={() =>\n void rejectChange({\n variables: { id: change.id, reason: reason.trim() || null },\n })\n }\n disabled={rejecting}\n >\n {rejecting ? 'Rejecting…' : 'Reject change'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,IAAM,IAAe,CAAG;;;;;;;;;;;;;;;;;;GAoBlB,IAA0B,CAAG;;;;;;;GAS7B,IAAyB,CAAG;;;;;;;GAmC5B,IAAkF;CACtF,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACN,EAEK,KAAc,MAA2B,IAAQ,IAAI,KAAK,EAAM,CAAC,gBAAgB,GAAG;AAE1F,SAAgB,IAAuB;CACrC,IAAM,IAAW,GAAyB,EACpC,EAAE,gBAAa,GAAiC,EAChD,EAAE,cAAW,GAAsB,EAEnC,EAAE,SAAM,YAAS,eAAY,EAA4B,GAAc;EAC3E,WAAW,EAAE,IAAI,KAAY,IAAI;EACjC,MAAM,CAAC;EACP,aAAa;EACd,CAAC,EAEI,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAQ,KAAa,EAAS,GAAG,EAElC,CAAC,GAAe,EAAE,SAAS,OAAe,EAAY,GAAyB;EACnF,gBAAgB,CAAC,wBAAwB;EACzC,mBAAmB;AAEZ,GADL,EAAO,QAAQ,mBAAmB,wCAAwC,EACrE,GAAS;;EAEhB,UAAU,MAAU,EAAO,MAAM,4BAA4B,EAAM,QAAQ;EAC5E,CAAC,EAEI,CAAC,GAAc,EAAE,SAAS,OAAe,EAAY,GAAwB;EACjF,gBAAgB,CAAC,wBAAwB;EACzC,mBAAmB;AAIZ,GAHL,EAAO,QAAQ,mBAAmB,wCAAwC,EAC1E,EAAc,GAAM,EACpB,EAAU,GAAG,EACR,GAAS;;EAEhB,UAAU,MAAU,EAAO,MAAM,2BAA2B,EAAM,QAAQ;EAC3E,CAAC;AAEF,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD,EAAa,WAAU,+DAAgE,EAA7E,EAA6E,CACvF;EACE,CAAA;CAIV,IAAM,IAAM,GAAM;AAClB,KAAI,CAAC,EACH,QACE,kBAAC,IAAD;EACE,aAAY;EACZ,aAAY;EACZ,WAAU;EACV,cAAc,EAAS,0BAA0B;EACjD,CAAA;CAIN,IAAM,IAAS;EACb,GAAG;EACH,QAAQ,EAAI,OAAO,aAAa;EAChC,MAAM,EAAI,KAAK,aAAa;EAC5B,MAAM,EAAI,KAAK,aAAa;EAC7B,EACK,IAAY,EAAI,aAAa,EAAE,EAC/B,IAAuB,EAAO,QAAQ,MAAM,EAAI,eAAe,SAAS,EAAE,GAAG,CAAC,EAC9E,IACJ,EAAO,WAAW,cAAc,EAAO,WAAW,eAAe,EAAO,WAAW;AAErF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,SAAQ;MACR,MAAK;MACL,cAAW;MACX,eAAe,EAAS,0BAA0B;gBAElD,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MAC1B,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACZ,kBAAC,GAAD,EAAA,UAAe,EAAO,IAAkB,CAAA;QACrC,CAAA;OACL,kBAAC,GAAD;QACE,SAAS,EAAO,SAAS,cAAc,gBAAgB;QACvD,WAAU;kBAET,EAAO;QACF,CAAA;OACR,kBAAC,GAAD;QAAO,SAAS,EAAW,EAAO,SAAS;kBAA3C,CAAsD,UAAO,EAAO,KAAa;;OACjF,kBAAC,GAAD;QAAO,SAAQ;kBAAW,EAAO,OAAO,QAAQ,MAAM,IAAI;QAAS,CAAA;OAC/D;SACN,kBAAC,KAAD;MAAG,WAAU;gBAAoC,EAAO;MAAU,CAAA,CAC9D,EAAA,CAAA,CACF;QACJ,IAeE,OAdF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,eAAe,EAAc,GAAK;gBAAtE,CACE,kBAAC,GAAD,EAAS,WAAU,gBAAiB,CAAA,EAAA,SAE7B;SACT,kBAAC,GAAD;MACE,MAAK;MACL,eAAe,KAAK,EAAc,EAAE,WAAW,EAAE,IAAI,EAAO,IAAI,EAAE,CAAC;MACnE,UAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAa,WAAU,gBAAiB,CAAA,EAAA,UAEjC;QACL;OAEJ;;GAEN,kBAAC,GAAD,EAAA,UAAa,wPAIC,CAAA;GAEd,kBAAC,GAAD;IACE,YAAW;IACX,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM;MACP;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,qBAAqB;MAC9C;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,oCAAoC;MAC7D;KACF;IACD,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAe,WAAU;eAAzB,CACE,kBAAC,GAAD;MAAY,WAAU;gBACpB,kBAAC,GAAD,EAAA,UAAW,kBAA0B,CAAA;MAC1B,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAA0C;QAAgB,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAAgB,EAAO;QAAgB,CAAA,CAChD,EAAA,CAAA;OACN,kBAAC,GAAD,EAAa,CAAA;OACb,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAsB;SAAsB,CAAA,EAC5D,kBAAC,KAAD;SAAG,WAAU;mBAAe,EAAW,EAAO,eAAe;SAAK,CAAA,CAC9D,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAsB;SAAoB,CAAA,EAC1D,kBAAC,KAAD;SAAG,WAAU;mBAAe,EAAW,EAAO,aAAa;SAAK,CAAA,CAC5D,EAAA,CAAA,CACF;;OACN,kBAAC,GAAD,EAAa,CAAA;OACb,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAA+C;QAAoB,CAAA,EAChF,EAAqB,WAAW,IAC/B,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAA+B,CAAA,GAE1E,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAqB,KAAK,MACzB,kBAAC,OAAD;SAEE,WAAU;mBAFZ,CAIE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAuB,EAAE;UAAS,CAAA,EAC/C,kBAAC,KAAD;UAAG,WAAU;oBAA+B,EAAE;UAAa,CAAA,CACvD,EAAA,CAAA,EACN,kBAAC,GAAD;UAAO,SAAQ;oBAAW,EAAE,OAAO,QAAQ,MAAM,IAAI;UAAS,CAAA,CAC1D;WARC,EAAE,GAQH,CACN;QACE,CAAA,CAEJ,EAAA,CAAA;OACM;QACA;QAEhB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAW,WAAU;gBAAY;MAAsB,CAAA,EAC5C,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,MAAD;MAAI,WAAU;gBAAd;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAS,CAAA,EAC7C,kBAAC,MAAD;SAAI,WAAU;mBAA0B,EAAO;SAAU,CAAA,CACrD;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAS,CAAA,EAC7C,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;SAAO,SAAS,EAAW,EAAO,SAAS;mBAAY,EAAO;SAAa,CAAA,EACxE,CAAA,CACD;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAW,CAAA,EAC/C,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;SAAO,SAAQ;mBAAW,EAAO,OAAO,QAAQ,MAAM,IAAI;SAAS,CAAA,EAChE,CAAA,CACD;;OACN,kBAAC,GAAD,EAAa,CAAA;OACb,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAiB,CAAA,EACrD,kBAAC,MAAD;SAAI,WAAU;mBAAW,EAAO;SAAiB,CAAA,CAC7C;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAgB,CAAA,EACpD,kBAAC,MAAD;SAAI,WAAU;mBAAW,EAAO,cAAc;SAAkB,CAAA,CAC5D;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsB;SAAY,CAAA,EAChD,kBAAC,MAAD;SAAI,WAAU;mBAAW,IAAI,KAAK,EAAO,UAAU,CAAC,oBAAoB;SAAM,CAAA,CAC1E;;OACH;SACO,CAAA,CACT,EAAA,CAAA,EAEP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAW,WAAU;gBAAY;MAAqB,CAAA,EAC3C,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,EAAU,WAAW,IACpB,kBAAC,KAAD;MAAG,WAAU;gBAA+C;MAAoB,CAAA,GAEhF,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAU,KAAK,GAAU,MACxB,kBAAC,OAAD;OAAa,WAAU;iBAAvB,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,EAAS,WAAW,aACnB,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA,GAE5D,kBAAC,GAAD,EAAS,WAAU,kCAAmC,CAAA,EAExD,kBAAC,QAAD;SAAM,WAAU;mBAAW,EAAS,QAAQ;SAAkB,CAAA,CAC1D;WACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAS,OAAO,IAAI,KAAK,EAAS,KAAK,CAAC,oBAAoB,GAAG;QAC3D,CAAA,CACH;SAZI,EAYJ,CACN;MACE,CAAA,EAEI,CAAA,CACT,EAAA,CAAA,CACH;OACF;;GAEN,kBAAC,GAAD;IAAkB,YAAW;IAA8B,UAAU,EAAO;IAAM,CAAA;GAElF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAe,YAAW;KAA8B,UAAU,EAAO;KAAM,CAAA,EAC/E,kBAAC,IAAD,EAAkB,YAAY,EAAO,IAAM,CAAA,CACvC;;GAGN,kBAAC,GAAD;IAAkB,MAAM;IAAY,cAAc;cAChD,kBAAC,IAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,yBAA6C,CAAA,EACpE,kBAAC,IAAD,EAAA,UAA6B,4EAEC,CAAA,CACP,EAAA,CAAA;KACzB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;OACE,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;OAC1C,MAAM;OACN,CAAA,CACE;;KACN,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAc,GAAM;MAAE,UAAU;gBAAW;MAE3E,CAAA,EACT,kBAAC,GAAD;MACE,SAAQ;MACR,eACE,KAAK,EAAa,EAChB,WAAW;OAAE,IAAI,EAAO;OAAI,QAAQ,EAAO,MAAM,IAAI;OAAM,EAC5D,CAAC;MAEJ,UAAU;gBAET,IAAY,eAAe;MACrB,CAAA,CACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GACf"}
|
|
1
|
+
{"version":3,"file":"ItilChangeDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/ItilChangeDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n Label,\n Textarea,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle, XCircle } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport { AttachmentsPanel, CommentsPanel, ActivityTimeline, NotFoundState } from '../components';\n\nconst CHANGE_QUERY = gql`\n query AssetHandlerChangeRequest($id: ID!) {\n changeRequest(id: $id) {\n id\n title\n description\n type\n status\n risk\n requestedBy\n assignedTo\n affectedAssets\n scheduledStart\n scheduledEnd\n approvals\n createdAt\n }\n }\n`;\n\nconst APPROVE_CHANGE_MUTATION = gql`\n mutation AssetHandlerApproveChangeRequest($id: ID!) {\n approveChangeRequest(id: $id) {\n id\n status\n }\n }\n`;\n\nconst REJECT_CHANGE_MUTATION = gql`\n mutation AssetHandlerRejectChangeRequest($id: ID!, $reason: String) {\n rejectChangeRequest(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\ninterface ChangeApproval {\n name?: string | null;\n status?: string | null;\n date?: string | null;\n}\n\ninterface ChangeRecord {\n id: string;\n title: string;\n description: string;\n type: string;\n status: string;\n risk: string;\n requestedBy: string;\n assignedTo?: string | null;\n affectedAssets: string[];\n scheduledStart?: string | null;\n scheduledEnd?: string | null;\n approvals?: ChangeApproval[] | null;\n createdAt: string;\n}\n\ninterface ChangeQueryResult {\n changeRequest: ChangeRecord | null;\n}\n\nconst riskColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nconst formatDate = (value?: string | null) => (value ? new Date(value).toLocaleString() : '—');\n\nexport function ItilChangeDetailPage() {\n const navigate = useAssetHandlerNavigate();\n const { changeId } = useParams<{ changeId: string }>();\n const { assets } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<ChangeQueryResult>(CHANGE_QUERY, {\n variables: { id: changeId ?? '' },\n skip: !changeId,\n fetchPolicy: 'cache-and-network',\n });\n\n const [showReject, setShowReject] = useState(false);\n const [reason, setReason] = useState('');\n\n const [approveChange, { loading: approving }] = useMutation(APPROVE_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Change approved', 'The change request has been approved.');\n void refetch();\n },\n onError: (error) => notify.error('Could not approve change', error.message),\n });\n\n const [rejectChange, { loading: rejecting }] = useMutation(REJECT_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Change rejected', 'The change request has been rejected.');\n setShowReject(false);\n setReason('');\n void refetch();\n },\n onError: (error) => notify.error('Could not reject change', error.message),\n });\n\n if (loading && !data) {\n return (\n <div className=\"space-y-3 p-6\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-10 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n );\n }\n\n const raw = data?.changeRequest;\n if (!raw) {\n return (\n <NotFoundState\n entityLabel=\"Change request\"\n description=\"This change may have been completed or removed. Return to change management to find it.\"\n backLabel=\"Back to changes\"\n onBack={() => navigate('/itil/change-management')}\n />\n );\n }\n\n const change = {\n ...raw,\n status: raw.status.toLowerCase(),\n risk: raw.risk.toLowerCase(),\n type: raw.type.toLowerCase(),\n };\n const approvals = raw.approvals ?? [];\n const affectedAssetDetails = assets.filter((a) => raw.affectedAssets.includes(a.id));\n const isDecided =\n change.status === 'approved' || change.status === 'completed' || change.status === 'rejected';\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Go back\"\n onClick={() => navigate('/itil/change-management')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{change.id}</GradientText>\n </h1>\n <Badge\n variant={change.type === 'emergency' ? 'destructive' : 'outline'}\n className=\"capitalize\"\n >\n {change.type}\n </Badge>\n <Badge variant={riskColors[change.risk] ?? 'outline'}>Risk: {change.risk}</Badge>\n <Badge variant=\"outline\">{change.status.replace(/_/g, ' ')}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{change.title}</p>\n </div>\n </div>\n {!isDecided ? (\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowReject(true)}>\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n <Button\n size=\"sm\"\n onClick={() => void approveChange({ variables: { id: change.id } })}\n disabled={approving}\n >\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Approve\n </Button>\n </div>\n ) : null}\n </div>\n\n <PagePurpose>\n The full record of a single planned change: what is changing, its risk and schedule, which\n assets it touches, and where it stands in the approval chain. Use this page to approve,\n reject or track a change so it lands safely in its agreed window.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-change-detail\"\n steps={[\n {\n id: 'approve',\n label: 'Approve or reject this change',\n description: 'Sign off on the change once you have reviewed its risk.',\n done: isDecided,\n },\n {\n id: 'assets',\n label: 'Review affected assets',\n description: 'Confirm the blast radius before the change window.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'calendar',\n label: 'Check the maintenance calendar',\n description: 'Make sure the schedule does not clash with other work.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Change Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{change.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Scheduled Start</span>\n <p className=\"font-medium\">{formatDate(change.scheduledStart)}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Scheduled End</span>\n <p className=\"font-medium\">{formatDate(change.scheduledEnd)}</p>\n </div>\n </div>\n <Separator />\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary mb-2\">Affected Assets</h4>\n {affectedAssetDetails.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No linked assets on record.</p>\n ) : (\n <div className=\"space-y-2\">\n {affectedAssetDetails.map((a) => (\n <div\n key={a.id}\n className=\"flex items-center justify-between rounded border p-2\"\n >\n <div>\n <p className=\"text-sm font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetTag}</p>\n </div>\n <Badge variant=\"outline\">{a.status.replace(/_/g, ' ')}</Badge>\n </div>\n ))}\n </div>\n )}\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Properties</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd className=\"font-medium capitalize\">{change.type}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Risk</dt>\n <dd>\n <Badge variant={riskColors[change.risk] ?? 'outline'}>{change.risk}</Badge>\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Badge variant=\"outline\">{change.status.replace(/_/g, ' ')}</Badge>\n </dd>\n </div>\n <Separator />\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Requested By</dt>\n <dd className=\"text-xs\">{change.requestedBy}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Assigned To</dt>\n <dd className=\"text-xs\">{change.assignedTo || 'Unassigned'}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-xs\">{new Date(change.createdAt).toLocaleDateString()}</dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Approvals</CardTitle>\n </CardHeader>\n <CardContent>\n {approvals.length === 0 ? (\n <p className=\"text-sm text-text-secondary text-center py-4\">No approvals yet</p>\n ) : (\n <div className=\"space-y-2\">\n {approvals.map((approval, i) => (\n <div key={i} className=\"flex items-center justify-between rounded border p-2\">\n <div className=\"flex items-center gap-2\">\n {approval.status === 'approved' ? (\n <CheckCircle className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <XCircle className=\"h-4 w-4 text-status-error-text\" />\n )}\n <span className=\"text-sm\">{approval.name ?? 'Approver'}</span>\n </div>\n <span className=\"text-xs text-text-secondary\">\n {approval.date ? new Date(approval.date).toLocaleDateString() : '—'}\n </span>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n\n <AttachmentsPanel entityType=\"assethandler-change-request\" entityId={change.id} />\n\n <div className=\"grid gap-6 lg:grid-cols-2\">\n <CommentsPanel entityType=\"assethandler-change-request\" entityId={change.id} />\n <ActivityTimeline resourceId={change.id} />\n </div>\n\n {/* Reject dialog */}\n <ResponsiveDialog open={showReject} onOpenChange={setShowReject}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Reject change request</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Give a reason so the requester understands why this change was declined.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-2\">\n <Label>Reason</Label>\n <Textarea\n placeholder=\"Why is this change being rejected?\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={3}\n />\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setShowReject(false)} disabled={rejecting}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={() =>\n void rejectChange({\n variables: { id: change.id, reason: reason.trim() || null },\n })\n }\n disabled={rejecting}\n >\n {rejecting ? 'Rejecting…' : 'Reject change'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ItilChangeManagementPage.js","names":[],"sources":["../../../src/assethandler/pages/ItilChangeManagementPage.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from 'react';\nimport {\n Button,\n Input,\n Checkbox,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n Check,\n X,\n Download,\n CheckCircle2,\n XCircle,\n PieChart as PieIcon,\n BarChart3,\n Loader2,\n} from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore, type ChangeRequest } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n chartTokens,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\nimport { downloadCsv } from '../utils/csv';\nimport { NewChangeRequestDialog } from './ItilDialogs';\n\ntype Tone = 'neutral' | 'info' | 'warning' | 'success' | 'error';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary',\n info: 'bg-status-info-subtle text-status-info-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n success: 'bg-status-success-subtle text-status-success-text',\n error: 'bg-status-error-subtle text-status-error-text',\n};\nconst TONE_CSS: Record<Tone, string> = {\n neutral: 'var(--color-text-muted)',\n info: chartTokens.status.info,\n warning: chartTokens.status.warning,\n success: chartTokens.status.success,\n error: chartTokens.status.danger,\n};\n\nconst RISK_TONE: Record<string, Tone> = {\n critical: 'error',\n high: 'warning',\n medium: 'info',\n low: 'success',\n};\nconst STATUS_TONE: Record<string, Tone> = {\n draft: 'neutral',\n submitted: 'info',\n approved: 'success',\n rejected: 'error',\n in_progress: 'info',\n completed: 'success',\n};\nconst TYPE_TONE: Record<string, Tone> = {\n emergency: 'error',\n standard: 'info',\n normal: 'neutral',\n};\n\nfunction Pill({ tone, children }: { tone: Tone; children: ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center whitespace-nowrap rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n TONE_CLASS[tone]\n )}\n >\n {children}\n </span>\n );\n}\n\nconst humanize = (v: string) => v.replace(/_/g, ' ');\n\nconst initials = (name: string) =>\n name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? '')\n .join('') || '?';\n\nfunction relTime(dateStr: string): string {\n const t = new Date(dateStr).getTime();\n if (Number.isNaN(t)) return '';\n const diff = Date.now() - t;\n const min = Math.round(diff / 60000);\n if (min < 1) return 'just now';\n if (min < 60) return `${min}m ago`;\n const h = Math.round(min / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\nfunction Avatar({ name }: { name: string }) {\n return (\n <span className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary ring-2 ring-bg-surface\">\n {initials(name)}\n </span>\n );\n}\n\n/* ── approve / reject mutations ───────────────────────────────────────── */\nconst APPROVE_CHANGE_MUTATION = gql`\n mutation AssetHandlerApproveChangeList($id: ID!) {\n approveChangeRequest(id: $id) {\n id\n status\n }\n }\n`;\nconst REJECT_CHANGE_MUTATION = gql`\n mutation AssetHandlerRejectChangeList($id: ID!, $reason: String) {\n rejectChangeRequest(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\nconst isActionable = (status: string) =>\n status !== 'approved' && status !== 'rejected' && status !== 'completed';\n\n/* ── detail-preview panel ─────────────────────────────────────────────── */\nfunction ChangeDetail({\n change,\n onApprove,\n onReject,\n busy,\n}: {\n change: ChangeRequest;\n onApprove: () => void;\n onReject: () => void;\n busy: boolean;\n}) {\n return (\n <div className=\"space-y-5\">\n <div>\n <p className=\"font-mono text-xs text-text-secondary\">{change.id}</p>\n <h3 className=\"mt-1 text-base font-semibold text-text-primary\">{change.title}</h3>\n {change.description ? (\n <p className=\"mt-1 text-sm text-text-secondary\">{change.description}</p>\n ) : null}\n </div>\n\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd>\n <Pill tone={TYPE_TONE[change.type] ?? 'neutral'}>{change.type}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Risk</dt>\n <dd>\n <Pill tone={RISK_TONE[change.risk] ?? 'neutral'}>{change.risk}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Pill tone={STATUS_TONE[change.status] ?? 'neutral'}>{humanize(change.status)}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Scheduled</dt>\n <dd className=\"tabular-nums text-text-primary\">\n {change.scheduledStart ? new Date(change.scheduledStart).toLocaleDateString() : '—'}\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Requested by</dt>\n <dd className=\"text-text-primary\">{change.requestedBy || '—'}</dd>\n </div>\n </dl>\n\n {isActionable(change.status) ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <Button onClick={onApprove} disabled={busy}>\n {busy ? (\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"mr-2 h-4 w-4\" />\n )}\n Approve\n </Button>\n <Button\n variant=\"outline\"\n className=\"text-status-error-text\"\n onClick={onReject}\n disabled={busy}\n >\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n </div>\n ) : null}\n\n <div>\n <h4 className=\"mb-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Approvals\n </h4>\n {change.approvals.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No approvers assigned yet.</p>\n ) : (\n <ul className=\"space-y-3\">\n {change.approvals.map((a, i) => {\n const approved = a.status === 'approved';\n const rejected = a.status === 'rejected';\n return (\n <li key={`${a.name}-${i}`} className=\"flex items-center gap-3\">\n <span className=\"relative\">\n <Avatar name={a.name} />\n <span\n className={cn(\n 'absolute -bottom-0.5 -right-0.5 flex h-3.5 w-3.5 items-center justify-center rounded-full ring-2 ring-bg-surface',\n approved\n ? 'bg-status-success-bg'\n : rejected\n ? 'bg-status-error-bg'\n : 'bg-bg-sunken'\n )}\n >\n {approved ? (\n <Check className=\"h-2.5 w-2.5 text-status-success-text\" />\n ) : rejected ? (\n <X className=\"h-2.5 w-2.5 text-status-error-text\" />\n ) : null}\n </span>\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {humanize(a.status)}\n {a.date ? ` · ${relTime(a.date)}` : ''}\n </p>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n );\n}\n\n/* ── page ─────────────────────────────────────────────────────────────── */\nexport function ItilChangeManagementPage() {\n const { changeRequests } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('all');\n const [riskFilter, setRiskFilter] = useState('all');\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobileOpen, setMobileOpen] = useState(false);\n const [checked, setChecked] = useState<Set<string>>(new Set());\n\n const counts = useMemo(() => {\n let approved = 0;\n let submitted = 0;\n let completed = 0;\n for (const c of changeRequests) {\n if (c.status === 'approved') approved += 1;\n else if (c.status === 'submitted') submitted += 1;\n else if (c.status === 'completed') completed += 1;\n }\n return { approved, submitted, completed };\n }, [changeRequests]);\n\n const statusData = useMemo(() => {\n const order = ['draft', 'submitted', 'approved', 'in_progress', 'completed', 'rejected'];\n const map = new Map<string, number>();\n for (const c of changeRequests) map.set(c.status, (map.get(c.status) ?? 0) + 1);\n return order\n .filter((s) => map.get(s))\n .map((s) => ({\n name: humanize(s).replace(/^\\w/, (ch) => ch.toUpperCase()),\n value: map.get(s) ?? 0,\n color: TONE_CSS[STATUS_TONE[s] ?? 'neutral'],\n }));\n }, [changeRequests]);\n\n const riskData = useMemo(() => {\n const order = ['critical', 'high', 'medium', 'low'];\n const map = new Map<string, number>();\n for (const c of changeRequests) map.set(c.risk, (map.get(c.risk) ?? 0) + 1);\n return order\n .filter((r) => map.get(r))\n .map((r) => ({ risk: r.replace(/^\\w/, (ch) => ch.toUpperCase()), count: map.get(r) ?? 0 }));\n }, [changeRequests]);\n\n const filtered = useMemo(\n () =>\n changeRequests.filter((c) => {\n const q = search.trim().toLowerCase();\n const matchSearch =\n q === '' ||\n c.title.toLowerCase().includes(q) ||\n c.id.toLowerCase().includes(q) ||\n (c.requestedBy ?? '').toLowerCase().includes(q) ||\n (c.assignedTo ?? '').toLowerCase().includes(q);\n const matchStatus = statusFilter === 'all' || c.status === statusFilter;\n const matchRisk = riskFilter === 'all' || c.risk === riskFilter;\n return matchSearch && matchStatus && matchRisk;\n }),\n [changeRequests, search, statusFilter, riskFilter]\n );\n\n const pager = usePagination(filtered, {\n pageSize: 10,\n resetKey: `${search}|${statusFilter}|${riskFilter}`,\n });\n\n const selected = selectedId ? (changeRequests.find((c) => c.id === selectedId) ?? null) : null;\n\n const [approveChange, { loading: approving }] = useMutation(APPROVE_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => notify.success('Change approved', 'The change request has been approved.'),\n onError: (error) => notify.error('Could not approve change', error.message),\n });\n const [rejectChange, { loading: rejecting }] = useMutation(REJECT_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => notify.success('Change rejected', 'The change request has been rejected.'),\n onError: (error) => notify.error('Could not reject change', error.message),\n });\n const busy = approving || rejecting;\n\n const openChange = (id: string) => {\n setSelectedId(id);\n if (typeof window !== 'undefined' && window.matchMedia('(max-width: 1023px)').matches) {\n setMobileOpen(true);\n }\n };\n\n const pageIds = pager.pageItems.map((c) => c.id);\n const allPageChecked = pageIds.length > 0 && pageIds.every((id) => checked.has(id));\n const toggleAll = () =>\n setChecked((prev) => {\n const next = new Set(prev);\n if (allPageChecked) pageIds.forEach((id) => next.delete(id));\n else pageIds.forEach((id) => next.add(id));\n return next;\n });\n const toggleOne = (id: string) =>\n setChecked((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const exportRows = (rows: ChangeRequest[]) => {\n downloadCsv(\n 'change-requests',\n ['ID', 'Title', 'Type', 'Risk', 'Status', 'Requested By', 'Scheduled'],\n rows.map((c) => [\n c.id,\n c.title,\n c.type,\n c.risk,\n c.status,\n c.requestedBy,\n c.scheduledStart ? new Date(c.scheduledStart).toLocaleDateString() : '',\n ])\n );\n };\n\n const selectedRows = filtered.filter((c) => checked.has(c.id));\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n ITIL Change Management\n </p>\n <SectionHeader\n hero\n spaced={false}\n title=\"Change Management\"\n description=\"Plan and govern every change to your assets and services so nothing breaks unexpectedly — capture, risk-assess, route for approval and schedule a safe window.\"\n actions={\n <div className=\"flex w-full gap-2 sm:w-auto\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1 sm:flex-none\"\n onClick={() => exportRows(filtered)}\n disabled={filtered.length === 0}\n >\n <Download className=\"mr-2 h-4 w-4\" />\n Export\n </Button>\n <Button size=\"sm\" className=\"flex-1 sm:flex-none\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n New Change Request\n </Button>\n </div>\n }\n />\n\n <NewChangeRequestDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n {/* KPI row */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatTile hero label=\"Total\" value={changeRequests.length} />\n <StatTile label=\"Submitted\" value={counts.submitted} />\n <StatTile label=\"Approved\" value={counts.approved} />\n <StatTile label=\"Completed\" value={counts.completed} />\n </div>\n\n {/* analytics */}\n {changeRequests.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2\">\n <ChartCard title=\"Status distribution\" subtitle=\"Across the board\" icon={PieIcon}>\n <DonutChart\n data={statusData}\n height={220}\n centerLabel=\"Changes\"\n centerValue={changeRequests.length}\n ariaLabel=\"Change requests by status\"\n />\n </ChartCard>\n <ChartCard title=\"Risk mix\" subtitle=\"Governance signal\" icon={BarChart3}>\n <BarsChart\n data={riskData}\n xKey=\"risk\"\n orientation=\"horizontal\"\n height={220}\n series={[{ key: 'count', label: 'Changes', color: chartTokens.brand }]}\n ariaLabel=\"Change requests by risk\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"grid gap-4 lg:grid-cols-[1fr_340px]\">\n {/* list column */}\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 rounded-xl border border-border-seam bg-bg-surface p-3 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search change requests…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[150px]\">\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n <SelectItem value=\"draft\">Draft</SelectItem>\n <SelectItem value=\"submitted\">Submitted</SelectItem>\n <SelectItem value=\"approved\">Approved</SelectItem>\n <SelectItem value=\"in_progress\">In Progress</SelectItem>\n <SelectItem value=\"completed\">Completed</SelectItem>\n <SelectItem value=\"rejected\">Rejected</SelectItem>\n </SelectContent>\n </Select>\n <Select value={riskFilter} onValueChange={setRiskFilter}>\n <SelectTrigger className=\"w-full sm:w-[130px]\">\n <SelectValue placeholder=\"Risk\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All risk</SelectItem>\n <SelectItem value=\"critical\">Critical</SelectItem>\n <SelectItem value=\"high\">High</SelectItem>\n <SelectItem value=\"medium\">Medium</SelectItem>\n <SelectItem value=\"low\">Low</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {checked.size > 0 ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2 rounded-lg bg-bg-sunken px-3 py-2 text-sm\">\n <span className=\"text-text-secondary\">{checked.size} selected</span>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => exportRows(selectedRows)}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export selected\n </Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setChecked(new Set())}>\n Clear\n </Button>\n </div>\n </div>\n ) : null}\n\n {filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration={changeRequests.length === 0 ? 'empty-generic' : 'empty-search'}\n title={changeRequests.length === 0 ? 'No change requests' : 'No matching changes'}\n description={\n changeRequests.length === 0\n ? 'Raise a change request to plan and risk-assess updates to your assets.'\n : 'No change requests match your search or filters.'\n }\n />\n ) : (\n <ChartCard title=\"Change requests\" subtitle={`${filtered.length} shown`}>\n {/* desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"w-10 p-3\">\n <Checkbox\n checked={allPageChecked}\n onCheckedChange={toggleAll}\n aria-label=\"Select all\"\n />\n </th>\n <th className=\"p-3 font-medium\">ID</th>\n <th className=\"p-3 font-medium\">Title</th>\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Risk</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Scheduled</th>\n <th className=\"p-3 font-medium\">Approvals</th>\n </tr>\n </thead>\n <tbody>\n {pager.pageItems.map((chg) => (\n <tr\n key={chg.id}\n className={cn(\n 'cursor-pointer border-b border-border-seam/60 hover:bg-bg-sunken/50',\n selectedId === chg.id && 'bg-bg-sunken/60'\n )}\n onClick={() => openChange(chg.id)}\n >\n <td className=\"p-3\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={checked.has(chg.id)}\n onCheckedChange={() => toggleOne(chg.id)}\n aria-label={`Select ${chg.id}`}\n />\n </td>\n <td className=\"p-3 font-mono text-xs\">{chg.id}</td>\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\" title={chg.title}>\n {chg.title}\n </p>\n </td>\n <td className=\"p-3\">\n <Pill tone={TYPE_TONE[chg.type] ?? 'neutral'}>{chg.type}</Pill>\n </td>\n <td className=\"p-3\">\n <Pill tone={RISK_TONE[chg.risk] ?? 'neutral'}>{chg.risk}</Pill>\n </td>\n <td className=\"p-3\">\n <Pill tone={STATUS_TONE[chg.status] ?? 'neutral'}>\n {humanize(chg.status)}\n </Pill>\n </td>\n <td className=\"p-3 text-xs tabular-nums\">\n {chg.scheduledStart\n ? new Date(chg.scheduledStart).toLocaleDateString()\n : '—'}\n </td>\n <td className=\"p-3\">\n {chg.approvals.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">Pending</span>\n ) : (\n <div className=\"flex -space-x-2\">\n {chg.approvals.slice(0, 3).map((a, i) => (\n <Avatar key={`${a.name}-${i}`} name={a.name} />\n ))}\n {chg.approvals.length > 3 ? (\n <span className=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary ring-2 ring-bg-surface\">\n +{chg.approvals.length - 3}\n </span>\n ) : null}\n </div>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {/* mobile cards */}\n <ul className=\"space-y-3 md:hidden\">\n {pager.pageItems.map((chg) => (\n <li key={chg.id}>\n <button\n type=\"button\"\n className=\"w-full rounded-xl border border-border-seam bg-bg-surface p-4 text-left\"\n onClick={() => openChange(chg.id)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{chg.title}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{chg.id}</p>\n </div>\n <Pill tone={STATUS_TONE[chg.status] ?? 'neutral'}>\n {humanize(chg.status)}\n </Pill>\n </div>\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Pill tone={TYPE_TONE[chg.type] ?? 'neutral'}>{chg.type}</Pill>\n <Pill tone={RISK_TONE[chg.risk] ?? 'neutral'}>{chg.risk}</Pill>\n </div>\n </button>\n </li>\n ))}\n </ul>\n\n <div className=\"pt-3\">\n <Pagination\n page={pager.page}\n pageCount={pager.pageCount}\n rangeStart={pager.rangeStart}\n rangeEnd={pager.rangeEnd}\n totalItems={pager.totalItems}\n canPrev={pager.canPrev}\n canNext={pager.canNext}\n onPrev={pager.prevPage}\n onNext={pager.nextPage}\n itemLabel=\"changes\"\n />\n </div>\n </ChartCard>\n )}\n </div>\n\n {/* desktop detail-preview rail */}\n <div className=\"hidden lg:block\">\n <div className=\"sticky top-4\">\n <ChartCard title=\"Detail preview\">\n {selected ? (\n <ChangeDetail\n change={selected}\n busy={busy}\n onApprove={() => void approveChange({ variables: { id: selected.id } })}\n onReject={() =>\n void rejectChange({ variables: { id: selected.id, reason: null } })\n }\n />\n ) : (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n Select a change request to preview its risk, schedule and approval chain.\n </p>\n )}\n </ChartCard>\n </div>\n </div>\n </div>\n\n <PagePurpose>\n Capture the change, assess its risk, route it for approval, and schedule it for a safe\n window — giving you a controlled, auditable trail of what changed, when and why.\n </PagePurpose>\n\n {/* mobile detail sheet */}\n <ResponsiveDialog\n open={mobileOpen}\n onOpenChange={(open) => {\n setMobileOpen(open);\n if (!open) setSelectedId(null);\n }}\n >\n <ResponsiveDialogContent className=\"max-h-[88vh] overflow-y-auto sm:max-w-lg\">\n {selected ? (\n <ChangeDetail\n change={selected}\n busy={busy}\n onApprove={() => void approveChange({ variables: { id: selected.id } })}\n onReject={() => void rejectChange({ variables: { id: selected.id, reason: null } })}\n />\n ) : null}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ItilChangeManagementPage.js","names":[],"sources":["../../../src/assethandler/pages/ItilChangeManagementPage.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from 'react';\nimport {\n Button,\n Input,\n Checkbox,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n Check,\n X,\n Download,\n CheckCircle2,\n XCircle,\n PieChart as PieIcon,\n BarChart3,\n Loader2,\n} from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore, type ChangeRequest } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n chartTokens,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\nimport { downloadCsv } from '../utils/csv';\nimport { NewChangeRequestDialog } from './ItilDialogs';\n\ntype Tone = 'neutral' | 'info' | 'warning' | 'success' | 'error';\n\nconst TONE_CLASS: Record<Tone, string> = {\n neutral: 'bg-bg-sunken text-text-secondary',\n info: 'bg-status-info-subtle text-status-info-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n success: 'bg-status-success-subtle text-status-success-text',\n error: 'bg-status-error-subtle text-status-error-text',\n};\nconst TONE_CSS: Record<Tone, string> = {\n neutral: 'var(--color-text-muted)',\n info: chartTokens.status.info,\n warning: chartTokens.status.warning,\n success: chartTokens.status.success,\n error: chartTokens.status.danger,\n};\n\nconst RISK_TONE: Record<string, Tone> = {\n critical: 'error',\n high: 'warning',\n medium: 'info',\n low: 'success',\n};\nconst STATUS_TONE: Record<string, Tone> = {\n draft: 'neutral',\n submitted: 'info',\n approved: 'success',\n rejected: 'error',\n in_progress: 'info',\n completed: 'success',\n};\nconst TYPE_TONE: Record<string, Tone> = {\n emergency: 'error',\n standard: 'info',\n normal: 'neutral',\n};\n\nfunction Pill({ tone, children }: { tone: Tone; children: ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center whitespace-nowrap rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n TONE_CLASS[tone]\n )}\n >\n {children}\n </span>\n );\n}\n\nconst humanize = (v: string) => v.replace(/_/g, ' ');\n\nconst initials = (name: string) =>\n name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? '')\n .join('') || '?';\n\nfunction relTime(dateStr: string): string {\n const t = new Date(dateStr).getTime();\n if (Number.isNaN(t)) return '';\n const diff = Date.now() - t;\n const min = Math.round(diff / 60000);\n if (min < 1) return 'just now';\n if (min < 60) return `${min}m ago`;\n const h = Math.round(min / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\nfunction Avatar({ name }: { name: string }) {\n return (\n <span className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary ring-2 ring-bg-surface\">\n {initials(name)}\n </span>\n );\n}\n\n/* ── approve / reject mutations ───────────────────────────────────────── */\nconst APPROVE_CHANGE_MUTATION = gql`\n mutation AssetHandlerApproveChangeList($id: ID!) {\n approveChangeRequest(id: $id) {\n id\n status\n }\n }\n`;\nconst REJECT_CHANGE_MUTATION = gql`\n mutation AssetHandlerRejectChangeList($id: ID!, $reason: String) {\n rejectChangeRequest(id: $id, reason: $reason) {\n id\n status\n }\n }\n`;\n\nconst isActionable = (status: string) =>\n status !== 'approved' && status !== 'rejected' && status !== 'completed';\n\n/* ── detail-preview panel ─────────────────────────────────────────────── */\nfunction ChangeDetail({\n change,\n onApprove,\n onReject,\n busy,\n}: {\n change: ChangeRequest;\n onApprove: () => void;\n onReject: () => void;\n busy: boolean;\n}) {\n return (\n <div className=\"space-y-5\">\n <div>\n <p className=\"font-mono text-xs text-text-secondary\">{change.id}</p>\n <h3 className=\"mt-1 text-base font-semibold text-text-primary\">{change.title}</h3>\n {change.description ? (\n <p className=\"mt-1 text-sm text-text-secondary\">{change.description}</p>\n ) : null}\n </div>\n\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Type</dt>\n <dd>\n <Pill tone={TYPE_TONE[change.type] ?? 'neutral'}>{change.type}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Risk</dt>\n <dd>\n <Pill tone={RISK_TONE[change.risk] ?? 'neutral'}>{change.risk}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Pill tone={STATUS_TONE[change.status] ?? 'neutral'}>{humanize(change.status)}</Pill>\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Scheduled</dt>\n <dd className=\"tabular-nums text-text-primary\">\n {change.scheduledStart ? new Date(change.scheduledStart).toLocaleDateString() : '—'}\n </dd>\n </div>\n <div className=\"flex items-center justify-between\">\n <dt className=\"text-text-secondary\">Requested by</dt>\n <dd className=\"text-text-primary\">{change.requestedBy || '—'}</dd>\n </div>\n </dl>\n\n {isActionable(change.status) ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <Button onClick={onApprove} disabled={busy}>\n {busy ? (\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n ) : (\n <CheckCircle2 className=\"mr-2 h-4 w-4\" />\n )}\n Approve\n </Button>\n <Button\n variant=\"outline\"\n className=\"text-status-error-text\"\n onClick={onReject}\n disabled={busy}\n >\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n </div>\n ) : null}\n\n <div>\n <h4 className=\"mb-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Approvals\n </h4>\n {change.approvals.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">No approvers assigned yet.</p>\n ) : (\n <ul className=\"space-y-3\">\n {change.approvals.map((a, i) => {\n const approved = a.status === 'approved';\n const rejected = a.status === 'rejected';\n return (\n <li key={`${a.name}-${i}`} className=\"flex items-center gap-3\">\n <span className=\"relative\">\n <Avatar name={a.name} />\n <span\n className={cn(\n 'absolute -bottom-0.5 -right-0.5 flex h-3.5 w-3.5 items-center justify-center rounded-full ring-2 ring-bg-surface',\n approved\n ? 'bg-status-success-bg'\n : rejected\n ? 'bg-status-error-bg'\n : 'bg-bg-sunken'\n )}\n >\n {approved ? (\n <Check className=\"h-2.5 w-2.5 text-status-success-text\" />\n ) : rejected ? (\n <X className=\"h-2.5 w-2.5 text-status-error-text\" />\n ) : null}\n </span>\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {humanize(a.status)}\n {a.date ? ` · ${relTime(a.date)}` : ''}\n </p>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n );\n}\n\n/* ── page ─────────────────────────────────────────────────────────────── */\nexport function ItilChangeManagementPage() {\n const { changeRequests } = useAssetHandlerStore();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('all');\n const [riskFilter, setRiskFilter] = useState('all');\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobileOpen, setMobileOpen] = useState(false);\n const [checked, setChecked] = useState<Set<string>>(new Set());\n\n const counts = useMemo(() => {\n let approved = 0;\n let submitted = 0;\n let completed = 0;\n for (const c of changeRequests) {\n if (c.status === 'approved') approved += 1;\n else if (c.status === 'submitted') submitted += 1;\n else if (c.status === 'completed') completed += 1;\n }\n return { approved, submitted, completed };\n }, [changeRequests]);\n\n const statusData = useMemo(() => {\n const order = ['draft', 'submitted', 'approved', 'in_progress', 'completed', 'rejected'];\n const map = new Map<string, number>();\n for (const c of changeRequests) map.set(c.status, (map.get(c.status) ?? 0) + 1);\n return order\n .filter((s) => map.get(s))\n .map((s) => ({\n name: humanize(s).replace(/^\\w/, (ch) => ch.toUpperCase()),\n value: map.get(s) ?? 0,\n color: TONE_CSS[STATUS_TONE[s] ?? 'neutral'],\n }));\n }, [changeRequests]);\n\n const riskData = useMemo(() => {\n const order = ['critical', 'high', 'medium', 'low'];\n const map = new Map<string, number>();\n for (const c of changeRequests) map.set(c.risk, (map.get(c.risk) ?? 0) + 1);\n return order\n .filter((r) => map.get(r))\n .map((r) => ({ risk: r.replace(/^\\w/, (ch) => ch.toUpperCase()), count: map.get(r) ?? 0 }));\n }, [changeRequests]);\n\n const filtered = useMemo(\n () =>\n changeRequests.filter((c) => {\n const q = search.trim().toLowerCase();\n const matchSearch =\n q === '' ||\n c.title.toLowerCase().includes(q) ||\n c.id.toLowerCase().includes(q) ||\n (c.requestedBy ?? '').toLowerCase().includes(q) ||\n (c.assignedTo ?? '').toLowerCase().includes(q);\n const matchStatus = statusFilter === 'all' || c.status === statusFilter;\n const matchRisk = riskFilter === 'all' || c.risk === riskFilter;\n return matchSearch && matchStatus && matchRisk;\n }),\n [changeRequests, search, statusFilter, riskFilter]\n );\n\n const pager = usePagination(filtered, {\n pageSize: 10,\n resetKey: `${search}|${statusFilter}|${riskFilter}`,\n });\n\n const selected = selectedId ? (changeRequests.find((c) => c.id === selectedId) ?? null) : null;\n\n const [approveChange, { loading: approving }] = useMutation(APPROVE_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => notify.success('Change approved', 'The change request has been approved.'),\n onError: (error) => notify.error('Could not approve change', error.message),\n });\n const [rejectChange, { loading: rejecting }] = useMutation(REJECT_CHANGE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => notify.success('Change rejected', 'The change request has been rejected.'),\n onError: (error) => notify.error('Could not reject change', error.message),\n });\n const busy = approving || rejecting;\n\n const openChange = (id: string) => {\n setSelectedId(id);\n if (typeof window !== 'undefined' && window.matchMedia('(max-width: 1023px)').matches) {\n setMobileOpen(true);\n }\n };\n\n const pageIds = pager.pageItems.map((c) => c.id);\n const allPageChecked = pageIds.length > 0 && pageIds.every((id) => checked.has(id));\n const toggleAll = () =>\n setChecked((prev) => {\n const next = new Set(prev);\n if (allPageChecked) pageIds.forEach((id) => next.delete(id));\n else pageIds.forEach((id) => next.add(id));\n return next;\n });\n const toggleOne = (id: string) =>\n setChecked((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const exportRows = (rows: ChangeRequest[]) => {\n downloadCsv(\n 'change-requests',\n ['ID', 'Title', 'Type', 'Risk', 'Status', 'Requested By', 'Scheduled'],\n rows.map((c) => [\n c.id,\n c.title,\n c.type,\n c.risk,\n c.status,\n c.requestedBy,\n c.scheduledStart ? new Date(c.scheduledStart).toLocaleDateString() : '',\n ])\n );\n };\n\n const selectedRows = filtered.filter((c) => checked.has(c.id));\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <p className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n ITIL Change Management\n </p>\n <SectionHeader\n hero\n spaced={false}\n title=\"Change Management\"\n description=\"Plan and govern every change to your assets and services so nothing breaks unexpectedly — capture, risk-assess, route for approval and schedule a safe window.\"\n actions={\n <div className=\"flex w-full gap-2 sm:w-auto\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1 sm:flex-none\"\n onClick={() => exportRows(filtered)}\n disabled={filtered.length === 0}\n >\n <Download className=\"mr-2 h-4 w-4\" />\n Export\n </Button>\n <Button size=\"sm\" className=\"flex-1 sm:flex-none\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n New Change Request\n </Button>\n </div>\n }\n />\n\n <NewChangeRequestDialog open={dialogOpen} onOpenChange={setDialogOpen} />\n\n {/* KPI row */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatTile hero label=\"Total\" value={changeRequests.length} />\n <StatTile label=\"Submitted\" value={counts.submitted} />\n <StatTile label=\"Approved\" value={counts.approved} />\n <StatTile label=\"Completed\" value={counts.completed} />\n </div>\n\n {/* analytics */}\n {changeRequests.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2\">\n <ChartCard title=\"Status distribution\" subtitle=\"Across the board\" icon={PieIcon}>\n <DonutChart\n data={statusData}\n height={220}\n centerLabel=\"Changes\"\n centerValue={changeRequests.length}\n ariaLabel=\"Change requests by status\"\n />\n </ChartCard>\n <ChartCard title=\"Risk mix\" subtitle=\"Governance signal\" icon={BarChart3}>\n <BarsChart\n data={riskData}\n xKey=\"risk\"\n orientation=\"horizontal\"\n height={220}\n series={[{ key: 'count', label: 'Changes', color: chartTokens.brand }]}\n ariaLabel=\"Change requests by risk\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"grid gap-4 lg:grid-cols-[1fr_340px]\">\n {/* list column */}\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 rounded-xl border border-border-seam bg-bg-surface p-3 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search change requests…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[150px]\">\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n <SelectItem value=\"draft\">Draft</SelectItem>\n <SelectItem value=\"submitted\">Submitted</SelectItem>\n <SelectItem value=\"approved\">Approved</SelectItem>\n <SelectItem value=\"in_progress\">In Progress</SelectItem>\n <SelectItem value=\"completed\">Completed</SelectItem>\n <SelectItem value=\"rejected\">Rejected</SelectItem>\n </SelectContent>\n </Select>\n <Select value={riskFilter} onValueChange={setRiskFilter}>\n <SelectTrigger className=\"w-full sm:w-[130px]\">\n <SelectValue placeholder=\"Risk\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All risk</SelectItem>\n <SelectItem value=\"critical\">Critical</SelectItem>\n <SelectItem value=\"high\">High</SelectItem>\n <SelectItem value=\"medium\">Medium</SelectItem>\n <SelectItem value=\"low\">Low</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {checked.size > 0 ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2 rounded-lg bg-bg-sunken px-3 py-2 text-sm\">\n <span className=\"text-text-secondary\">{checked.size} selected</span>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => exportRows(selectedRows)}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export selected\n </Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setChecked(new Set())}>\n Clear\n </Button>\n </div>\n </div>\n ) : null}\n\n {filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration={changeRequests.length === 0 ? 'empty-generic' : 'empty-search'}\n title={changeRequests.length === 0 ? 'No change requests' : 'No matching changes'}\n description={\n changeRequests.length === 0\n ? 'Raise a change request to plan and risk-assess updates to your assets.'\n : 'No change requests match your search or filters.'\n }\n />\n ) : (\n <ChartCard title=\"Change requests\" subtitle={`${filtered.length} shown`}>\n {/* desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"w-10 p-3\">\n <Checkbox\n checked={allPageChecked}\n onCheckedChange={toggleAll}\n aria-label=\"Select all\"\n />\n </th>\n <th className=\"p-3 font-medium\">ID</th>\n <th className=\"p-3 font-medium\">Title</th>\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Risk</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Scheduled</th>\n <th className=\"p-3 font-medium\">Approvals</th>\n </tr>\n </thead>\n <tbody>\n {pager.pageItems.map((chg) => (\n <tr\n key={chg.id}\n className={cn(\n 'cursor-pointer border-b border-border-seam/60 hover:bg-bg-sunken/50',\n selectedId === chg.id && 'bg-bg-sunken/60'\n )}\n onClick={() => openChange(chg.id)}\n >\n <td className=\"p-3\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={checked.has(chg.id)}\n onCheckedChange={() => toggleOne(chg.id)}\n aria-label={`Select ${chg.id}`}\n />\n </td>\n <td className=\"p-3 font-mono text-xs\">{chg.id}</td>\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\" title={chg.title}>\n {chg.title}\n </p>\n </td>\n <td className=\"p-3\">\n <Pill tone={TYPE_TONE[chg.type] ?? 'neutral'}>{chg.type}</Pill>\n </td>\n <td className=\"p-3\">\n <Pill tone={RISK_TONE[chg.risk] ?? 'neutral'}>{chg.risk}</Pill>\n </td>\n <td className=\"p-3\">\n <Pill tone={STATUS_TONE[chg.status] ?? 'neutral'}>\n {humanize(chg.status)}\n </Pill>\n </td>\n <td className=\"p-3 text-xs tabular-nums\">\n {chg.scheduledStart\n ? new Date(chg.scheduledStart).toLocaleDateString()\n : '—'}\n </td>\n <td className=\"p-3\">\n {chg.approvals.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">Pending</span>\n ) : (\n <div className=\"flex -space-x-2\">\n {chg.approvals.slice(0, 3).map((a, i) => (\n <Avatar key={`${a.name}-${i}`} name={a.name} />\n ))}\n {chg.approvals.length > 3 ? (\n <span className=\"inline-flex h-7 w-7 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary ring-2 ring-bg-surface\">\n +{chg.approvals.length - 3}\n </span>\n ) : null}\n </div>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {/* mobile cards */}\n <ul className=\"space-y-3 md:hidden\">\n {pager.pageItems.map((chg) => (\n <li key={chg.id}>\n <button\n type=\"button\"\n className=\"w-full rounded-xl border border-border-seam bg-bg-surface p-4 text-left\"\n onClick={() => openChange(chg.id)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{chg.title}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{chg.id}</p>\n </div>\n <Pill tone={STATUS_TONE[chg.status] ?? 'neutral'}>\n {humanize(chg.status)}\n </Pill>\n </div>\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Pill tone={TYPE_TONE[chg.type] ?? 'neutral'}>{chg.type}</Pill>\n <Pill tone={RISK_TONE[chg.risk] ?? 'neutral'}>{chg.risk}</Pill>\n </div>\n </button>\n </li>\n ))}\n </ul>\n\n <div className=\"pt-3\">\n <Pagination\n page={pager.page}\n pageCount={pager.pageCount}\n rangeStart={pager.rangeStart}\n rangeEnd={pager.rangeEnd}\n totalItems={pager.totalItems}\n canPrev={pager.canPrev}\n canNext={pager.canNext}\n onPrev={pager.prevPage}\n onNext={pager.nextPage}\n itemLabel=\"changes\"\n />\n </div>\n </ChartCard>\n )}\n </div>\n\n {/* desktop detail-preview rail */}\n <div className=\"hidden lg:block\">\n <div className=\"sticky top-4\">\n <ChartCard title=\"Detail preview\">\n {selected ? (\n <ChangeDetail\n change={selected}\n busy={busy}\n onApprove={() => void approveChange({ variables: { id: selected.id } })}\n onReject={() =>\n void rejectChange({ variables: { id: selected.id, reason: null } })\n }\n />\n ) : (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n Select a change request to preview its risk, schedule and approval chain.\n </p>\n )}\n </ChartCard>\n </div>\n </div>\n </div>\n\n <PagePurpose>\n Capture the change, assess its risk, route it for approval, and schedule it for a safe\n window — giving you a controlled, auditable trail of what changed, when and why.\n </PagePurpose>\n\n {/* mobile detail sheet */}\n <ResponsiveDialog\n open={mobileOpen}\n onOpenChange={(open) => {\n setMobileOpen(open);\n if (!open) setSelectedId(null);\n }}\n >\n <ResponsiveDialogContent className=\"max-h-[88vh] overflow-y-auto sm:max-w-lg\">\n {selected ? (\n <ChangeDetail\n change={selected}\n busy={busy}\n onApprove={() => void approveChange({ variables: { id: selected.id } })}\n onReject={() => void rejectChange({ variables: { id: selected.id, reason: null } })}\n />\n ) : null}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+CA,IAAM,IAAmC;CACvC,SAAS;CACT,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACT,GACM,KAAiC;CACrC,SAAS;CACT,MAAM,EAAY,OAAO;CACzB,SAAS,EAAY,OAAO;CAC5B,SAAS,EAAY,OAAO;CAC5B,OAAO,EAAY,OAAO;AAC5B,GAEM,IAAkC;CACtC,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;AACP,GACM,IAAoC;CACxC,OAAO;CACP,WAAW;CACX,UAAU;CACV,UAAU;CACV,aAAa;CACb,WAAW;AACb,GACM,IAAkC;CACtC,WAAW;CACX,UAAU;CACV,QAAQ;AACV;AAEA,SAAS,EAAK,EAAE,SAAM,eAAiD;CACrE,OACE,kBAAC,QAAD;EACE,WAAW,EACT,sGACA,EAAW,EACb;EAEC;CACG,CAAA;AAEV;AAEA,IAAM,KAAY,MAAc,EAAE,QAAQ,MAAM,GAAG,GAE7C,KAAY,MAChB,EACG,MAAM,KAAK,EACX,OAAO,OAAO,EACd,MAAM,GAAG,CAAC,EACV,KAAK,MAAM,EAAE,IAAI,YAAY,KAAK,EAAE,EACpC,KAAK,EAAE,KAAK;AAEjB,SAAS,EAAQ,GAAyB;CACxC,IAAM,IAAI,IAAI,KAAK,CAAO,EAAE,QAAQ;CACpC,IAAI,OAAO,MAAM,CAAC,GAAG,OAAO;CAC5B,IAAM,IAAO,KAAK,IAAI,IAAI,GACpB,IAAM,KAAK,MAAM,IAAO,GAAK;CACnC,IAAI,IAAM,GAAG,OAAO;CACpB,IAAI,IAAM,IAAI,OAAO,GAAG,EAAI;CAC5B,IAAM,IAAI,KAAK,MAAM,IAAM,EAAE;CAE7B,OADI,IAAI,KAAW,GAAG,EAAE,SACjB,GAAG,KAAK,MAAM,IAAI,EAAE,EAAE;AAC/B;AAEA,SAAS,EAAO,EAAE,WAA0B;CAC1C,OACE,kBAAC,QAAD;EAAM,WAAU;YACb,EAAS,CAAI;CACV,CAAA;AAEV;AAGA,IAAM,KAA0B,CAAG;;;;;;;GAQ7B,KAAyB,CAAG;;;;;;;GAS5B,KAAgB,MACpB,MAAW,cAAc,MAAW,cAAc,MAAW;AAG/D,SAAS,EAAa,EACpB,WACA,cACA,aACA,WAMC;CACD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,KAAD;KAAG,WAAU;eAAyC,EAAO;IAAM,CAAA;IACnE,kBAAC,MAAD;KAAI,WAAU;eAAkD,EAAO;IAAU,CAAA;IAChF,EAAO,cACN,kBAAC,KAAD;KAAG,WAAU;eAAoC,EAAO;IAAe,CAAA,IACrE;GACD,EAAA,CAAA;GAEL,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsB;MAAQ,CAAA,GAC5C,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;OAAM,MAAM,EAAU,EAAO,SAAS;iBAAY,EAAO;MAAW,CAAA,EAClE,CAAA,CACD;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsB;MAAQ,CAAA,GAC5C,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;OAAM,MAAM,EAAU,EAAO,SAAS;iBAAY,EAAO;MAAW,CAAA,EAClE,CAAA,CACD;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsB;MAAU,CAAA,GAC9C,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;OAAM,MAAM,EAAY,EAAO,WAAW;iBAAY,EAAS,EAAO,MAAM;MAAQ,CAAA,EAClF,CAAA,CACD;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsB;MAAa,CAAA,GACjD,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAO,iBAAiB,IAAI,KAAK,EAAO,cAAc,EAAE,mBAAmB,IAAI;MAC9E,CAAA,CACD;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAsB;MAAgB,CAAA,GACpD,kBAAC,MAAD;OAAI,WAAU;iBAAqB,EAAO,eAAe;MAAQ,CAAA,CAC9D;;IACH;;GAEH,EAAa,EAAO,MAAM,IACzB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAQ,SAAS;KAAW,UAAU;eAAtC,CACG,IACC,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA,IAEhD,kBAAC,GAAD,EAAc,WAAU,eAAgB,CAAA,GACxC,SAEI;QACR,kBAAC,GAAD;KACE,SAAQ;KACR,WAAU;KACV,SAAS;KACT,UAAU;eAJZ,CAME,kBAAC,GAAD,EAAS,WAAU,eAAgB,CAAA,GAAC,QAE9B;MACL;QACH;GAEJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAAyE;GAEnF,CAAA,GACH,EAAO,UAAU,WAAW,IAC3B,kBAAC,KAAD;IAAG,WAAU;cAA8B;GAA6B,CAAA,IAExE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAO,UAAU,KAAK,GAAG,MAAM;KAC9B,IAAM,IAAW,EAAE,WAAW,YACxB,IAAW,EAAE,WAAW;KAC9B,OACE,kBAAC,MAAD;MAA2B,WAAU;gBAArC,CACE,kBAAC,QAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,GAAD,EAAQ,MAAM,EAAE,KAAO,CAAA,GACvB,kBAAC,QAAD;QACE,WAAW,EACT,oHACA,IACI,yBACA,IACE,uBACA,cACR;kBAEC,IACC,kBAAC,GAAD,EAAO,WAAU,uCAAwC,CAAA,IACvD,IACF,kBAAC,GAAD,EAAG,WAAU,qCAAsC,CAAA,IACjD;OACA,CAAA,CACF;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAkD,EAAE;OAAQ,CAAA,GACzE,kBAAC,KAAD;QAAG,WAAU;kBAAb,CACG,EAAS,EAAE,MAAM,GACjB,EAAE,OAAO,MAAM,EAAQ,EAAE,IAAI,MAAM,EACnC;SACA;QACH;QA3BK,GAAG,EAAE,KAAK,GAAG,GA2BlB;IAER,CAAC;GACC,CAAA,CAEH,EAAA,CAAA;EACF;;AAET;AAGA,SAAgB,IAA2B;CACzC,IAAM,EAAE,sBAAmB,EAAqB,GAC1C,CAAC,GAAY,KAAiB,EAAS,EAAK,GAC5C,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,CAAC,GAAc,KAAmB,EAAS,KAAK,GAChD,CAAC,GAAY,KAAiB,EAAS,KAAK,GAC5C,CAAC,GAAY,KAAiB,EAAwB,IAAI,GAC1D,CAAC,IAAY,KAAiB,EAAS,EAAK,GAC5C,CAAC,GAAS,KAAc,kBAAsB,IAAI,IAAI,CAAC,GAEvD,IAAS,QAAc;EAC3B,IAAI,IAAW,GACX,IAAY,GACZ,IAAY;EAChB,KAAK,IAAM,KAAK,GACd,AAAI,EAAE,WAAW,aAAY,KAAY,IAChC,EAAE,WAAW,cAAa,KAAa,IACvC,EAAE,WAAW,gBAAa,KAAa;EAElD,OAAO;GAAE;GAAU;GAAW;EAAU;CAC1C,GAAG,CAAC,CAAc,CAAC,GAEb,KAAa,QAAc;EAC/B,IAAM,IAAQ;GAAC;GAAS;GAAa;GAAY;GAAe;GAAa;EAAU,GACjF,oBAAM,IAAI,IAAoB;EACpC,KAAK,IAAM,KAAK,GAAgB,EAAI,IAAI,EAAE,SAAS,EAAI,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;EAC9E,OAAO,EACJ,QAAQ,MAAM,EAAI,IAAI,CAAC,CAAC,EACxB,KAAK,OAAO;GACX,MAAM,EAAS,CAAC,EAAE,QAAQ,QAAQ,MAAO,EAAG,YAAY,CAAC;GACzD,OAAO,EAAI,IAAI,CAAC,KAAK;GACrB,OAAO,GAAS,EAAY,MAAM;EACpC,EAAE;CACN,GAAG,CAAC,CAAc,CAAC,GAEb,KAAW,QAAc;EAC7B,IAAM,IAAQ;GAAC;GAAY;GAAQ;GAAU;EAAK,GAC5C,oBAAM,IAAI,IAAoB;EACpC,KAAK,IAAM,KAAK,GAAgB,EAAI,IAAI,EAAE,OAAO,EAAI,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC;EAC1E,OAAO,EACJ,QAAQ,MAAM,EAAI,IAAI,CAAC,CAAC,EACxB,KAAK,OAAO;GAAE,MAAM,EAAE,QAAQ,QAAQ,MAAO,EAAG,YAAY,CAAC;GAAG,OAAO,EAAI,IAAI,CAAC,KAAK;EAAE,EAAE;CAC9F,GAAG,CAAC,CAAc,CAAC,GAEb,IAAW,QAEb,EAAe,QAAQ,MAAM;EAC3B,IAAM,IAAI,EAAO,KAAK,EAAE,YAAY,GAC9B,IACJ,MAAM,MACN,EAAE,MAAM,YAAY,EAAE,SAAS,CAAC,KAChC,EAAE,GAAG,YAAY,EAAE,SAAS,CAAC,MAC5B,EAAE,eAAe,IAAI,YAAY,EAAE,SAAS,CAAC,MAC7C,EAAE,cAAc,IAAI,YAAY,EAAE,SAAS,CAAC,GACzC,IAAc,MAAiB,SAAS,EAAE,WAAW,GACrD,IAAY,MAAe,SAAS,EAAE,SAAS;EACrD,OAAO,KAAe,KAAe;CACvC,CAAC,GACH;EAAC;EAAgB;EAAQ;EAAc;CAAU,CACnD,GAEM,IAAQ,GAAc,GAAU;EACpC,UAAU;EACV,UAAU,GAAG,EAAO,GAAG,EAAa,GAAG;CACzC,CAAC,GAEK,IAAW,IAAc,EAAe,MAAM,MAAM,EAAE,OAAO,CAAU,KAAK,OAAQ,MAEpF,CAAC,GAAe,EAAE,SAAS,QAAe,EAAY,IAAyB;EACnF,gBAAgB,CAAC,uBAAuB;EACxC,mBAAmB,EAAO,QAAQ,mBAAmB,uCAAuC;EAC5F,UAAU,MAAU,EAAO,MAAM,4BAA4B,EAAM,OAAO;CAC5E,CAAC,GACK,CAAC,GAAc,EAAE,SAAS,QAAe,EAAY,IAAwB;EACjF,gBAAgB,CAAC,uBAAuB;EACxC,mBAAmB,EAAO,QAAQ,mBAAmB,uCAAuC;EAC5F,UAAU,MAAU,EAAO,MAAM,2BAA2B,EAAM,OAAO;CAC3E,CAAC,GACK,IAAO,MAAa,IAEpB,KAAc,MAAe;EAEjC,AADA,EAAc,CAAE,GACZ,OAAO,SAAW,OAAe,OAAO,WAAW,qBAAqB,EAAE,WAC5E,EAAc,EAAI;CAEtB,GAEM,IAAU,EAAM,UAAU,KAAK,MAAM,EAAE,EAAE,GACzC,IAAiB,EAAQ,SAAS,KAAK,EAAQ,OAAO,MAAO,EAAQ,IAAI,CAAE,CAAC,GAC5E,WACJ,GAAY,MAAS;EACnB,IAAM,IAAO,IAAI,IAAI,CAAI;EAGzB,OAFI,IAAgB,EAAQ,SAAS,MAAO,EAAK,OAAO,CAAE,CAAC,IACtD,EAAQ,SAAS,MAAO,EAAK,IAAI,CAAE,CAAC,GAClC;CACT,CAAC,GACG,MAAa,MACjB,GAAY,MAAS;EACnB,IAAM,IAAO,IAAI,IAAI,CAAI;EAGzB,OAFI,EAAK,IAAI,CAAE,IAAG,EAAK,OAAO,CAAE,IAC3B,EAAK,IAAI,CAAE,GACT;CACT,CAAC,GAEG,KAAc,MAA0B;EAC5C,EACE,mBACA;GAAC;GAAM;GAAS;GAAQ;GAAQ;GAAU;GAAgB;EAAW,GACrE,EAAK,KAAK,MAAM;GACd,EAAE;GACF,EAAE;GACF,EAAE;GACF,EAAE;GACF,EAAE;GACF,EAAE;GACF,EAAE,iBAAiB,IAAI,KAAK,EAAE,cAAc,EAAE,mBAAmB,IAAI;EACvE,CAAC,CACH;CACF,GAEM,KAAe,EAAS,QAAQ,MAAM,EAAQ,IAAI,EAAE,EAAE,CAAC;CAE7D,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,KAAD;IAAG,WAAU;cAAoE;GAE9E,CAAA;GACH,kBAAC,IAAD;IACE,MAAA;IACA,QAAQ;IACR,OAAM;IACN,aAAY;IACZ,SACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,SAAQ;MACR,MAAK;MACL,WAAU;MACV,eAAe,EAAW,CAAQ;MAClC,UAAU,EAAS,WAAW;gBALhC,CAOE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAAC,QAE/B;SACR,kBAAC,GAAD;MAAQ,MAAK;MAAK,WAAU;MAAsB,eAAe,EAAc,EAAI;gBAAnF,CACE,kBAAC,IAAD,EAAM,WAAU,eAAgB,CAAA,GAAC,oBAE3B;OACL;;GAER,CAAA;GAED,kBAAC,IAAD;IAAwB,MAAM;IAAY,cAAc;GAAgB,CAAA;GAGxE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,MAAA;MAAK,OAAM;MAAQ,OAAO,EAAe;KAAS,CAAA;KAC5D,kBAAC,GAAD;MAAU,OAAM;MAAY,OAAO,EAAO;KAAY,CAAA;KACtD,kBAAC,GAAD;MAAU,OAAM;MAAW,OAAO,EAAO;KAAW,CAAA;KACpD,kBAAC,GAAD;MAAU,OAAM;MAAY,OAAO,EAAO;KAAY,CAAA;IACnD;;GAGJ,EAAe,SAAS,IACvB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,OAAM;KAAsB,UAAS;KAAmB,MAAM;eACvE,kBAAC,IAAD;MACE,MAAM;MACN,QAAQ;MACR,aAAY;MACZ,aAAa,EAAe;MAC5B,WAAU;KACX,CAAA;IACQ,CAAA,GACX,kBAAC,GAAD;KAAW,OAAM;KAAW,UAAS;KAAoB,MAAM;eAC7D,kBAAC,GAAD;MACE,MAAM;MACN,MAAK;MACL,aAAY;MACZ,QAAQ;MACR,QAAQ,CAAC;OAAE,KAAK;OAAS,OAAO;OAAW,OAAO,EAAY;MAAM,CAAC;MACrE,WAAU;KACX,CAAA;IACQ,CAAA,CACR;QACH;GAEJ,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,IAAD,EAAQ,WAAU,uEAAwE,CAAA,GAC1F,kBAAC,IAAD;UACE,aAAY;UACZ,OAAO;UACP,WAAW,MAAM,EAAU,EAAE,OAAO,KAAK;UACzC,WAAU;SACX,CAAA,CACE;;QACL,kBAAC,GAAD;SAAQ,OAAO;SAAc,eAAe;mBAA5C,CACE,kBAAC,GAAD;UAAe,WAAU;oBACvB,kBAAC,GAAD,EAAa,aAAY,SAAU,CAAA;SACtB,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA;UACE,kBAAC,GAAD;WAAY,OAAM;qBAAM;UAAwB,CAAA;UAChD,kBAAC,GAAD;WAAY,OAAM;qBAAQ;UAAiB,CAAA;UAC3C,kBAAC,GAAD;WAAY,OAAM;qBAAY;UAAqB,CAAA;UACnD,kBAAC,GAAD;WAAY,OAAM;qBAAW;UAAoB,CAAA;UACjD,kBAAC,GAAD;WAAY,OAAM;qBAAc;UAAuB,CAAA;UACvD,kBAAC,GAAD;WAAY,OAAM;qBAAY;UAAqB,CAAA;UACnD,kBAAC,GAAD;WAAY,OAAM;qBAAW;UAAoB,CAAA;SACpC,EAAA,CAAA,CACT;;QACR,kBAAC,GAAD;SAAQ,OAAO;SAAY,eAAe;mBAA1C,CACE,kBAAC,GAAD;UAAe,WAAU;oBACvB,kBAAC,GAAD,EAAa,aAAY,OAAQ,CAAA;SACpB,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA;UACE,kBAAC,GAAD;WAAY,OAAM;qBAAM;UAAoB,CAAA;UAC5C,kBAAC,GAAD;WAAY,OAAM;qBAAW;UAAoB,CAAA;UACjD,kBAAC,GAAD;WAAY,OAAM;qBAAO;UAAgB,CAAA;UACzC,kBAAC,GAAD;WAAY,OAAM;qBAAS;UAAkB,CAAA;UAC7C,kBAAC,GAAD;WAAY,OAAM;qBAAM;UAAe,CAAA;SAC1B,EAAA,CAAA,CACT;;OACL;;MAEJ,EAAQ,OAAO,IACd,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAAuC,EAAQ,MAAK,WAAe;WACnE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAQ,MAAK;SAAK,SAAQ;SAAU,eAAe,EAAW,EAAY;mBAA1E,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAAC,iBAE/B;YACR,kBAAC,GAAD;SAAQ,MAAK;SAAK,SAAQ;SAAQ,eAAe,kBAAW,IAAI,IAAI,CAAC;mBAAG;QAEhE,CAAA,CACL;SACF;WACH;MAEH,EAAS,WAAW,IACnB,kBAAC,IAAD;OACE,cAAc,EAAe,WAAW,IAAI,kBAAkB;OAC9D,OAAO,EAAe,WAAW,IAAI,uBAAuB;OAC5D,aACE,EAAe,WAAW,IACtB,2EACA;MAEP,CAAA,IAED,kBAAC,GAAD;OAAW,OAAM;OAAkB,UAAU,GAAG,EAAS,OAAO;iBAAhE;QAEE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,SAAD;UAAO,WAAU;oBAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;WAAI,WAAU;qBAAd;YACE,kBAAC,MAAD;aAAI,WAAU;uBACZ,kBAAC,GAAD;cACE,SAAS;cACT,iBAAiB;cACjB,cAAW;aACZ,CAAA;YACC,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAM,CAAA;YACtC,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAS,CAAA;YACzC,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAQ,CAAA;YACxC,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAQ,CAAA;YACxC,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAU,CAAA;YAC1C,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAa,CAAA;YAC7C,kBAAC,MAAD;aAAI,WAAU;uBAAkB;YAAa,CAAA;WAC3C;aACC,CAAA,GACP,kBAAC,SAAD,EAAA,UACG,EAAM,UAAU,KAAK,MACpB,kBAAC,MAAD;WAEE,WAAW,EACT,uEACA,MAAe,EAAI,MAAM,iBAC3B;WACA,eAAe,EAAW,EAAI,EAAE;qBANlC;YAQE,kBAAC,MAAD;aAAI,WAAU;aAAM,UAAU,MAAM,EAAE,gBAAgB;uBACpD,kBAAC,GAAD;cACE,SAAS,EAAQ,IAAI,EAAI,EAAE;cAC3B,uBAAuB,GAAU,EAAI,EAAE;cACvC,cAAY,UAAU,EAAI;aAC3B,CAAA;YACC,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBAAyB,EAAI;YAAO,CAAA;YAClD,kBAAC,MAAD;aAAI,WAAU;uBACZ,kBAAC,KAAD;cAAG,WAAU;cAAgC,OAAO,EAAI;wBACrD,EAAI;aACJ,CAAA;YACD,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBACZ,kBAAC,GAAD;cAAM,MAAM,EAAU,EAAI,SAAS;wBAAY,EAAI;aAAW,CAAA;YAC5D,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBACZ,kBAAC,GAAD;cAAM,MAAM,EAAU,EAAI,SAAS;wBAAY,EAAI;aAAW,CAAA;YAC5D,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBACZ,kBAAC,GAAD;cAAM,MAAM,EAAY,EAAI,WAAW;wBACpC,EAAS,EAAI,MAAM;aAChB,CAAA;YACJ,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBACX,EAAI,iBACD,IAAI,KAAK,EAAI,cAAc,EAAE,mBAAmB,IAChD;YACF,CAAA;YACJ,kBAAC,MAAD;aAAI,WAAU;uBACX,EAAI,UAAU,WAAW,IACxB,kBAAC,QAAD;cAAM,WAAU;wBAA8B;aAAa,CAAA,IAE3D,kBAAC,OAAD;cAAK,WAAU;wBAAf,CACG,EAAI,UAAU,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,MACjC,kBAAC,GAAD,EAA+B,MAAM,EAAE,KAAO,GAAjC,GAAG,EAAE,KAAK,GAAG,GAAoB,CAC/C,GACA,EAAI,UAAU,SAAS,IACtB,kBAAC,QAAD;eAAM,WAAU;yBAAhB,CAAiK,KAC7J,EAAI,UAAU,SAAS,CACrB;mBACJ,IACD;;YAEL,CAAA;WACF;aApDG,EAAI,EAoDP,CACL,EACI,CAAA,CACF;;QACJ,CAAA;QAGL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM,UAAU,KAAK,MACpB,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;UACE,MAAK;UACL,WAAU;UACV,eAAe,EAAW,EAAI,EAAE;oBAHlC,CAKE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,KAAD;aAAG,WAAU;uBAA0C,EAAI;YAAS,CAAA,GACpE,kBAAC,KAAD;aAAG,WAAU;uBAAyC,EAAI;YAAM,CAAA,CAC7D;eACL,kBAAC,GAAD;YAAM,MAAM,EAAY,EAAI,WAAW;sBACpC,EAAS,EAAI,MAAM;WAChB,CAAA,CACH;cACL,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAM,MAAM,EAAU,EAAI,SAAS;sBAAY,EAAI;WAAW,CAAA,GAC9D,kBAAC,GAAD;YAAM,MAAM,EAAU,EAAI,SAAS;sBAAY,EAAI;WAAW,CAAA,CAC3D;YACC;YACN,GApBK,EAAI,EAoBT,CACL;QACC,CAAA;QAEJ,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,IAAD;UACE,MAAM,EAAM;UACZ,WAAW,EAAM;UACjB,YAAY,EAAM;UAClB,UAAU,EAAM;UAChB,YAAY,EAAM;UAClB,SAAS,EAAM;UACf,SAAS,EAAM;UACf,QAAQ,EAAM;UACd,QAAQ,EAAM;UACd,WAAU;SACX,CAAA;QACE,CAAA;OACI;;KAEV;QAGL,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAW,OAAM;iBACd,IACC,kBAAC,GAAD;QACE,QAAQ;QACF;QACN,iBAAiB,KAAK,EAAc,EAAE,WAAW,EAAE,IAAI,EAAS,GAAG,EAAE,CAAC;QACtE,gBACE,KAAK,EAAa,EAAE,WAAW;SAAE,IAAI,EAAS;SAAI,QAAQ;QAAK,EAAE,CAAC;OAErE,CAAA,IAED,kBAAC,KAAD;QAAG,WAAU;kBAA+C;OAEzD,CAAA;MAEI,CAAA;KACR,CAAA;IACF,CAAA,CACF;;GAEL,kBAAC,IAAD,EAAA,UAAa,0KAGA,CAAA;GAGb,kBAAC,GAAD;IACE,MAAM;IACN,eAAe,MAAS;KAEtB,AADA,EAAc,CAAI,GACb,KAAM,EAAc,IAAI;IAC/B;cAEA,kBAAC,IAAD;KAAyB,WAAU;eAChC,IACC,kBAAC,GAAD;MACE,QAAQ;MACF;MACN,iBAAiB,KAAK,EAAc,EAAE,WAAW,EAAE,IAAI,EAAS,GAAG,EAAE,CAAC;MACtE,gBAAgB,KAAK,EAAa,EAAE,WAAW;OAAE,IAAI,EAAS;OAAI,QAAQ;MAAK,EAAE,CAAC;KACnF,CAAA,IACC;IACmB,CAAA;GACT,CAAA;EACf;;AAET"}
|