@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":"AssetsAssetListPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetListPage.tsx"],"sourcesContent":["import { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n formatAssetCategory,\n useAssetCategoryPresentation,\n useHiddenCategoryIds,\n} from '../providers/AssetHandlerProvider';\nimport { useState, useMemo, useSyncExternalStore } from 'react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Plus,\n Grid3x3,\n List,\n Table as TableIcon,\n ArrowUp,\n ArrowDown,\n ChevronsUpDown,\n MoreHorizontal,\n Copy,\n Eye,\n Monitor,\n Server,\n Wifi,\n Truck,\n Wrench,\n Code,\n Box,\n Boxes,\n CheckCircle2,\n Printer,\n} from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport { useCopy } from '../hooks/useCopy';\nimport { printAssetTag } from '../utils/printAssetTag';\nimport {\n Pagination,\n usePagination,\n ChartCard,\n StatTile,\n DonutChart,\n BarsChart,\n formatCompact,\n} from '../components';\n\n// Soft, semantic status pill — matches the mock's soft pills (green/amber/gray/red).\nconst STATUS_PILL: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n maintenance: 'bg-status-warning-bg-subtle text-status-warning-text',\n inactive: 'bg-bg-sunken text-text-secondary',\n retired: 'bg-bg-sunken text-text-secondary',\n disposed: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\nconst conditionColors: Record<string, string> = {\n excellent: 'text-status-success-text bg-status-success-bg-subtle',\n good: 'text-status-info-text bg-status-info-bg-subtle',\n fair: 'text-status-warning-text bg-status-warning-bg-subtle',\n poor: 'text-status-warning-text bg-status-warning-bg-subtle',\n damaged: 'text-status-error-text bg-status-error-bg-subtle',\n};\n\n// Status distribution slice colours — semantic tokens (theme-aware CSS vars).\nconst STATUS_SLICE_COLOR: Record<string, string> = {\n active: 'var(--color-status-success-bg)',\n maintenance: 'var(--color-status-warning-bg)',\n inactive: 'var(--color-status-info-bg)',\n retired: 'var(--color-text-muted)',\n disposed: 'var(--color-status-error-bg)',\n};\n\nconst categoryIcons: Record<string, typeof Box> = {\n electronics: Monitor,\n it_hardware: Monitor,\n furniture: Box,\n vehicles: Truck,\n equipment: Wrench,\n software: Code,\n networking: Wifi,\n servers: Server,\n};\nconst categoryTints: Record<string, string> = {\n electronics: 'bg-status-info-bg-subtle text-status-info-text',\n it_hardware: 'bg-status-info-bg-subtle text-status-info-text',\n furniture: 'bg-status-warning-bg-subtle text-status-warning-text',\n vehicles: 'bg-status-success-bg-subtle text-status-success-text',\n equipment: 'bg-status-warning-bg-subtle text-status-warning-text',\n software: 'bg-action-primary-bg/10 text-action-primary-bg',\n networking: 'bg-status-info-bg-subtle text-status-info-text',\n servers: 'bg-status-error-bg-subtle text-status-error-text',\n};\nfunction CategoryIconTile({ category }: { category: string }) {\n const Icon = categoryIcons[category] ?? Box;\n const tint = categoryTints[category] ?? 'bg-bg-sunken text-text-secondary';\n return (\n <span className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md ${tint}`}>\n <Icon className=\"h-4 w-4\" />\n </span>\n );\n}\n\nfunction StatusPill({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex rounded-full px-2.5 py-0.5 text-xs font-medium capitalize ${\n STATUS_PILL[status] || 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {status.replace(/_/g, ' ')}\n </span>\n );\n}\n\ntype SortKey = 'assetTag' | 'name' | 'category' | 'status' | 'condition' | 'assignedTo';\n\n// SSR-safe narrow-viewport hook (auto-fall-back the table to cards on phones).\nfunction useIsNarrow(): boolean {\n return useSyncExternalStore(\n (cb) => {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mq = window.matchMedia('(max-width: 767px)');\n mq.addEventListener('change', cb);\n return () => mq.removeEventListener('change', cb);\n },\n () =>\n typeof window !== 'undefined' && window.matchMedia\n ? window.matchMedia('(max-width: 767px)').matches\n : false,\n () => false\n );\n}\n\nexport function AssetsAssetListPage() {\n const tc = useCopy();\n const navigate = useAssetHandlerNavigate();\n const hiddenCategories = useHiddenCategoryIds();\n const { labels: categoryLabels, options: configuredCategoryOptions } =\n useAssetCategoryPresentation();\n const { assets, hydrated } = useAssetHandlerStore();\n const isNarrow = useIsNarrow();\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState('all');\n const [statusFilter, setStatusFilter] = useState('all');\n const [viewMode, setViewMode] = useState<'table' | 'grid' | 'list'>('table');\n const [userPickedView, setUserPickedView] = useState(false);\n const [sortKey, setSortKey] = useState<SortKey>('name');\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');\n\n // On phones, default to the card list (unless the user explicitly chose a view).\n const effectiveView = !userPickedView && isNarrow && viewMode === 'table' ? 'list' : viewMode;\n const pickView = (mode: 'table' | 'grid' | 'list') => {\n setUserPickedView(true);\n setViewMode(mode);\n };\n\n const categories = useMemo(\n () =>\n [\n ...new Set([\n ...(configuredCategoryOptions?.map((option) => option.id) ?? []),\n ...assets.map((a) => a.category).filter(Boolean),\n ]),\n ]\n .filter((c) => !hiddenCategories.has(c))\n .sort(),\n [assets, configuredCategoryOptions, hiddenCategories]\n );\n\n const filteredAssets = useMemo(() => {\n return assets.filter((a) => {\n if (hiddenCategories.has(a.category)) return false;\n const matchesSearch =\n searchQuery === '' ||\n a.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.assetTag.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.serialNumber.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesCategory = categoryFilter === 'all' || a.category === categoryFilter;\n const matchesStatus = statusFilter === 'all' || a.status === statusFilter;\n return matchesSearch && matchesCategory && matchesStatus;\n });\n }, [assets, searchQuery, categoryFilter, statusFilter, hiddenCategories]);\n\n const sortedAssets = useMemo(() => {\n const dir = sortDir === 'asc' ? 1 : -1;\n return [...filteredAssets].sort((a, b) => {\n const av = (a[sortKey] ?? '').toString().toLowerCase();\n const bv = (b[sortKey] ?? '').toString().toLowerCase();\n return av.localeCompare(bv) * dir;\n });\n }, [filteredAssets, sortKey, sortDir]);\n\n const activeCount = assets.filter((a) => a.status === 'active').length;\n\n const statusSlices = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of assets) counts[a.status] = (counts[a.status] || 0) + 1;\n return Object.entries(counts).map(([status, value]) => ({\n name: status.charAt(0).toUpperCase() + status.slice(1),\n value,\n color: STATUS_SLICE_COLOR[status],\n }));\n }, [assets]);\n\n const categoryBars = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of assets) counts[a.category] = (counts[a.category] || 0) + 1;\n return Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([category, count]) => ({\n category: formatAssetCategory(category, categoryLabels),\n count,\n }));\n }, [assets, categoryLabels]);\n\n const pager = usePagination(sortedAssets, {\n pageSize: 12,\n resetKey: `${searchQuery}|${categoryFilter}|${statusFilter}|${sortKey}|${sortDir}`,\n });\n\n const toggleSort = (key: SortKey) => {\n if (sortKey === key) {\n setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));\n } else {\n setSortKey(key);\n setSortDir('asc');\n }\n };\n\n const renderSortHeader = (label: string, col: SortKey) => (\n <th className=\"p-3 text-left font-medium\">\n <button\n type=\"button\"\n onClick={() => toggleSort(col)}\n className=\"inline-flex items-center gap-1 hover:text-text-primary\"\n >\n {label}\n {sortKey === col ? (\n sortDir === 'asc' ? (\n <ArrowUp className=\"h-3 w-3 text-action-primary-bg\" />\n ) : (\n <ArrowDown className=\"h-3 w-3 text-action-primary-bg\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3 w-3 text-text-muted\" />\n )}\n </button>\n </th>\n );\n\n const copyTag = (tag: string) => {\n void navigator.clipboard?.writeText(tag);\n notify.success('Asset tag copied', `${tag} copied to clipboard.`);\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>\n {tc('assethandler.assets.list.title', '{{asset}} Inventory')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {assets.length}{' '}\n {tc('assethandler.assets.list.subtitle.totalAssets', 'total {{assetsLower}}')} ·{' '}\n {activeCount} {tc('assethandler.assets.list.subtitle.active', 'active')}\n </p>\n </div>\n <Button\n className=\"w-full sm:w-auto\"\n size=\"sm\"\n onClick={() => navigate('/assets/asset-create')}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {tc('assethandler.assets.list.actions.addAsset', 'Add {{asset}}')}\n </Button>\n </div>\n\n <PagePurpose>\n {tc(\n 'assethandler.assets.list.purpose',\n 'The single source of truth for every {{assetLower}} you own or manage. Search, filter and group by category, status or condition to find any item fast, review its assignment, then drill in to update, check it in/out or schedule maintenance.'\n )}\n </PagePurpose>\n\n {/* Insight strip */}\n {assets.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Total assets\"\n value={assets.length}\n format={formatCompact}\n icon={Boxes}\n hero\n />\n <StatTile\n label=\"Active\"\n value={activeCount}\n format={formatCompact}\n icon={CheckCircle2}\n />\n <StatTile\n label=\"Categories\"\n value={categories.length}\n format={formatCompact}\n icon={Box}\n />\n <StatTile\n label=\"Showing\"\n value={filteredAssets.length}\n format={formatCompact}\n icon={Search}\n />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Status mix\" subtitle=\"Assets by lifecycle status\">\n <DonutChart\n data={statusSlices}\n centerLabel=\"Total\"\n centerValue={assets.length}\n height={220}\n />\n </ChartCard>\n <ChartCard title=\"By category\" subtitle=\"Top categories by asset count\">\n <BarsChart\n data={categoryBars}\n xKey=\"category\"\n orientation=\"horizontal\"\n height={220}\n categoryWidth={110}\n valueFormat={formatCompact}\n series={[\n {\n key: 'count',\n label: tc('assethandler.assets.list.chart.series', '{{assets}}'),\n },\n ]}\n />\n </ChartCard>\n </div>\n </>\n ) : null}\n\n {/* Filters Bar */}\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex flex-col gap-3 md:flex-row md:flex-wrap\">\n <div className=\"relative min-w-0 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={tc(\n 'assethandler.assets.list.search.placeholder',\n 'Search by name, {{assetLower}} tag, serial number...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={categoryFilter} onValueChange={setCategoryFilter}>\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue\n placeholder={tc(\n 'assethandler.assets.list.filters.category.placeholder',\n 'Category'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tc('assethandler.assets.list.filters.category.all', 'All Categories')}\n </SelectItem>\n {categories.map((category) => (\n <SelectItem key={category} value={category} className=\"capitalize\">\n {formatAssetCategory(category, categoryLabels)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[160px]\">\n <SelectValue\n placeholder={tc('assethandler.assets.list.filters.status.placeholder', 'Status')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tc('assethandler.assets.list.filters.status.all', 'All Statuses')}\n </SelectItem>\n <SelectItem value=\"active\">\n {tc('assethandler.assets.list.filters.status.active', 'Active')}\n </SelectItem>\n <SelectItem value=\"inactive\">\n {tc('assethandler.assets.list.filters.status.inactive', 'Inactive')}\n </SelectItem>\n <SelectItem value=\"maintenance\">\n {tc('assethandler.assets.list.filters.status.maintenance', 'Maintenance')}\n </SelectItem>\n <SelectItem value=\"retired\">\n {tc('assethandler.assets.list.filters.status.retired', 'Retired')}\n </SelectItem>\n <SelectItem value=\"disposed\">\n {tc('assethandler.assets.list.filters.status.disposed', 'Disposed')}\n </SelectItem>\n </SelectContent>\n </Select>\n <div className=\"flex gap-1 rounded-md border p-0.5\">\n <Button\n variant={effectiveView === 'table' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'table'}\n onClick={() => pickView('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Table</span>\n </Button>\n <Button\n variant={effectiveView === 'grid' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'grid'}\n onClick={() => pickView('grid')}\n >\n <Grid3x3 className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Grid</span>\n </Button>\n <Button\n variant={effectiveView === 'list' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'list'}\n onClick={() => pickView('list')}\n >\n <List className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">List</span>\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {!hydrated && assets.length === 0 ? (\n <div className=\"space-y-2\">\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 ) : null}\n\n {effectiveView === 'table' && filteredAssets.length > 0 && (\n <Card>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50 text-text-secondary\">\n {renderSortHeader(\n tc('assethandler.assets.list.table.assetTag', '{{asset}} Tag'),\n 'assetTag'\n )}\n {renderSortHeader(tc('assethandler.assets.list.table.name', 'Name'), 'name')}\n {renderSortHeader(\n tc('assethandler.assets.list.table.category', 'Category'),\n 'category'\n )}\n {renderSortHeader(\n tc('assethandler.assets.list.table.status', 'Status'),\n 'status'\n )}\n {renderSortHeader(\n tc('assethandler.assets.list.table.condition', 'Condition'),\n 'condition'\n )}\n <th className=\"p-3 text-left font-medium\">\n {tc('assethandler.assets.list.table.location', 'Location')}\n </th>\n {renderSortHeader(\n tc('assethandler.assets.list.table.assignedTo', 'Assigned To'),\n 'assignedTo'\n )}\n <th className=\"w-10 p-3\" />\n </tr>\n </thead>\n <tbody>\n {pager.pageItems.map((asset) => (\n <tr\n key={asset.id}\n className=\"cursor-pointer border-b hover:bg-bg-sunken/50\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <td className=\"p-3\">\n <span className=\"flex items-center gap-3\">\n <CategoryIconTile category={asset.category} />\n <span className=\"font-mono text-xs\">{asset.assetTag}</span>\n </span>\n </td>\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">{asset.serialNumber}</p>\n </td>\n <td className=\"p-3\">{formatAssetCategory(asset.category, categoryLabels)}</td>\n <td className=\"p-3\">\n <StatusPill status={asset.status} />\n </td>\n <td className=\"p-3\">\n <span\n className={`inline-flex rounded-md px-2 py-0.5 text-xs font-medium capitalize ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </td>\n <td className=\"max-w-[200px] truncate p-3 text-xs\">\n {asset.location || '—'}\n </td>\n <td className=\"p-3 text-xs\">{asset.assignedTo || '—'}</td>\n <td className=\"p-3\" onClick={(e) => e.stopPropagation()}>\n <RowActions\n onView={() => navigate(`/assets/${asset.id}`)}\n onCopy={() => copyTag(asset.assetTag)}\n onPrint={() =>\n void printAssetTag({\n name: asset.name,\n tagId: asset.tagId,\n assetTag: asset.assetTag,\n category: asset.category,\n })\n }\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n\n {effectiveView === 'grid' && filteredAssets.length > 0 && (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {pager.pageItems.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <CategoryIconTile category={asset.category} />\n <span className=\"font-mono text-xs text-text-secondary\">{asset.assetTag}</span>\n </span>\n <StatusPill status={asset.status} />\n </div>\n <CardTitle className=\"mt-2 text-base\">{asset.name}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.category', 'Category')}\n </span>\n <span>{formatAssetCategory(asset.category, categoryLabels)}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.condition', 'Condition')}\n </span>\n <span\n className={`rounded-md px-2 py-0.5 text-xs font-medium capitalize ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.assignedTo', 'Assigned To')}\n </span>\n <span className=\"text-xs\">{asset.assignedTo || '—'}</span>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {effectiveView === 'list' && filteredAssets.length > 0 && (\n <div className=\"space-y-2\">\n {pager.pageItems.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardContent className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <CategoryIconTile category={asset.category} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"truncate text-sm font-medium\">{asset.name}</p>\n <StatusPill status={asset.status} />\n </div>\n <p className=\"truncate text-xs text-text-secondary\">\n {asset.assetTag}\n {asset.serialNumber ? <> · {asset.serialNumber}</> : null}\n {asset.location ? <> · {asset.location}</> : null}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {filteredAssets.length > 0 && (\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=\"assets\"\n />\n )}\n\n {hydrated && filteredAssets.length === 0 && (\n <IllustratedEmptyState\n illustration={\n searchQuery || categoryFilter !== 'all' || statusFilter !== 'all'\n ? 'empty-search'\n : 'empty-data'\n }\n title={tc('assethandler.assets.list.empty.title', 'No {{assetsLower}} found')}\n description={tc(\n 'assethandler.assets.list.empty.description',\n 'Try adjusting your filters or add a new {{assetLower}} to get started.'\n )}\n action={\n <Button size=\"sm\" onClick={() => navigate('/assets/asset-create')}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {tc('assethandler.assets.list.actions.addAsset', 'Add {{asset}}')}\n </Button>\n }\n />\n )}\n </div>\n );\n}\n\nfunction RowActions({\n onView,\n onCopy,\n onPrint,\n}: {\n onView: () => void;\n onCopy: () => void;\n onPrint: () => void;\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" aria-label=\"Asset actions\">\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={onView}>\n <Eye className=\"mr-2 h-4 w-4\" />\n View details\n </DropdownMenuItem>\n <DropdownMenuItem onClick={onCopy}>\n <Copy className=\"mr-2 h-4 w-4\" />\n Copy asset tag\n </DropdownMenuItem>\n <DropdownMenuItem onClick={onPrint}>\n <Printer className=\"mr-2 h-4 w-4\" />\n Print tag\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetsAssetListPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetListPage.tsx"],"sourcesContent":["import { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n formatAssetCategory,\n useAssetCategoryPresentation,\n useHiddenCategoryIds,\n} from '../providers/AssetHandlerProvider';\nimport { useState, useMemo, useSyncExternalStore } from 'react';\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Plus,\n Grid3x3,\n List,\n Table as TableIcon,\n ArrowUp,\n ArrowDown,\n ChevronsUpDown,\n MoreHorizontal,\n Copy,\n Eye,\n Monitor,\n Server,\n Wifi,\n Truck,\n Wrench,\n Code,\n Box,\n Boxes,\n CheckCircle2,\n Printer,\n} from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\nimport { useCopy } from '../hooks/useCopy';\nimport { printAssetTag } from '../utils/printAssetTag';\nimport {\n Pagination,\n usePagination,\n ChartCard,\n StatTile,\n DonutChart,\n BarsChart,\n formatCompact,\n} from '../components';\n\n// Soft, semantic status pill — matches the mock's soft pills (green/amber/gray/red).\nconst STATUS_PILL: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n maintenance: 'bg-status-warning-bg-subtle text-status-warning-text',\n inactive: 'bg-bg-sunken text-text-secondary',\n retired: 'bg-bg-sunken text-text-secondary',\n disposed: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\nconst conditionColors: Record<string, string> = {\n excellent: 'text-status-success-text bg-status-success-bg-subtle',\n good: 'text-status-info-text bg-status-info-bg-subtle',\n fair: 'text-status-warning-text bg-status-warning-bg-subtle',\n poor: 'text-status-warning-text bg-status-warning-bg-subtle',\n damaged: 'text-status-error-text bg-status-error-bg-subtle',\n};\n\n// Status distribution slice colours — semantic tokens (theme-aware CSS vars).\nconst STATUS_SLICE_COLOR: Record<string, string> = {\n active: 'var(--color-status-success-bg)',\n maintenance: 'var(--color-status-warning-bg)',\n inactive: 'var(--color-status-info-bg)',\n retired: 'var(--color-text-muted)',\n disposed: 'var(--color-status-error-bg)',\n};\n\nconst categoryIcons: Record<string, typeof Box> = {\n electronics: Monitor,\n it_hardware: Monitor,\n furniture: Box,\n vehicles: Truck,\n equipment: Wrench,\n software: Code,\n networking: Wifi,\n servers: Server,\n};\nconst categoryTints: Record<string, string> = {\n electronics: 'bg-status-info-bg-subtle text-status-info-text',\n it_hardware: 'bg-status-info-bg-subtle text-status-info-text',\n furniture: 'bg-status-warning-bg-subtle text-status-warning-text',\n vehicles: 'bg-status-success-bg-subtle text-status-success-text',\n equipment: 'bg-status-warning-bg-subtle text-status-warning-text',\n software: 'bg-action-primary-bg/10 text-action-primary-bg',\n networking: 'bg-status-info-bg-subtle text-status-info-text',\n servers: 'bg-status-error-bg-subtle text-status-error-text',\n};\nfunction CategoryIconTile({ category }: { category: string }) {\n const Icon = categoryIcons[category] ?? Box;\n const tint = categoryTints[category] ?? 'bg-bg-sunken text-text-secondary';\n return (\n <span className={`inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md ${tint}`}>\n <Icon className=\"h-4 w-4\" />\n </span>\n );\n}\n\nfunction StatusPill({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex rounded-full px-2.5 py-0.5 text-xs font-medium capitalize ${\n STATUS_PILL[status] || 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {status.replace(/_/g, ' ')}\n </span>\n );\n}\n\ntype SortKey = 'assetTag' | 'name' | 'category' | 'status' | 'condition' | 'assignedTo';\n\n// SSR-safe narrow-viewport hook (auto-fall-back the table to cards on phones).\nfunction useIsNarrow(): boolean {\n return useSyncExternalStore(\n (cb) => {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mq = window.matchMedia('(max-width: 767px)');\n mq.addEventListener('change', cb);\n return () => mq.removeEventListener('change', cb);\n },\n () =>\n typeof window !== 'undefined' && window.matchMedia\n ? window.matchMedia('(max-width: 767px)').matches\n : false,\n () => false\n );\n}\n\nexport function AssetsAssetListPage() {\n const tc = useCopy();\n const navigate = useAssetHandlerNavigate();\n const hiddenCategories = useHiddenCategoryIds();\n const { labels: categoryLabels, options: configuredCategoryOptions } =\n useAssetCategoryPresentation();\n const { assets, hydrated } = useAssetHandlerStore();\n const isNarrow = useIsNarrow();\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState('all');\n const [statusFilter, setStatusFilter] = useState('all');\n const [viewMode, setViewMode] = useState<'table' | 'grid' | 'list'>('table');\n const [userPickedView, setUserPickedView] = useState(false);\n const [sortKey, setSortKey] = useState<SortKey>('name');\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');\n\n // On phones, default to the card list (unless the user explicitly chose a view).\n const effectiveView = !userPickedView && isNarrow && viewMode === 'table' ? 'list' : viewMode;\n const pickView = (mode: 'table' | 'grid' | 'list') => {\n setUserPickedView(true);\n setViewMode(mode);\n };\n\n const categories = useMemo(\n () =>\n [\n ...new Set([\n ...(configuredCategoryOptions?.map((option) => option.id) ?? []),\n ...assets.map((a) => a.category).filter(Boolean),\n ]),\n ]\n .filter((c) => !hiddenCategories.has(c))\n .sort(),\n [assets, configuredCategoryOptions, hiddenCategories]\n );\n\n const filteredAssets = useMemo(() => {\n return assets.filter((a) => {\n if (hiddenCategories.has(a.category)) return false;\n const matchesSearch =\n searchQuery === '' ||\n a.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.assetTag.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.serialNumber.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesCategory = categoryFilter === 'all' || a.category === categoryFilter;\n const matchesStatus = statusFilter === 'all' || a.status === statusFilter;\n return matchesSearch && matchesCategory && matchesStatus;\n });\n }, [assets, searchQuery, categoryFilter, statusFilter, hiddenCategories]);\n\n const sortedAssets = useMemo(() => {\n const dir = sortDir === 'asc' ? 1 : -1;\n return [...filteredAssets].sort((a, b) => {\n const av = (a[sortKey] ?? '').toString().toLowerCase();\n const bv = (b[sortKey] ?? '').toString().toLowerCase();\n return av.localeCompare(bv) * dir;\n });\n }, [filteredAssets, sortKey, sortDir]);\n\n const activeCount = assets.filter((a) => a.status === 'active').length;\n\n const statusSlices = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of assets) counts[a.status] = (counts[a.status] || 0) + 1;\n return Object.entries(counts).map(([status, value]) => ({\n name: status.charAt(0).toUpperCase() + status.slice(1),\n value,\n color: STATUS_SLICE_COLOR[status],\n }));\n }, [assets]);\n\n const categoryBars = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of assets) counts[a.category] = (counts[a.category] || 0) + 1;\n return Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([category, count]) => ({\n category: formatAssetCategory(category, categoryLabels),\n count,\n }));\n }, [assets, categoryLabels]);\n\n const pager = usePagination(sortedAssets, {\n pageSize: 12,\n resetKey: `${searchQuery}|${categoryFilter}|${statusFilter}|${sortKey}|${sortDir}`,\n });\n\n const toggleSort = (key: SortKey) => {\n if (sortKey === key) {\n setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'));\n } else {\n setSortKey(key);\n setSortDir('asc');\n }\n };\n\n const renderSortHeader = (label: string, col: SortKey) => (\n <th className=\"p-3 text-left font-medium\">\n <button\n type=\"button\"\n onClick={() => toggleSort(col)}\n className=\"inline-flex items-center gap-1 hover:text-text-primary\"\n >\n {label}\n {sortKey === col ? (\n sortDir === 'asc' ? (\n <ArrowUp className=\"h-3 w-3 text-action-primary-bg\" />\n ) : (\n <ArrowDown className=\"h-3 w-3 text-action-primary-bg\" />\n )\n ) : (\n <ChevronsUpDown className=\"h-3 w-3 text-text-muted\" />\n )}\n </button>\n </th>\n );\n\n const copyTag = (tag: string) => {\n void navigator.clipboard?.writeText(tag);\n notify.success('Asset tag copied', `${tag} copied to clipboard.`);\n };\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>\n {tc('assethandler.assets.list.title', '{{asset}} Inventory')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {assets.length}{' '}\n {tc('assethandler.assets.list.subtitle.totalAssets', 'total {{assetsLower}}')} ·{' '}\n {activeCount} {tc('assethandler.assets.list.subtitle.active', 'active')}\n </p>\n </div>\n <Button\n className=\"w-full sm:w-auto\"\n size=\"sm\"\n onClick={() => navigate('/assets/asset-create')}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {tc('assethandler.assets.list.actions.addAsset', 'Add {{asset}}')}\n </Button>\n </div>\n\n <PagePurpose>\n {tc(\n 'assethandler.assets.list.purpose',\n 'The single source of truth for every {{assetLower}} you own or manage. Search, filter and group by category, status or condition to find any item fast, review its assignment, then drill in to update, check it in/out or schedule maintenance.'\n )}\n </PagePurpose>\n\n {/* Insight strip */}\n {assets.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Total assets\"\n value={assets.length}\n format={formatCompact}\n icon={Boxes}\n hero\n />\n <StatTile\n label=\"Active\"\n value={activeCount}\n format={formatCompact}\n icon={CheckCircle2}\n />\n <StatTile\n label=\"Categories\"\n value={categories.length}\n format={formatCompact}\n icon={Box}\n />\n <StatTile\n label=\"Showing\"\n value={filteredAssets.length}\n format={formatCompact}\n icon={Search}\n />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Status mix\" subtitle=\"Assets by lifecycle status\">\n <DonutChart\n data={statusSlices}\n centerLabel=\"Total\"\n centerValue={assets.length}\n height={220}\n />\n </ChartCard>\n <ChartCard title=\"By category\" subtitle=\"Top categories by asset count\">\n <BarsChart\n data={categoryBars}\n xKey=\"category\"\n orientation=\"horizontal\"\n height={220}\n categoryWidth={110}\n valueFormat={formatCompact}\n series={[\n {\n key: 'count',\n label: tc('assethandler.assets.list.chart.series', '{{assets}}'),\n },\n ]}\n />\n </ChartCard>\n </div>\n </>\n ) : null}\n\n {/* Filters Bar */}\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex flex-col gap-3 md:flex-row md:flex-wrap\">\n <div className=\"relative min-w-0 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={tc(\n 'assethandler.assets.list.search.placeholder',\n 'Search by name, {{assetLower}} tag, serial number...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={categoryFilter} onValueChange={setCategoryFilter}>\n <SelectTrigger className=\"w-full sm:w-[180px]\">\n <SelectValue\n placeholder={tc(\n 'assethandler.assets.list.filters.category.placeholder',\n 'Category'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tc('assethandler.assets.list.filters.category.all', 'All Categories')}\n </SelectItem>\n {categories.map((category) => (\n <SelectItem key={category} value={category} className=\"capitalize\">\n {formatAssetCategory(category, categoryLabels)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-full sm:w-[160px]\">\n <SelectValue\n placeholder={tc('assethandler.assets.list.filters.status.placeholder', 'Status')}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tc('assethandler.assets.list.filters.status.all', 'All Statuses')}\n </SelectItem>\n <SelectItem value=\"active\">\n {tc('assethandler.assets.list.filters.status.active', 'Active')}\n </SelectItem>\n <SelectItem value=\"inactive\">\n {tc('assethandler.assets.list.filters.status.inactive', 'Inactive')}\n </SelectItem>\n <SelectItem value=\"maintenance\">\n {tc('assethandler.assets.list.filters.status.maintenance', 'Maintenance')}\n </SelectItem>\n <SelectItem value=\"retired\">\n {tc('assethandler.assets.list.filters.status.retired', 'Retired')}\n </SelectItem>\n <SelectItem value=\"disposed\">\n {tc('assethandler.assets.list.filters.status.disposed', 'Disposed')}\n </SelectItem>\n </SelectContent>\n </Select>\n <div className=\"flex gap-1 rounded-md border p-0.5\">\n <Button\n variant={effectiveView === 'table' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'table'}\n onClick={() => pickView('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Table</span>\n </Button>\n <Button\n variant={effectiveView === 'grid' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'grid'}\n onClick={() => pickView('grid')}\n >\n <Grid3x3 className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">Grid</span>\n </Button>\n <Button\n variant={effectiveView === 'list' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"h-8 gap-1.5 px-2\"\n aria-pressed={effectiveView === 'list'}\n onClick={() => pickView('list')}\n >\n <List className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">List</span>\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {!hydrated && assets.length === 0 ? (\n <div className=\"space-y-2\">\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 ) : null}\n\n {effectiveView === 'table' && filteredAssets.length > 0 && (\n <Card>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50 text-text-secondary\">\n {renderSortHeader(\n tc('assethandler.assets.list.table.assetTag', '{{asset}} Tag'),\n 'assetTag'\n )}\n {renderSortHeader(tc('assethandler.assets.list.table.name', 'Name'), 'name')}\n {renderSortHeader(\n tc('assethandler.assets.list.table.category', 'Category'),\n 'category'\n )}\n {renderSortHeader(\n tc('assethandler.assets.list.table.status', 'Status'),\n 'status'\n )}\n {renderSortHeader(\n tc('assethandler.assets.list.table.condition', 'Condition'),\n 'condition'\n )}\n <th className=\"p-3 text-left font-medium\">\n {tc('assethandler.assets.list.table.location', 'Location')}\n </th>\n {renderSortHeader(\n tc('assethandler.assets.list.table.assignedTo', 'Assigned To'),\n 'assignedTo'\n )}\n <th className=\"w-10 p-3\" />\n </tr>\n </thead>\n <tbody>\n {pager.pageItems.map((asset) => (\n <tr\n key={asset.id}\n className=\"cursor-pointer border-b hover:bg-bg-sunken/50\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <td className=\"p-3\">\n <span className=\"flex items-center gap-3\">\n <CategoryIconTile category={asset.category} />\n <span className=\"font-mono text-xs\">{asset.assetTag}</span>\n </span>\n </td>\n <td className=\"p-3\">\n <p className=\"font-medium text-text-primary\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">{asset.serialNumber}</p>\n </td>\n <td className=\"p-3\">{formatAssetCategory(asset.category, categoryLabels)}</td>\n <td className=\"p-3\">\n <StatusPill status={asset.status} />\n </td>\n <td className=\"p-3\">\n <span\n className={`inline-flex rounded-md px-2 py-0.5 text-xs font-medium capitalize ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </td>\n <td className=\"max-w-[200px] truncate p-3 text-xs\">\n {asset.location || '—'}\n </td>\n <td className=\"p-3 text-xs\">{asset.assignedTo || '—'}</td>\n <td className=\"p-3\" onClick={(e) => e.stopPropagation()}>\n <RowActions\n onView={() => navigate(`/assets/${asset.id}`)}\n onCopy={() => copyTag(asset.assetTag)}\n onPrint={() =>\n void printAssetTag({\n name: asset.name,\n tagId: asset.tagId,\n assetTag: asset.assetTag,\n category: asset.category,\n })\n }\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n\n {effectiveView === 'grid' && filteredAssets.length > 0 && (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {pager.pageItems.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <CategoryIconTile category={asset.category} />\n <span className=\"font-mono text-xs text-text-secondary\">{asset.assetTag}</span>\n </span>\n <StatusPill status={asset.status} />\n </div>\n <CardTitle className=\"mt-2 text-base\">{asset.name}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.category', 'Category')}\n </span>\n <span>{formatAssetCategory(asset.category, categoryLabels)}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.condition', 'Condition')}\n </span>\n <span\n className={`rounded-md px-2 py-0.5 text-xs font-medium capitalize ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tc('assethandler.assets.list.grid.assignedTo', 'Assigned To')}\n </span>\n <span className=\"text-xs\">{asset.assignedTo || '—'}</span>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {effectiveView === 'list' && filteredAssets.length > 0 && (\n <div className=\"space-y-2\">\n {pager.pageItems.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardContent className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <CategoryIconTile category={asset.category} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <p className=\"truncate text-sm font-medium\">{asset.name}</p>\n <StatusPill status={asset.status} />\n </div>\n <p className=\"truncate text-xs text-text-secondary\">\n {asset.assetTag}\n {asset.serialNumber ? <> · {asset.serialNumber}</> : null}\n {asset.location ? <> · {asset.location}</> : null}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {filteredAssets.length > 0 && (\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=\"assets\"\n />\n )}\n\n {hydrated && filteredAssets.length === 0 && (\n <IllustratedEmptyState\n illustration={\n searchQuery || categoryFilter !== 'all' || statusFilter !== 'all'\n ? 'empty-search'\n : 'empty-data'\n }\n title={tc('assethandler.assets.list.empty.title', 'No {{assetsLower}} found')}\n description={tc(\n 'assethandler.assets.list.empty.description',\n 'Try adjusting your filters or add a new {{assetLower}} to get started.'\n )}\n action={\n <Button size=\"sm\" onClick={() => navigate('/assets/asset-create')}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {tc('assethandler.assets.list.actions.addAsset', 'Add {{asset}}')}\n </Button>\n }\n />\n )}\n </div>\n );\n}\n\nfunction RowActions({\n onView,\n onCopy,\n onPrint,\n}: {\n onView: () => void;\n onCopy: () => void;\n onPrint: () => void;\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-8 w-8\" aria-label=\"Asset actions\">\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={onView}>\n <Eye className=\"mr-2 h-4 w-4\" />\n View details\n </DropdownMenuItem>\n <DropdownMenuItem onClick={onCopy}>\n <Copy className=\"mr-2 h-4 w-4\" />\n Copy asset tag\n </DropdownMenuItem>\n <DropdownMenuItem onClick={onPrint}>\n <Printer className=\"mr-2 h-4 w-4\" />\n Print tag\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetsAssetTrackingPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetTrackingPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n GradientText,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport {\n MapPin,\n Search,\n MapPinned,\n Building,\n HelpCircle,\n UserX,\n ChevronDown,\n ChevronRight,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type Asset } from '../store/assethandlerStore';\nimport { ChartCard, StatTile, BarsChart, formatCompact } from '../components';\n\nconst UNLOCATED = 'Unlocated';\n\n// Soft, semantic status pill — active=green, maintenance=amber, disposed=red,\n// inactive/retired=neutral. Tokens only (matches the rest of the AH surfaces).\nconst STATUS_PILL: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n maintenance: 'bg-status-warning-bg-subtle text-status-warning-text',\n inactive: 'bg-bg-sunken text-text-secondary',\n retired: 'bg-bg-sunken text-text-secondary',\n disposed: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\ninterface GroupCounts {\n total: number;\n active: number;\n maintenance: number;\n retired: number;\n unassigned: number;\n}\n\nfunction countGroup(assets: Asset[]): GroupCounts {\n return assets.reduce<GroupCounts>(\n (acc, a) => {\n acc.total += 1;\n if (a.status === 'active') acc.active += 1;\n if (a.status === 'maintenance') acc.maintenance += 1;\n if (a.status === 'retired') acc.retired += 1;\n if (!a.assignedTo.trim()) acc.unassigned += 1;\n return acc;\n },\n { total: 0, active: 0, maintenance: 0, retired: 0, unassigned: 0 }\n );\n}\n\nexport function AssetsAssetTrackingPage() {\n const navigate = useAssetHandlerNavigate();\n const { assets } = useAssetHandlerStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});\n\n const filteredAssets = useMemo(() => {\n const query = searchQuery.trim().toLowerCase();\n if (!query) return assets;\n return assets.filter(\n (asset) =>\n asset.name.toLowerCase().includes(query) ||\n asset.assetTag.toLowerCase().includes(query) ||\n asset.location.toLowerCase().includes(query)\n );\n }, [assets, searchQuery]);\n\n const locationGroups = useMemo(\n () =>\n filteredAssets.reduce<Record<string, Asset[]>>((acc, asset) => {\n const key = asset.location.trim() || UNLOCATED;\n if (!acc[key]) acc[key] = [];\n acc[key].push(asset);\n return acc;\n }, {}),\n [filteredAssets]\n );\n\n const locatedCount = assets.filter((a) => a.location.trim()).length;\n const unlocatedCount = assets.length - locatedCount;\n const unassignedCount = assets.filter((a) => !a.assignedTo.trim()).length;\n const locationCount = Object.keys(\n assets.reduce<Record<string, true>>((acc, a) => {\n const key = a.location.trim();\n if (key) acc[key] = true;\n return acc;\n }, {})\n ).length;\n\n const sortedGroups = useMemo(\n () =>\n Object.entries(locationGroups).sort(([a], [b]) => {\n if (a === UNLOCATED) return 1;\n if (b === UNLOCATED) return -1;\n return a.localeCompare(b);\n }),\n [locationGroups]\n );\n\n // Top locations by asset count (real, point-in-time) for the comparison chart.\n const byLocation = useMemo(\n () =>\n Object.entries(\n assets.reduce<Record<string, number>>((acc, a) => {\n const key = a.location.trim() || UNLOCATED;\n acc[key] = (acc[key] || 0) + 1;\n return acc;\n }, {})\n )\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([location, count]) => ({ location, count })),\n [assets]\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <div>\n <p className=\"text-xs font-semibold uppercase tracking-wide text-text-muted\">\n Asset tracking · by location\n </p>\n <h1 className=\"mt-1 text-2xl font-bold\">\n <GradientText>Asset Tracking</GradientText>\n </h1>\n </div>\n\n {/* Hero search */}\n <div className=\"relative\">\n <Search className=\"absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search to locate an asset by name, tag or location…\"\n className=\"h-12 pl-10 text-base\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.target.value)}\n />\n </div>\n\n {/* KPI strip */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Locations\"\n value={locationCount}\n format={formatCompact}\n icon={Building}\n hero\n />\n <StatTile\n label=\"Assets located\"\n value={locatedCount}\n format={formatCompact}\n icon={MapPinned}\n />\n <StatTile\n label=\"Unlocated\"\n value={unlocatedCount}\n format={formatCompact}\n icon={HelpCircle}\n />\n <StatTile label=\"Unassigned\" value={unassignedCount} format={formatCompact} icon={UserX} />\n </div>\n\n {byLocation.length > 0 ? (\n <ChartCard\n title=\"Assets by location\"\n subtitle=\"Top locations by asset count\"\n icon={MapPinned}\n >\n <BarsChart\n data={byLocation}\n xKey=\"location\"\n orientation=\"horizontal\"\n height={Math.max(180, byLocation.length * 40)}\n categoryWidth={130}\n valueFormat={formatCompact}\n series={[{ key: 'count', label: 'Assets' }]}\n />\n </ChartCard>\n ) : null}\n\n <PagePurpose>\n Know where your assets physically are. Assets are grouped by their recorded location, so you\n can find equipment fast, spot items that still have no location on file, and confirm things\n are where they should be. Click any asset to open its full record.\n </PagePurpose>\n\n {assets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets to track\"\n description=\"Add an asset and give it a location to see it grouped here.\"\n />\n ) : filteredAssets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching assets\"\n description=\"No assets match your search — try a different name, tag or location.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {sortedGroups.map(([location, groupAssets]) => {\n const counts = countGroup(groupAssets);\n const isCollapsed = collapsed[location];\n return (\n <GlassCard key={location} treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-4 sm:p-5\">\n <button\n type=\"button\"\n onClick={() =>\n setCollapsed((prev) => ({ ...prev, [location]: !prev[location] }))\n }\n className=\"flex w-full items-start justify-between gap-3 text-left\"\n aria-expanded={!isCollapsed}\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n {isCollapsed ? (\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n )}\n <Building className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"truncate text-base font-semibold\">{location}</span>\n </span>\n <span className=\"flex shrink-0 flex-wrap items-center justify-end gap-x-4 gap-y-1 text-sm tabular-nums\">\n <span className=\"font-semibold\">{counts.total}</span>\n <span className=\"text-status-warning-text\">{counts.maintenance}</span>\n <span className=\"text-status-success-text\">{counts.active}</span>\n <span className=\"text-text-muted\">{counts.unassigned}</span>\n </span>\n </button>\n\n {!isCollapsed ? (\n <div className=\"mt-3 space-y-1.5 border-t border-border-seam pt-3\">\n {groupAssets.map((asset) => (\n <button\n key={asset.id}\n type=\"button\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left hover:bg-bg-sunken/60\"\n >\n <MapPin className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium\">{asset.name}</span>\n <span className=\"block truncate text-xs text-text-secondary\">\n {asset.assetTag}\n {asset.assignedTo ? <> · {asset.assignedTo}</> : null}\n </span>\n </span>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium capitalize ${\n STATUS_PILL[asset.status] || 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {asset.status.replace(/_/g, ' ')}\n </span>\n </button>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetsAssetTrackingPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetTrackingPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n GradientText,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport {\n MapPin,\n Search,\n MapPinned,\n Building,\n HelpCircle,\n UserX,\n ChevronDown,\n ChevronRight,\n} from 'lucide-react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { useAssetHandlerStore, type Asset } from '../store/assethandlerStore';\nimport { ChartCard, StatTile, BarsChart, formatCompact } from '../components';\n\nconst UNLOCATED = 'Unlocated';\n\n// Soft, semantic status pill — active=green, maintenance=amber, disposed=red,\n// inactive/retired=neutral. Tokens only (matches the rest of the AH surfaces).\nconst STATUS_PILL: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n maintenance: 'bg-status-warning-bg-subtle text-status-warning-text',\n inactive: 'bg-bg-sunken text-text-secondary',\n retired: 'bg-bg-sunken text-text-secondary',\n disposed: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\ninterface GroupCounts {\n total: number;\n active: number;\n maintenance: number;\n retired: number;\n unassigned: number;\n}\n\nfunction countGroup(assets: Asset[]): GroupCounts {\n return assets.reduce<GroupCounts>(\n (acc, a) => {\n acc.total += 1;\n if (a.status === 'active') acc.active += 1;\n if (a.status === 'maintenance') acc.maintenance += 1;\n if (a.status === 'retired') acc.retired += 1;\n if (!a.assignedTo.trim()) acc.unassigned += 1;\n return acc;\n },\n { total: 0, active: 0, maintenance: 0, retired: 0, unassigned: 0 }\n );\n}\n\nexport function AssetsAssetTrackingPage() {\n const navigate = useAssetHandlerNavigate();\n const { assets } = useAssetHandlerStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});\n\n const filteredAssets = useMemo(() => {\n const query = searchQuery.trim().toLowerCase();\n if (!query) return assets;\n return assets.filter(\n (asset) =>\n asset.name.toLowerCase().includes(query) ||\n asset.assetTag.toLowerCase().includes(query) ||\n asset.location.toLowerCase().includes(query)\n );\n }, [assets, searchQuery]);\n\n const locationGroups = useMemo(\n () =>\n filteredAssets.reduce<Record<string, Asset[]>>((acc, asset) => {\n const key = asset.location.trim() || UNLOCATED;\n if (!acc[key]) acc[key] = [];\n acc[key].push(asset);\n return acc;\n }, {}),\n [filteredAssets]\n );\n\n const locatedCount = assets.filter((a) => a.location.trim()).length;\n const unlocatedCount = assets.length - locatedCount;\n const unassignedCount = assets.filter((a) => !a.assignedTo.trim()).length;\n const locationCount = Object.keys(\n assets.reduce<Record<string, true>>((acc, a) => {\n const key = a.location.trim();\n if (key) acc[key] = true;\n return acc;\n }, {})\n ).length;\n\n const sortedGroups = useMemo(\n () =>\n Object.entries(locationGroups).sort(([a], [b]) => {\n if (a === UNLOCATED) return 1;\n if (b === UNLOCATED) return -1;\n return a.localeCompare(b);\n }),\n [locationGroups]\n );\n\n // Top locations by asset count (real, point-in-time) for the comparison chart.\n const byLocation = useMemo(\n () =>\n Object.entries(\n assets.reduce<Record<string, number>>((acc, a) => {\n const key = a.location.trim() || UNLOCATED;\n acc[key] = (acc[key] || 0) + 1;\n return acc;\n }, {})\n )\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8)\n .map(([location, count]) => ({ location, count })),\n [assets]\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n <div>\n <p className=\"text-xs font-semibold uppercase tracking-wide text-text-muted\">\n Asset tracking · by location\n </p>\n <h1 className=\"mt-1 text-2xl font-bold\">\n <GradientText>Asset Tracking</GradientText>\n </h1>\n </div>\n\n {/* Hero search */}\n <div className=\"relative\">\n <Search className=\"absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search to locate an asset by name, tag or location…\"\n className=\"h-12 pl-10 text-base\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.target.value)}\n />\n </div>\n\n {/* KPI strip */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Locations\"\n value={locationCount}\n format={formatCompact}\n icon={Building}\n hero\n />\n <StatTile\n label=\"Assets located\"\n value={locatedCount}\n format={formatCompact}\n icon={MapPinned}\n />\n <StatTile\n label=\"Unlocated\"\n value={unlocatedCount}\n format={formatCompact}\n icon={HelpCircle}\n />\n <StatTile label=\"Unassigned\" value={unassignedCount} format={formatCompact} icon={UserX} />\n </div>\n\n {byLocation.length > 0 ? (\n <ChartCard\n title=\"Assets by location\"\n subtitle=\"Top locations by asset count\"\n icon={MapPinned}\n >\n <BarsChart\n data={byLocation}\n xKey=\"location\"\n orientation=\"horizontal\"\n height={Math.max(180, byLocation.length * 40)}\n categoryWidth={130}\n valueFormat={formatCompact}\n series={[{ key: 'count', label: 'Assets' }]}\n />\n </ChartCard>\n ) : null}\n\n <PagePurpose>\n Know where your assets physically are. Assets are grouped by their recorded location, so you\n can find equipment fast, spot items that still have no location on file, and confirm things\n are where they should be. Click any asset to open its full record.\n </PagePurpose>\n\n {assets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets to track\"\n description=\"Add an asset and give it a location to see it grouped here.\"\n />\n ) : filteredAssets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching assets\"\n description=\"No assets match your search — try a different name, tag or location.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {sortedGroups.map(([location, groupAssets]) => {\n const counts = countGroup(groupAssets);\n const isCollapsed = collapsed[location];\n return (\n <GlassCard key={location} treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"p-4 sm:p-5\">\n <button\n type=\"button\"\n onClick={() =>\n setCollapsed((prev) => ({ ...prev, [location]: !prev[location] }))\n }\n className=\"flex w-full items-start justify-between gap-3 text-left\"\n aria-expanded={!isCollapsed}\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n {isCollapsed ? (\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n )}\n <Building className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"truncate text-base font-semibold\">{location}</span>\n </span>\n <span className=\"flex shrink-0 flex-wrap items-center justify-end gap-x-4 gap-y-1 text-sm tabular-nums\">\n <span className=\"font-semibold\">{counts.total}</span>\n <span className=\"text-status-warning-text\">{counts.maintenance}</span>\n <span className=\"text-status-success-text\">{counts.active}</span>\n <span className=\"text-text-muted\">{counts.unassigned}</span>\n </span>\n </button>\n\n {!isCollapsed ? (\n <div className=\"mt-3 space-y-1.5 border-t border-border-seam pt-3\">\n {groupAssets.map((asset) => (\n <button\n key={asset.id}\n type=\"button\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left hover:bg-bg-sunken/60\"\n >\n <MapPin className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium\">{asset.name}</span>\n <span className=\"block truncate text-xs text-text-secondary\">\n {asset.assetTag}\n {asset.assignedTo ? <> · {asset.assignedTo}</> : null}\n </span>\n </span>\n <span\n className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium capitalize ${\n STATUS_PILL[asset.status] || 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {asset.status.replace(/_/g, ' ')}\n </span>\n </button>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAsBA,IAAM,IAAY,aAIZ,IAAsC;CAC1C,QAAQ;CACR,aAAa;CACb,UAAU;CACV,SAAS;CACT,UAAU;AACZ;AAUA,SAAS,EAAW,GAA8B;CAChD,OAAO,EAAO,QACX,GAAK,OACJ,EAAI,SAAS,GACT,EAAE,WAAW,aAAU,EAAI,UAAU,IACrC,EAAE,WAAW,kBAAe,EAAI,eAAe,IAC/C,EAAE,WAAW,cAAW,EAAI,WAAW,IACtC,EAAE,WAAW,KAAK,MAAG,EAAI,cAAc,IACrC,IAET;EAAE,OAAO;EAAG,QAAQ;EAAG,aAAa;EAAG,SAAS;EAAG,YAAY;CAAE,CACnE;AACF;AAEA,SAAgB,IAA0B;CACxC,IAAM,IAAW,EAAwB,GACnC,EAAE,cAAW,EAAqB,GAClC,CAAC,GAAa,KAAkB,EAAS,EAAE,GAC3C,CAAC,GAAW,KAAgB,EAAkC,CAAC,CAAC,GAEhE,IAAiB,QAAc;EACnC,IAAM,IAAQ,EAAY,KAAK,EAAE,YAAY;EAE7C,OADK,IACE,EAAO,QACX,MACC,EAAM,KAAK,YAAY,EAAE,SAAS,CAAK,KACvC,EAAM,SAAS,YAAY,EAAE,SAAS,CAAK,KAC3C,EAAM,SAAS,YAAY,EAAE,SAAS,CAAK,CAC/C,IANmB;CAOrB,GAAG,CAAC,GAAQ,CAAW,CAAC,GAElB,IAAiB,QAEnB,EAAe,QAAiC,GAAK,MAAU;EAC7D,IAAM,IAAM,EAAM,SAAS,KAAK,KAAK;EAGrC,OAFK,EAAI,OAAM,EAAI,KAAO,CAAC,IAC3B,EAAI,GAAK,KAAK,CAAK,GACZ;CACT,GAAG,CAAC,CAAC,GACP,CAAC,CAAc,CACjB,GAEM,IAAe,EAAO,QAAQ,MAAM,EAAE,SAAS,KAAK,CAAC,EAAE,QACvD,IAAiB,EAAO,SAAS,GACjC,IAAkB,EAAO,QAAQ,MAAM,CAAC,EAAE,WAAW,KAAK,CAAC,EAAE,QAC7D,IAAgB,OAAO,KAC3B,EAAO,QAA8B,GAAK,MAAM;EAC9C,IAAM,IAAM,EAAE,SAAS,KAAK;EAE5B,OADI,MAAK,EAAI,KAAO,KACb;CACT,GAAG,CAAC,CAAC,CACP,EAAE,QAEI,IAAe,QAEjB,OAAO,QAAQ,CAAc,EAAE,MAAM,CAAC,IAAI,CAAC,OACrC,MAAM,IAAkB,IACxB,MAAM,IAAkB,KACrB,EAAE,cAAc,CAAC,CACzB,GACH,CAAC,CAAc,CACjB,GAGM,IAAa,QAEf,OAAO,QACL,EAAO,QAAgC,GAAK,MAAM;EAChD,IAAM,IAAM,EAAE,SAAS,KAAK,KAAK;EAEjC,OADA,EAAI,MAAQ,EAAI,MAAQ,KAAK,GACtB;CACT,GAAG,CAAC,CAAC,CACP,EACG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,EAC1B,MAAM,GAAG,CAAC,EACV,KAAK,CAAC,GAAU,QAAY;EAAE;EAAU;CAAM,EAAE,GACrD,CAAC,CAAM,CACT;CAEA,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;IAAG,WAAU;cAAgE;GAE1E,CAAA,GACH,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,GAAD,EAAA,UAAc,iBAA4B,CAAA;GACxC,CAAA,CACD,EAAA,CAAA;GAGL,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,yEAA0E,CAAA,GAC5F,kBAAC,GAAD;KACE,aAAY;KACZ,WAAU;KACV,OAAO;KACP,WAAW,MAAU,EAAe,EAAM,OAAO,KAAK;IACvD,CAAA,CACE;;GAGL,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,QAAQ;MACR,MAAM;MACN,MAAA;KACD,CAAA;KACD,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,QAAQ;MACR,MAAM;KACP,CAAA;KACD,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,QAAQ;MACR,MAAM;KACP,CAAA;KACD,kBAAC,GAAD;MAAU,OAAM;MAAa,OAAO;MAAiB,QAAQ;MAAe,MAAM;KAAQ,CAAA;IACvF;;GAEJ,EAAW,SAAS,IACnB,kBAAC,GAAD;IACE,OAAM;IACN,UAAS;IACT,MAAM;cAEN,kBAAC,GAAD;KACE,MAAM;KACN,MAAK;KACL,aAAY;KACZ,QAAQ,KAAK,IAAI,KAAK,EAAW,SAAS,EAAE;KAC5C,eAAe;KACf,aAAa;KACb,QAAQ,CAAC;MAAE,KAAK;MAAS,OAAO;KAAS,CAAC;IAC3C,CAAA;GACQ,CAAA,IACT;GAEJ,kBAAC,GAAD,EAAA,UAAa,8PAIA,CAAA;GAEZ,EAAO,WAAW,IACjB,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;GACb,CAAA,IACC,EAAe,WAAW,IAC5B,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;GACb,CAAA,IAED,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAa,KAAK,CAAC,GAAU,OAAiB;KAC7C,IAAM,IAAS,EAAW,CAAW,GAC/B,IAAc,EAAU;KAC9B,OACE,kBAAC,GAAD;MAA0B,WAAU;MAAQ,WAAU;gBACpD,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,MAAK;QACL,eACE,GAAc,OAAU;SAAE,GAAG;UAAO,IAAW,CAAC,EAAK;QAAU,EAAE;QAEnE,WAAU;QACV,iBAAe,CAAC;kBANlB,CAQE,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UAEI,EADD,IACE,IAEA,GAFD,EAAc,WAAU,uCAAwC,CAED;UAEjE,kBAAC,GAAD,EAAU,WAAU,uCAAwC,CAAA;UAC5D,kBAAC,QAAD;WAAM,WAAU;qBAAoC;UAAe,CAAA;SAC/D;YACN,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,QAAD;WAAM,WAAU;qBAAiB,EAAO;UAAY,CAAA;UACpD,kBAAC,QAAD;WAAM,WAAU;qBAA4B,EAAO;UAAkB,CAAA;UACrE,kBAAC,QAAD;WAAM,WAAU;qBAA4B,EAAO;UAAa,CAAA;UAChE,kBAAC,QAAD;WAAM,WAAU;qBAAmB,EAAO;UAAiB,CAAA;SACvD;UACA;WAEN,IA2BE,OA1BF,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAY,KAAK,MAChB,kBAAC,UAAD;SAEE,MAAK;SACL,eAAe,EAAS,WAAW,EAAM,IAAI;SAC7C,WAAU;mBAJZ;UAME,kBAAC,GAAD,EAAQ,WAAU,uCAAwC,CAAA;UAC1D,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsC,EAAM;WAAW,CAAA,GACvE,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CACG,EAAM,UACN,EAAM,aAAa,kBAAA,GAAA,EAAA,UAAA,CAAE,OAAI,EAAM,UAAa,EAAA,CAAA,IAAI,IAC7C;aACF;;UACN,kBAAC,QAAD;WACE,WAAW,sEACT,EAAY,EAAM,WAAW;qBAG9B,EAAM,OAAO,QAAQ,MAAM,GAAG;UAC3B,CAAA;SACA;WApBD,EAAM,EAoBL,CACT;OACE,CAAA,CAEJ;;KACI,GAxDK,CAwDL;IAEf,CAAC;GACE,CAAA;EAEJ;;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CmdbBrowserPage.js","names":[],"sources":["../../../src/assethandler/pages/CmdbBrowserPage.tsx"],"sourcesContent":["import {\n Network,\n Plus,\n Search,\n Server,\n Database,\n AppWindow,\n HardDrive,\n Cog,\n ChevronDown,\n ChevronRight,\n Pencil,\n X,\n Trash2,\n} from 'lucide-react';\nimport type { ComponentType, ReactNode } from 'react';\nimport { useMemo, useState, useSyncExternalStore } 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 {\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst CONFIGURATION_ITEMS_QUERY = gql`\n query AssetHandlerConfigurationItems {\n configurationItems {\n id\n ciNumber\n name\n ciType\n status\n environment\n owner\n attributes\n updatedAt\n }\n }\n`;\n\nconst UPSERT_CONFIGURATION_ITEM_MUTATION = gql`\n mutation AssetHandlerUpsertConfigurationItem($input: UpsertConfigurationItemInput!) {\n upsertConfigurationItem(input: $input) {\n id\n ciNumber\n }\n }\n`;\n\ninterface ConfigurationItem {\n id: string;\n ciNumber: string;\n name: string;\n ciType: string;\n status: string;\n environment: string | null;\n owner: string | null;\n attributes: Record<string, unknown> | null;\n updatedAt: string;\n}\n\ninterface UpsertConfigurationItemResult {\n upsertConfigurationItem: { id: string; ciNumber: string };\n}\n\nconst CI_TYPES = ['SERVER', 'SERVICE', 'DATABASE', 'NETWORK', 'APPLICATION', 'STORAGE'] as const;\nconst CI_STATUSES = ['ACTIVE', 'INACTIVE', 'MAINTENANCE', 'RETIRED'] as const;\nconst CI_ENVIRONMENTS = ['PRODUCTION', 'STAGING', 'DEVELOPMENT', 'DR'] as const;\n\nconst TYPE_ICON: Record<string, ComponentType<{ className?: string }>> = {\n SERVER: Server,\n SERVICE: Cog,\n DATABASE: Database,\n NETWORK: Network,\n APPLICATION: AppWindow,\n STORAGE: HardDrive,\n};\n\nconst STATUS_META: Record<string, { label: string; className: string }> = {\n ACTIVE: {\n label: 'Operational',\n className: 'bg-status-success-bg-subtle text-status-success-text',\n },\n MAINTENANCE: {\n label: 'Maintenance',\n className: 'bg-status-warning-bg-subtle text-status-warning-text',\n },\n INACTIVE: { label: 'Inactive', className: 'bg-bg-sunken text-text-secondary' },\n RETIRED: { label: 'Retired', className: 'bg-status-error-bg-subtle text-status-error-text' },\n};\n\nfunction StatusPill({ status }: { status: string }) {\n const meta = STATUS_META[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-secondary',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n meta.className\n )}\n >\n {meta.label}\n </span>\n );\n}\n\n/** Track a min-width breakpoint so the CI detail can render as a rail (desktop) or sheet (mobile). */\nfunction useIsLargeScreen(): boolean {\n return useSyncExternalStore(\n (onChange) => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return () => {};\n const mq = window.matchMedia('(min-width: 1024px)');\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n },\n () => (typeof window !== 'undefined' ? window.matchMedia('(min-width: 1024px)').matches : true),\n () => true\n );\n}\n\ntype AttrRow = { key: string; value: string };\n\nfunction toAttrRows(attributes: Record<string, unknown> | null | undefined): AttrRow[] {\n if (!attributes) return [];\n return Object.entries(attributes).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : JSON.stringify(value),\n }));\n}\n\nfunction UpsertConfigurationItemDialog({\n open,\n onOpenChange,\n seed,\n onSaved,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n seed: ConfigurationItem | null;\n onSaved: () => void;\n}) {\n const editing = Boolean(seed);\n const [ciNumber, setCiNumber] = useState('');\n const [name, setName] = useState('');\n const [ciType, setCiType] = useState<string>('SERVER');\n const [status, setStatus] = useState<string>('ACTIVE');\n const [environment, setEnvironment] = useState<string>('PRODUCTION');\n const [owner, setOwner] = useState('');\n const [attrs, setAttrs] = useState<AttrRow[]>([]);\n // Re-seed the form each time the dialog opens against a (possibly new) CI.\n const [seededId, setSeededId] = useState<string | null>(null);\n if (open && seededId !== (seed?.id ?? '__new__')) {\n setSeededId(seed?.id ?? '__new__');\n setCiNumber(seed?.ciNumber ?? '');\n setName(seed?.name ?? '');\n setCiType(seed?.ciType ?? 'SERVER');\n setStatus(seed?.status ?? 'ACTIVE');\n setEnvironment(seed?.environment ?? 'PRODUCTION');\n setOwner(seed?.owner ?? '');\n setAttrs(toAttrRows(seed?.attributes));\n }\n if (!open && seededId !== null) setSeededId(null);\n\n const [upsertItem, { loading }] = useMutation<UpsertConfigurationItemResult>(\n UPSERT_CONFIGURATION_ITEM_MUTATION,\n {\n onCompleted: (data) => {\n notify.success(\n editing ? 'Configuration item updated' : 'Configuration item saved',\n `${data.upsertConfigurationItem.ciNumber} is now in the CMDB.`\n );\n onOpenChange(false);\n onSaved();\n },\n onError: (error) => notify.error('Could not save configuration item', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!ciNumber.trim() || !name.trim()) {\n notify.warning('Missing details', 'CI number and name are required.');\n return;\n }\n const attributes = attrs.reduce<Record<string, string>>((acc, row) => {\n if (row.key.trim()) acc[row.key.trim()] = row.value;\n return acc;\n }, {});\n void upsertItem({\n variables: {\n input: {\n ...(seed ? { id: seed.id } : {}),\n ciNumber: ciNumber.trim(),\n name: name.trim(),\n ciType,\n status,\n environment,\n owner: owner.trim() || null,\n attributes,\n },\n },\n });\n };\n\n const updateAttr = (index: number, patch: Partial<AttrRow>) =>\n setAttrs((rows) => rows.map((r, i) => (i === index ? { ...r, ...patch } : r)));\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{editing ? 'Edit CI' : 'Add CI'}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a configuration item in the CMDB and map it to your estate.\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>CI Number *</Label>\n <Input\n placeholder=\"e.g., CI-1042\"\n value={ciNumber}\n onChange={(e) => setCiNumber(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={ciType} onValueChange={setCiType}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_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>Status</Label>\n <Select value={status} onValueChange={setStatus}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Environment</Label>\n <Select value={environment} onValueChange={setEnvironment}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_ENVIRONMENTS.map((e) => (\n <SelectItem key={e} value={e}>\n {e}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Owner</Label>\n <Input\n placeholder=\"e.g., Platform team\"\n value={owner}\n onChange={(e) => setOwner(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Attributes</Label>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setAttrs((rows) => [...rows, { key: '', value: '' }])}\n >\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add\n </Button>\n </div>\n {attrs.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n Add structured key/value attributes (e.g. hostname, region, tier).\n </p>\n ) : (\n <div className=\"space-y-2\">\n {attrs.map((row, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder=\"key\"\n value={row.key}\n onChange={(e) => updateAttr(i, { key: e.target.value })}\n className=\"flex-1\"\n />\n <Input\n placeholder=\"value\"\n value={row.value}\n onChange={(e) => updateAttr(i, { value: e.target.value })}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setAttrs((rows) => rows.filter((_, idx) => idx !== i))}\n aria-label=\"Remove attribute\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\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 ? 'Saving…' : editing ? 'Save changes' : 'Add CI'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: ReactNode }) {\n return (\n <div className=\"flex items-start justify-between gap-3 py-2\">\n <span className=\"text-sm text-text-secondary\">{label}</span>\n <span className=\"min-w-0 text-right text-sm font-medium text-text-primary\">{value}</span>\n </div>\n );\n}\n\nfunction CiDetail({\n ci,\n onEdit,\n onClose,\n}: {\n ci: ConfigurationItem;\n onEdit: () => void;\n onClose?: () => void;\n}) {\n const attrRows = toAttrRows(ci.attributes);\n const TypeIcon = TYPE_ICON[ci.ciType] ?? Cog;\n return (\n <div className=\"space-y-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-action-primary-bg/10 text-primary\">\n <TypeIcon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-base font-semibold text-text-primary\">{ci.name}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{ci.ciNumber}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button variant=\"outline\" size=\"sm\" onClick={onEdit}>\n <Pencil className=\"mr-1 h-3.5 w-3.5\" />\n Edit\n </Button>\n {onClose ? (\n <Button variant=\"ghost\" size=\"icon\" onClick={onClose} aria-label=\"Close detail\">\n <X className=\"h-4 w-4\" />\n </Button>\n ) : null}\n </div>\n </div>\n\n <div className=\"divide-y divide-border-seam/60\">\n <DetailRow label=\"Type\" value={ci.ciType} />\n <DetailRow label=\"Environment\" value={ci.environment ?? '—'} />\n <DetailRow label=\"Owner\" value={ci.owner ?? '—'} />\n <DetailRow label=\"Status\" value={<StatusPill status={ci.status} />} />\n <DetailRow\n label=\"Updated\"\n value={new Date(ci.updatedAt).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })}\n />\n </div>\n\n <div>\n <h4 className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Attributes\n </h4>\n {attrRows.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No attributes recorded for this CI.</p>\n ) : (\n <div className=\"divide-y divide-border-seam/60 rounded-lg bg-bg-sunken/40\">\n {attrRows.map((row) => (\n <div key={row.key} className=\"flex items-start justify-between gap-3 px-3 py-2\">\n <span className=\"text-sm text-text-secondary\">{row.key}</span>\n <span className=\"min-w-0 break-words text-right text-sm font-medium text-text-primary\">\n {row.value}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport function CmdbBrowserPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editSeed, setEditSeed] = useState<ConfigurationItem | null>(null);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobileDetailOpen, setMobileDetailOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<string>('ALL');\n const [envFilter, setEnvFilter] = useState<string>('ALL');\n const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});\n const isLarge = useIsLargeScreen();\n\n const { data, loading, refetch } = useQuery<{ configurationItems: ConfigurationItem[] }>(\n CONFIGURATION_ITEMS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const cis = useMemo(() => data?.configurationItems ?? [], [data?.configurationItems]);\n\n const filtered = useMemo(() => {\n const term = search.trim().toLowerCase();\n return cis.filter((ci) => {\n if (statusFilter !== 'ALL' && ci.status !== statusFilter) return false;\n if (envFilter !== 'ALL' && ci.environment !== envFilter) return false;\n if (!term) return true;\n return [ci.ciNumber, ci.name, ci.ciType, ci.owner ?? '']\n .join(' ')\n .toLowerCase()\n .includes(term);\n });\n }, [cis, search, statusFilter, envFilter]);\n\n const grouped = useMemo(() => {\n const map = new Map<string, ConfigurationItem[]>();\n for (const ci of filtered) {\n const key = ci.ciType || 'OTHER';\n const bucket = map.get(key);\n if (bucket) bucket.push(ci);\n else map.set(key, [ci]);\n }\n return [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n }, [filtered]);\n\n const stats = useMemo(() => {\n const total = cis.length;\n const operational = cis.filter((c) => c.status === 'ACTIVE').length;\n const maintenance = cis.filter((c) => c.status === 'MAINTENANCE').length;\n const retired = cis.filter((c) => c.status === 'RETIRED').length;\n return {\n total,\n operationalPct: total > 0 ? Math.round((operational / total) * 100) : 0,\n maintenance,\n retired,\n };\n }, [cis]);\n\n const statusMix = useMemo<DonutSlice[]>(() => {\n const counts = cis.reduce<Record<string, number>>((acc, c) => {\n acc[c.status] = (acc[c.status] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([status, value], i) => ({\n name: STATUS_META[status]?.label ?? status,\n value,\n color: seriesColor(i),\n }));\n }, [cis]);\n\n const typeBars = useMemo(() => {\n const counts = cis.reduce<Record<string, number>>((acc, c) => {\n acc[c.ciType] = (acc[c.ciType] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .map(([type, count]) => ({ name: type, count }));\n }, [cis]);\n\n const selected = useMemo(() => cis.find((c) => c.id === selectedId) ?? null, [cis, selectedId]);\n\n const handleSelect = (ci: ConfigurationItem) => {\n setSelectedId(ci.id);\n if (!isLarge) setMobileDetailOpen(true);\n };\n\n const openCreate = () => {\n setEditSeed(null);\n setDialogOpen(true);\n };\n\n const openEdit = (ci: ConfigurationItem) => {\n setEditSeed(ci);\n setDialogOpen(true);\n setMobileDetailOpen(false);\n };\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <Network className=\"mt-1 h-6 w-6 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <GradientText as=\"h1\" className=\"text-2xl font-bold sm:text-3xl\">\n CMDB — Configuration Items\n </GradientText>\n <p className=\"mt-1 max-w-2xl text-sm text-text-secondary\">\n A living map of every configuration item and its attributes.\n </p>\n </div>\n </div>\n <Button className=\"w-full sm:w-auto\" onClick={openCreate}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Add CI\n </Button>\n </div>\n <PagePurpose>\n Your configuration management database (CMDB): servers, services, network gear and how they\n relate. Browse, search and inspect each configuration item to understand blast radius before\n a change and keep asset relationships accurate.\n </PagePurpose>\n\n <UpsertConfigurationItemDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n seed={editSeed}\n onSaved={() => void refetch()}\n />\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile label=\"Total CIs\" value={stats.total} icon={Network} />\n <StatTile\n label=\"Operational\"\n value={stats.operationalPct}\n format={(n) => `${n}%`}\n icon={Server}\n deltaTone=\"positive\"\n />\n <StatTile label=\"In Maintenance\" value={stats.maintenance} icon={Cog} deltaTone=\"neutral\" />\n <StatTile label=\"Retired\" value={stats.retired} icon={HardDrive} deltaTone=\"neutral\" />\n </div>\n\n {cis.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Status mix\" subtitle=\"Configuration items by status\">\n <DonutChart\n data={statusMix}\n height={220}\n centerLabel=\"CIs\"\n centerValue={stats.total}\n ariaLabel=\"Configuration items by status\"\n />\n </ChartCard>\n <ChartCard title=\"By type\" subtitle=\"Configuration items per type\">\n <BarsChart\n data={typeBars}\n xKey=\"name\"\n series={[{ key: 'count', label: 'Items' }]}\n orientation=\"horizontal\"\n height={220}\n categoryWidth={110}\n ariaLabel=\"Configuration items per type\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"grid gap-4 lg:grid-cols-[1fr_360px]\">\n {/* Navigator */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"space-y-3 p-4\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n className=\"pl-9\"\n placeholder=\"Search CIs by number, name, type or owner…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label=\"Search configuration items\"\n />\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {CI_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={envFilter} onValueChange={setEnvFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Environment\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All environments</SelectItem>\n {CI_ENVIRONMENTS.map((e) => (\n <SelectItem key={e} value={e}>\n {e}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"border-t border-border-seam\">\n {loading && cis.length === 0 ? (\n <div className=\"space-y-2 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div\n key={i}\n className=\"h-9 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : null}\n {!loading && filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'empty-search'\n : 'empty-data'\n }\n title={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'No configuration items match'\n : 'No configuration items found'\n }\n description={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'Try a different search or filter.'\n : 'Add a configuration item to start mapping your estate.'\n }\n />\n ) : null}\n <div className=\"max-h-[540px] overflow-y-auto\">\n {grouped.map(([type, items]) => {\n const TypeIcon = TYPE_ICON[type] ?? Cog;\n const isCollapsed = collapsed[type];\n return (\n <div key={type}>\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => ({ ...c, [type]: !c[type] }))}\n className=\"flex w-full items-center gap-2 border-b border-border-seam/60 bg-bg-sunken/30 px-4 py-2 text-left text-sm font-semibold text-text-primary\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"h-4 w-4 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 text-text-secondary\" />\n )}\n <TypeIcon className=\"h-4 w-4 text-primary\" />\n <span className=\"capitalize\">{type.toLowerCase()}</span>\n <span className=\"ml-auto rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary tabular-nums\">\n {items.length}\n </span>\n </button>\n {!isCollapsed\n ? items.map((ci) => (\n <button\n key={ci.id}\n type=\"button\"\n onClick={() => handleSelect(ci)}\n aria-current={selectedId === ci.id}\n className={cn(\n 'flex w-full items-center gap-3 border-b border-border-seam/40 px-4 py-2.5 pl-10 text-left last:border-b-0',\n selectedId === ci.id\n ? 'bg-action-primary-bg/10'\n : 'hover:bg-bg-sunken/40'\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {ci.name}\n </p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {ci.ciNumber}\n {ci.environment ? ` · ${ci.environment}` : ''}\n </p>\n </div>\n <StatusPill status={ci.status} />\n </button>\n ))\n : null}\n </div>\n );\n })}\n </div>\n </div>\n </GlassCard>\n\n {/* Detail rail (desktop) */}\n <div className=\"hidden lg:block\">\n <GlassCard treatment=\"glass\" className=\"sticky top-4 border-border-seam\">\n <div className=\"p-4\">\n {selected ? (\n <CiDetail ci={selected} onEdit={() => openEdit(selected)} />\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-2 py-12 text-center\">\n <Network className=\"h-8 w-8 text-text-muted\" />\n <p className=\"text-sm font-medium text-text-primary\">\n Select a configuration item\n </p>\n <p className=\"text-xs text-text-secondary\">\n Choose a CI from the navigator to inspect its attributes.\n </p>\n </div>\n )}\n </div>\n </GlassCard>\n </div>\n </div>\n\n {/* Detail sheet (mobile) */}\n <ResponsiveDialog open={mobileDetailOpen && !isLarge} onOpenChange={setMobileDetailOpen}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Configuration item</ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n {selected ? <CiDetail ci={selected} onEdit={() => openEdit(selected)} /> : null}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CmdbBrowserPage.js","names":[],"sources":["../../../src/assethandler/pages/CmdbBrowserPage.tsx"],"sourcesContent":["import {\n Network,\n Plus,\n Search,\n Server,\n Database,\n AppWindow,\n HardDrive,\n Cog,\n ChevronDown,\n ChevronRight,\n Pencil,\n X,\n Trash2,\n} from 'lucide-react';\nimport type { ComponentType, ReactNode } from 'react';\nimport { useMemo, useState, useSyncExternalStore } 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 {\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst CONFIGURATION_ITEMS_QUERY = gql`\n query AssetHandlerConfigurationItems {\n configurationItems {\n id\n ciNumber\n name\n ciType\n status\n environment\n owner\n attributes\n updatedAt\n }\n }\n`;\n\nconst UPSERT_CONFIGURATION_ITEM_MUTATION = gql`\n mutation AssetHandlerUpsertConfigurationItem($input: UpsertConfigurationItemInput!) {\n upsertConfigurationItem(input: $input) {\n id\n ciNumber\n }\n }\n`;\n\ninterface ConfigurationItem {\n id: string;\n ciNumber: string;\n name: string;\n ciType: string;\n status: string;\n environment: string | null;\n owner: string | null;\n attributes: Record<string, unknown> | null;\n updatedAt: string;\n}\n\ninterface UpsertConfigurationItemResult {\n upsertConfigurationItem: { id: string; ciNumber: string };\n}\n\nconst CI_TYPES = ['SERVER', 'SERVICE', 'DATABASE', 'NETWORK', 'APPLICATION', 'STORAGE'] as const;\nconst CI_STATUSES = ['ACTIVE', 'INACTIVE', 'MAINTENANCE', 'RETIRED'] as const;\nconst CI_ENVIRONMENTS = ['PRODUCTION', 'STAGING', 'DEVELOPMENT', 'DR'] as const;\n\nconst TYPE_ICON: Record<string, ComponentType<{ className?: string }>> = {\n SERVER: Server,\n SERVICE: Cog,\n DATABASE: Database,\n NETWORK: Network,\n APPLICATION: AppWindow,\n STORAGE: HardDrive,\n};\n\nconst STATUS_META: Record<string, { label: string; className: string }> = {\n ACTIVE: {\n label: 'Operational',\n className: 'bg-status-success-bg-subtle text-status-success-text',\n },\n MAINTENANCE: {\n label: 'Maintenance',\n className: 'bg-status-warning-bg-subtle text-status-warning-text',\n },\n INACTIVE: { label: 'Inactive', className: 'bg-bg-sunken text-text-secondary' },\n RETIRED: { label: 'Retired', className: 'bg-status-error-bg-subtle text-status-error-text' },\n};\n\nfunction StatusPill({ status }: { status: string }) {\n const meta = STATUS_META[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-secondary',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium',\n meta.className\n )}\n >\n {meta.label}\n </span>\n );\n}\n\n/** Track a min-width breakpoint so the CI detail can render as a rail (desktop) or sheet (mobile). */\nfunction useIsLargeScreen(): boolean {\n return useSyncExternalStore(\n (onChange) => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return () => {};\n const mq = window.matchMedia('(min-width: 1024px)');\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n },\n () => (typeof window !== 'undefined' ? window.matchMedia('(min-width: 1024px)').matches : true),\n () => true\n );\n}\n\ntype AttrRow = { key: string; value: string };\n\nfunction toAttrRows(attributes: Record<string, unknown> | null | undefined): AttrRow[] {\n if (!attributes) return [];\n return Object.entries(attributes).map(([key, value]) => ({\n key,\n value: typeof value === 'string' ? value : JSON.stringify(value),\n }));\n}\n\nfunction UpsertConfigurationItemDialog({\n open,\n onOpenChange,\n seed,\n onSaved,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n seed: ConfigurationItem | null;\n onSaved: () => void;\n}) {\n const editing = Boolean(seed);\n const [ciNumber, setCiNumber] = useState('');\n const [name, setName] = useState('');\n const [ciType, setCiType] = useState<string>('SERVER');\n const [status, setStatus] = useState<string>('ACTIVE');\n const [environment, setEnvironment] = useState<string>('PRODUCTION');\n const [owner, setOwner] = useState('');\n const [attrs, setAttrs] = useState<AttrRow[]>([]);\n // Re-seed the form each time the dialog opens against a (possibly new) CI.\n const [seededId, setSeededId] = useState<string | null>(null);\n if (open && seededId !== (seed?.id ?? '__new__')) {\n setSeededId(seed?.id ?? '__new__');\n setCiNumber(seed?.ciNumber ?? '');\n setName(seed?.name ?? '');\n setCiType(seed?.ciType ?? 'SERVER');\n setStatus(seed?.status ?? 'ACTIVE');\n setEnvironment(seed?.environment ?? 'PRODUCTION');\n setOwner(seed?.owner ?? '');\n setAttrs(toAttrRows(seed?.attributes));\n }\n if (!open && seededId !== null) setSeededId(null);\n\n const [upsertItem, { loading }] = useMutation<UpsertConfigurationItemResult>(\n UPSERT_CONFIGURATION_ITEM_MUTATION,\n {\n onCompleted: (data) => {\n notify.success(\n editing ? 'Configuration item updated' : 'Configuration item saved',\n `${data.upsertConfigurationItem.ciNumber} is now in the CMDB.`\n );\n onOpenChange(false);\n onSaved();\n },\n onError: (error) => notify.error('Could not save configuration item', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!ciNumber.trim() || !name.trim()) {\n notify.warning('Missing details', 'CI number and name are required.');\n return;\n }\n const attributes = attrs.reduce<Record<string, string>>((acc, row) => {\n if (row.key.trim()) acc[row.key.trim()] = row.value;\n return acc;\n }, {});\n void upsertItem({\n variables: {\n input: {\n ...(seed ? { id: seed.id } : {}),\n ciNumber: ciNumber.trim(),\n name: name.trim(),\n ciType,\n status,\n environment,\n owner: owner.trim() || null,\n attributes,\n },\n },\n });\n };\n\n const updateAttr = (index: number, patch: Partial<AttrRow>) =>\n setAttrs((rows) => rows.map((r, i) => (i === index ? { ...r, ...patch } : r)));\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{editing ? 'Edit CI' : 'Add CI'}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a configuration item in the CMDB and map it to your estate.\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>CI Number *</Label>\n <Input\n placeholder=\"e.g., CI-1042\"\n value={ciNumber}\n onChange={(e) => setCiNumber(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={ciType} onValueChange={setCiType}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_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>Status</Label>\n <Select value={status} onValueChange={setStatus}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Environment</Label>\n <Select value={environment} onValueChange={setEnvironment}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {CI_ENVIRONMENTS.map((e) => (\n <SelectItem key={e} value={e}>\n {e}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Owner</Label>\n <Input\n placeholder=\"e.g., Platform team\"\n value={owner}\n onChange={(e) => setOwner(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <Label>Attributes</Label>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setAttrs((rows) => [...rows, { key: '', value: '' }])}\n >\n <Plus className=\"mr-1 h-3.5 w-3.5\" />\n Add\n </Button>\n </div>\n {attrs.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n Add structured key/value attributes (e.g. hostname, region, tier).\n </p>\n ) : (\n <div className=\"space-y-2\">\n {attrs.map((row, i) => (\n <div key={i} className=\"flex items-center gap-2\">\n <Input\n placeholder=\"key\"\n value={row.key}\n onChange={(e) => updateAttr(i, { key: e.target.value })}\n className=\"flex-1\"\n />\n <Input\n placeholder=\"value\"\n value={row.value}\n onChange={(e) => updateAttr(i, { value: e.target.value })}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setAttrs((rows) => rows.filter((_, idx) => idx !== i))}\n aria-label=\"Remove attribute\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\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 ? 'Saving…' : editing ? 'Save changes' : 'Add CI'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: ReactNode }) {\n return (\n <div className=\"flex items-start justify-between gap-3 py-2\">\n <span className=\"text-sm text-text-secondary\">{label}</span>\n <span className=\"min-w-0 text-right text-sm font-medium text-text-primary\">{value}</span>\n </div>\n );\n}\n\nfunction CiDetail({\n ci,\n onEdit,\n onClose,\n}: {\n ci: ConfigurationItem;\n onEdit: () => void;\n onClose?: () => void;\n}) {\n const attrRows = toAttrRows(ci.attributes);\n const TypeIcon = TYPE_ICON[ci.ciType] ?? Cog;\n return (\n <div className=\"space-y-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-action-primary-bg/10 text-primary\">\n <TypeIcon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-base font-semibold text-text-primary\">{ci.name}</p>\n <p className=\"font-mono text-xs text-text-secondary\">{ci.ciNumber}</p>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button variant=\"outline\" size=\"sm\" onClick={onEdit}>\n <Pencil className=\"mr-1 h-3.5 w-3.5\" />\n Edit\n </Button>\n {onClose ? (\n <Button variant=\"ghost\" size=\"icon\" onClick={onClose} aria-label=\"Close detail\">\n <X className=\"h-4 w-4\" />\n </Button>\n ) : null}\n </div>\n </div>\n\n <div className=\"divide-y divide-border-seam/60\">\n <DetailRow label=\"Type\" value={ci.ciType} />\n <DetailRow label=\"Environment\" value={ci.environment ?? '—'} />\n <DetailRow label=\"Owner\" value={ci.owner ?? '—'} />\n <DetailRow label=\"Status\" value={<StatusPill status={ci.status} />} />\n <DetailRow\n label=\"Updated\"\n value={new Date(ci.updatedAt).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })}\n />\n </div>\n\n <div>\n <h4 className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Attributes\n </h4>\n {attrRows.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No attributes recorded for this CI.</p>\n ) : (\n <div className=\"divide-y divide-border-seam/60 rounded-lg bg-bg-sunken/40\">\n {attrRows.map((row) => (\n <div key={row.key} className=\"flex items-start justify-between gap-3 px-3 py-2\">\n <span className=\"text-sm text-text-secondary\">{row.key}</span>\n <span className=\"min-w-0 break-words text-right text-sm font-medium text-text-primary\">\n {row.value}\n </span>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport function CmdbBrowserPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [editSeed, setEditSeed] = useState<ConfigurationItem | null>(null);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobileDetailOpen, setMobileDetailOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<string>('ALL');\n const [envFilter, setEnvFilter] = useState<string>('ALL');\n const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});\n const isLarge = useIsLargeScreen();\n\n const { data, loading, refetch } = useQuery<{ configurationItems: ConfigurationItem[] }>(\n CONFIGURATION_ITEMS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const cis = useMemo(() => data?.configurationItems ?? [], [data?.configurationItems]);\n\n const filtered = useMemo(() => {\n const term = search.trim().toLowerCase();\n return cis.filter((ci) => {\n if (statusFilter !== 'ALL' && ci.status !== statusFilter) return false;\n if (envFilter !== 'ALL' && ci.environment !== envFilter) return false;\n if (!term) return true;\n return [ci.ciNumber, ci.name, ci.ciType, ci.owner ?? '']\n .join(' ')\n .toLowerCase()\n .includes(term);\n });\n }, [cis, search, statusFilter, envFilter]);\n\n const grouped = useMemo(() => {\n const map = new Map<string, ConfigurationItem[]>();\n for (const ci of filtered) {\n const key = ci.ciType || 'OTHER';\n const bucket = map.get(key);\n if (bucket) bucket.push(ci);\n else map.set(key, [ci]);\n }\n return [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]));\n }, [filtered]);\n\n const stats = useMemo(() => {\n const total = cis.length;\n const operational = cis.filter((c) => c.status === 'ACTIVE').length;\n const maintenance = cis.filter((c) => c.status === 'MAINTENANCE').length;\n const retired = cis.filter((c) => c.status === 'RETIRED').length;\n return {\n total,\n operationalPct: total > 0 ? Math.round((operational / total) * 100) : 0,\n maintenance,\n retired,\n };\n }, [cis]);\n\n const statusMix = useMemo<DonutSlice[]>(() => {\n const counts = cis.reduce<Record<string, number>>((acc, c) => {\n acc[c.status] = (acc[c.status] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([status, value], i) => ({\n name: STATUS_META[status]?.label ?? status,\n value,\n color: seriesColor(i),\n }));\n }, [cis]);\n\n const typeBars = useMemo(() => {\n const counts = cis.reduce<Record<string, number>>((acc, c) => {\n acc[c.ciType] = (acc[c.ciType] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts)\n .sort((a, b) => b[1] - a[1])\n .map(([type, count]) => ({ name: type, count }));\n }, [cis]);\n\n const selected = useMemo(() => cis.find((c) => c.id === selectedId) ?? null, [cis, selectedId]);\n\n const handleSelect = (ci: ConfigurationItem) => {\n setSelectedId(ci.id);\n if (!isLarge) setMobileDetailOpen(true);\n };\n\n const openCreate = () => {\n setEditSeed(null);\n setDialogOpen(true);\n };\n\n const openEdit = (ci: ConfigurationItem) => {\n setEditSeed(ci);\n setDialogOpen(true);\n setMobileDetailOpen(false);\n };\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex min-w-0 items-start gap-2.5\">\n <Network className=\"mt-1 h-6 w-6 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0\">\n <GradientText as=\"h1\" className=\"text-2xl font-bold sm:text-3xl\">\n CMDB — Configuration Items\n </GradientText>\n <p className=\"mt-1 max-w-2xl text-sm text-text-secondary\">\n A living map of every configuration item and its attributes.\n </p>\n </div>\n </div>\n <Button className=\"w-full sm:w-auto\" onClick={openCreate}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Add CI\n </Button>\n </div>\n <PagePurpose>\n Your configuration management database (CMDB): servers, services, network gear and how they\n relate. Browse, search and inspect each configuration item to understand blast radius before\n a change and keep asset relationships accurate.\n </PagePurpose>\n\n <UpsertConfigurationItemDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n seed={editSeed}\n onSaved={() => void refetch()}\n />\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile label=\"Total CIs\" value={stats.total} icon={Network} />\n <StatTile\n label=\"Operational\"\n value={stats.operationalPct}\n format={(n) => `${n}%`}\n icon={Server}\n deltaTone=\"positive\"\n />\n <StatTile label=\"In Maintenance\" value={stats.maintenance} icon={Cog} deltaTone=\"neutral\" />\n <StatTile label=\"Retired\" value={stats.retired} icon={HardDrive} deltaTone=\"neutral\" />\n </div>\n\n {cis.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Status mix\" subtitle=\"Configuration items by status\">\n <DonutChart\n data={statusMix}\n height={220}\n centerLabel=\"CIs\"\n centerValue={stats.total}\n ariaLabel=\"Configuration items by status\"\n />\n </ChartCard>\n <ChartCard title=\"By type\" subtitle=\"Configuration items per type\">\n <BarsChart\n data={typeBars}\n xKey=\"name\"\n series={[{ key: 'count', label: 'Items' }]}\n orientation=\"horizontal\"\n height={220}\n categoryWidth={110}\n ariaLabel=\"Configuration items per type\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"grid gap-4 lg:grid-cols-[1fr_360px]\">\n {/* Navigator */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"space-y-3 p-4\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n className=\"pl-9\"\n placeholder=\"Search CIs by number, name, type or owner…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label=\"Search configuration items\"\n />\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {CI_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={envFilter} onValueChange={setEnvFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Environment\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All environments</SelectItem>\n {CI_ENVIRONMENTS.map((e) => (\n <SelectItem key={e} value={e}>\n {e}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"border-t border-border-seam\">\n {loading && cis.length === 0 ? (\n <div className=\"space-y-2 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div\n key={i}\n className=\"h-9 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : null}\n {!loading && filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'empty-search'\n : 'empty-data'\n }\n title={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'No configuration items match'\n : 'No configuration items found'\n }\n description={\n search || statusFilter !== 'ALL' || envFilter !== 'ALL'\n ? 'Try a different search or filter.'\n : 'Add a configuration item to start mapping your estate.'\n }\n />\n ) : null}\n <div className=\"max-h-[540px] overflow-y-auto\">\n {grouped.map(([type, items]) => {\n const TypeIcon = TYPE_ICON[type] ?? Cog;\n const isCollapsed = collapsed[type];\n return (\n <div key={type}>\n <button\n type=\"button\"\n onClick={() => setCollapsed((c) => ({ ...c, [type]: !c[type] }))}\n className=\"flex w-full items-center gap-2 border-b border-border-seam/60 bg-bg-sunken/30 px-4 py-2 text-left text-sm font-semibold text-text-primary\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"h-4 w-4 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 text-text-secondary\" />\n )}\n <TypeIcon className=\"h-4 w-4 text-primary\" />\n <span className=\"capitalize\">{type.toLowerCase()}</span>\n <span className=\"ml-auto rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary tabular-nums\">\n {items.length}\n </span>\n </button>\n {!isCollapsed\n ? items.map((ci) => (\n <button\n key={ci.id}\n type=\"button\"\n onClick={() => handleSelect(ci)}\n aria-current={selectedId === ci.id}\n className={cn(\n 'flex w-full items-center gap-3 border-b border-border-seam/40 px-4 py-2.5 pl-10 text-left last:border-b-0',\n selectedId === ci.id\n ? 'bg-action-primary-bg/10'\n : 'hover:bg-bg-sunken/40'\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {ci.name}\n </p>\n <p className=\"truncate font-mono text-xs text-text-secondary\">\n {ci.ciNumber}\n {ci.environment ? ` · ${ci.environment}` : ''}\n </p>\n </div>\n <StatusPill status={ci.status} />\n </button>\n ))\n : null}\n </div>\n );\n })}\n </div>\n </div>\n </GlassCard>\n\n {/* Detail rail (desktop) */}\n <div className=\"hidden lg:block\">\n <GlassCard treatment=\"glass\" className=\"sticky top-4 border-border-seam\">\n <div className=\"p-4\">\n {selected ? (\n <CiDetail ci={selected} onEdit={() => openEdit(selected)} />\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-2 py-12 text-center\">\n <Network className=\"h-8 w-8 text-text-muted\" />\n <p className=\"text-sm font-medium text-text-primary\">\n Select a configuration item\n </p>\n <p className=\"text-xs text-text-secondary\">\n Choose a CI from the navigator to inspect its attributes.\n </p>\n </div>\n )}\n </div>\n </GlassCard>\n </div>\n </div>\n\n {/* Detail sheet (mobile) */}\n <ResponsiveDialog open={mobileDetailOpen && !isLarge} onOpenChange={setMobileDetailOpen}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Configuration item</ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n {selected ? <CiDetail ci={selected} onEdit={() => openEdit(selected)} /> : null}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|