@burdenoff/microfe-assethandler 2026.703.1 → 2026.703.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
  2. package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
  3. package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
  4. package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
  5. package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
  6. package/dist/assethandler/pages/DigitalTwinPage.js.map +1 -1
  7. package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
  8. package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -1
  9. package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
  10. package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
  11. package/dist/assethandler/pages/ItilChangeManagementPage.js.map +1 -1
  12. package/dist/assethandler/pages/ItilIncidentManagementPage.js.map +1 -1
  13. package/dist/assethandler/pages/ItilItilhubPage.js +1 -2
  14. package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
  15. package/dist/assethandler/pages/ItilProblemManagementPage.js.map +1 -1
  16. package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
  17. package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js.map +1 -1
  18. package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js.map +1 -1
  19. package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
  20. package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
  21. package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
  22. package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
  23. package/dist/assethandler/pages/ProvenancePage.js.map +1 -1
  24. package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
  25. package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
  26. package/dist/assethandler/store/assethandlerStore.js.map +1 -1
  27. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MaintenanceMaintenanceSchedulerPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceSchedulerPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nexport function MaintenanceMaintenanceSchedulerPage() {\n const { maintenanceRecords } = useAssetHandlerStore();\n const scheduled = maintenanceRecords.filter((m) => m.status === 'scheduled');\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Maintenance Scheduler</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Schedule and manage maintenance tasks</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n </div>\n\n <PagePurpose>\n Plan maintenance before things break. Schedule jobs against an asset (each with its own\n checklist and cost estimate), then track the upcoming work here — turning reactive\n firefighting into predictable preventive upkeep.\n </PagePurpose>\n\n {/* Scheduled Tasks */}\n <Card>\n <CardHeader>\n <CardTitle>Scheduled Maintenance ({scheduled.length})</CardTitle>\n </CardHeader>\n <CardContent>\n {scheduled.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing scheduled\"\n description=\"Schedule maintenance from a template or for a specific asset to see it here.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {scheduled.map((rec) => (\n <div key={rec.id} className=\"rounded-lg border p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"font-mono text-xs text-text-secondary\">{rec.id}</span>\n <Badge variant=\"outline\">{rec.type}</Badge>\n </div>\n <p className=\"font-medium mt-1\">{rec.title}</p>\n <p className=\"text-sm text-text-secondary\">{rec.assetId}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-medium\">\n {rec.scheduledDate\n ? new Date(rec.scheduledDate).toLocaleDateString()\n : 'Not scheduled'}\n </p>\n {rec.estimatedCost != null && (\n <p className=\"text-xs text-text-secondary\">\n Est. ${rec.estimatedCost.toLocaleString()}\n </p>\n )}\n </div>\n </div>\n <Separator className=\"my-3\" />\n <div>\n <p className=\"text-xs font-medium text-text-secondary mb-2\">\n Checklist ({rec.checklist.filter((c) => c.completed).length}/\n {rec.checklist.length})\n </p>\n <div className=\"space-y-1\">\n {rec.checklist.map((item, i) => (\n <div key={i} className=\"flex items-center gap-2 text-xs\">\n <div\n className={`h-3 w-3 rounded border ${item.completed ? 'bg-action-primary-bg border-primary' : 'border-muted-foreground'}`}\n />\n <span className={item.completed ? 'line-through text-text-secondary' : ''}>\n {item.task}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;AAeA,SAAgB,IAAsC;CACpD,IAAM,EAAE,0BAAuB,GAAsB,EAC/C,IAAY,EAAmB,QAAQ,MAAM,EAAE,WAAW,YAAY;AAE5E,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,yBAAoC,CAAA;KAC/C,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAAyC,CAAA,CAChF,EAAA,CAAA,EACN,kBAAC,GAAD;KAAQ,MAAK;eAAb,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,eAE1B;OACL;;GAEN,kBAAC,GAAD,EAAA,UAAa,+NAIC,CAAA;GAGd,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;IAAW;IAAwB,EAAU;IAAO;IAAa,EAAA,CAAA,EACtD,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,EAAU,WAAW,IACpB,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,CAAA,GAEJ,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAU,KAAK,MACd,kBAAC,OAAD;KAAkB,WAAU;eAA5B;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAyC,EAAI;UAAU,CAAA,EACvE,kBAAC,GAAD;UAAO,SAAQ;oBAAW,EAAI;UAAa,CAAA,CACvC;;QACN,kBAAC,KAAD;SAAG,WAAU;mBAAoB,EAAI;SAAU,CAAA;QAC/C,kBAAC,KAAD;SAAG,WAAU;mBAA+B,EAAI;SAAY,CAAA;QACxD,EAAA,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAI,gBACD,IAAI,KAAK,EAAI,cAAc,CAAC,oBAAoB,GAChD;SACF,CAAA,EACH,EAAI,iBAAiB,QACpB,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAA2C,UAClC,EAAI,cAAc,gBAAgB,CACvC;WAEF;UACF;;MACN,kBAAC,GAAD,EAAW,WAAU,QAAS,CAAA;MAC9B,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAA4D;QAC9C,EAAI,UAAU,QAAQ,MAAM,EAAE,UAAU,CAAC;QAAO;QAC3D,EAAI,UAAU;QAAO;QACpB;UACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAI,UAAU,KAAK,GAAM,MACxB,kBAAC,OAAD;QAAa,WAAU;kBAAvB,CACE,kBAAC,OAAD,EACE,WAAW,0BAA0B,EAAK,YAAY,wCAAwC,6BAC9F,CAAA,EACF,kBAAC,QAAD;SAAM,WAAW,EAAK,YAAY,qCAAqC;mBACpE,EAAK;SACD,CAAA,CACH;UAPI,EAOJ,CACN;OACE,CAAA,CACF,EAAA,CAAA;MACF;OA1CI,EAAI,GA0CR,CACN;IACE,CAAA,EAEM,CAAA,CACT,EAAA,CAAA;GACH"}
1
+ {"version":3,"file":"MaintenanceMaintenanceSchedulerPage.js","names":[],"sources":["../../../src/assethandler/pages/MaintenanceMaintenanceSchedulerPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Plus } from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nexport function MaintenanceMaintenanceSchedulerPage() {\n const { maintenanceRecords } = useAssetHandlerStore();\n const scheduled = maintenanceRecords.filter((m) => m.status === 'scheduled');\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Maintenance Scheduler</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Schedule and manage maintenance tasks</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n Schedule New\n </Button>\n </div>\n\n <PagePurpose>\n Plan maintenance before things break. Schedule jobs against an asset (each with its own\n checklist and cost estimate), then track the upcoming work here — turning reactive\n firefighting into predictable preventive upkeep.\n </PagePurpose>\n\n {/* Scheduled Tasks */}\n <Card>\n <CardHeader>\n <CardTitle>Scheduled Maintenance ({scheduled.length})</CardTitle>\n </CardHeader>\n <CardContent>\n {scheduled.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Nothing scheduled\"\n description=\"Schedule maintenance from a template or for a specific asset to see it here.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {scheduled.map((rec) => (\n <div key={rec.id} className=\"rounded-lg border p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"flex items-center gap-2\">\n <span className=\"font-mono text-xs text-text-secondary\">{rec.id}</span>\n <Badge variant=\"outline\">{rec.type}</Badge>\n </div>\n <p className=\"font-medium mt-1\">{rec.title}</p>\n <p className=\"text-sm text-text-secondary\">{rec.assetId}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm font-medium\">\n {rec.scheduledDate\n ? new Date(rec.scheduledDate).toLocaleDateString()\n : 'Not scheduled'}\n </p>\n {rec.estimatedCost != null && (\n <p className=\"text-xs text-text-secondary\">\n Est. ${rec.estimatedCost.toLocaleString()}\n </p>\n )}\n </div>\n </div>\n <Separator className=\"my-3\" />\n <div>\n <p className=\"text-xs font-medium text-text-secondary mb-2\">\n Checklist ({rec.checklist.filter((c) => c.completed).length}/\n {rec.checklist.length})\n </p>\n <div className=\"space-y-1\">\n {rec.checklist.map((item, i) => (\n <div key={i} className=\"flex items-center gap-2 text-xs\">\n <div\n className={`h-3 w-3 rounded border ${item.completed ? 'bg-action-primary-bg border-primary' : 'border-muted-foreground'}`}\n />\n <span\n className={item.completed ? 'line-through text-text-secondary' : ''}\n >\n {item.task}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;AAeA,SAAgB,IAAsC;CACpD,IAAM,EAAE,0BAAuB,GAAsB,EAC/C,IAAY,EAAmB,QAAQ,MAAM,EAAE,WAAW,YAAY;AAE5E,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,yBAAoC,CAAA;KAC/C,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAAyC,CAAA,CAChF,EAAA,CAAA,EACN,kBAAC,GAAD;KAAQ,MAAK;eAAb,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,eAE1B;OACL;;GAEN,kBAAC,GAAD,EAAA,UAAa,+NAIC,CAAA;GAGd,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;IAAW;IAAwB,EAAU;IAAO;IAAa,EAAA,CAAA,EACtD,CAAA,EACb,kBAAC,GAAD,EAAA,UACG,EAAU,WAAW,IACpB,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAU,KAAK,MACd,kBAAC,OAAD;KAAkB,WAAU;eAA5B;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAyC,EAAI;UAAU,CAAA,EACvE,kBAAC,GAAD;UAAO,SAAQ;oBAAW,EAAI;UAAa,CAAA,CACvC;;QACN,kBAAC,KAAD;SAAG,WAAU;mBAAoB,EAAI;SAAU,CAAA;QAC/C,kBAAC,KAAD;SAAG,WAAU;mBAA+B,EAAI;SAAY,CAAA;QACxD,EAAA,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAI,gBACD,IAAI,KAAK,EAAI,cAAc,CAAC,oBAAoB,GAChD;SACF,CAAA,EACH,EAAI,iBAAiB,QACpB,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAA2C,UAClC,EAAI,cAAc,gBAAgB,CACvC;WAEF;UACF;;MACN,kBAAC,GAAD,EAAW,WAAU,QAAS,CAAA;MAC9B,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAA4D;QAC9C,EAAI,UAAU,QAAQ,MAAM,EAAE,UAAU,CAAC;QAAO;QAC3D,EAAI,UAAU;QAAO;QACpB;UACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAI,UAAU,KAAK,GAAM,MACxB,kBAAC,OAAD;QAAa,WAAU;kBAAvB,CACE,kBAAC,OAAD,EACE,WAAW,0BAA0B,EAAK,YAAY,wCAAwC,6BAC9F,CAAA,EACF,kBAAC,QAAD;SACE,WAAW,EAAK,YAAY,qCAAqC;mBAEhE,EAAK;SACD,CAAA,CACH;UATI,EASJ,CACN;OACE,CAAA,CACF,EAAA,CAAA;MACF;OA5CI,EAAI,GA4CR,CACN;IACE,CAAA,EAEI,CAAA,CACT,EAAA,CAAA;GACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"OperationsMaintenanceDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsMaintenanceDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle } from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nexport function OperationsMaintenanceDetailPage() {\n const navigate = useNavigate();\n const { maintenanceId } = useParams<{ maintenanceId: string }>();\n const { maintenanceRecords } = useAssetHandlerStore();\n const record =\n maintenanceRecords.find((item) => item.id === maintenanceId) ?? maintenanceRecords[0];\n\n if (!record)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Maintenance record not found\"\n description=\"This record may have been completed or removed. Return to the operations hub to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/operations/operations-hub')}>\n Back to operations\n </Button>\n }\n />\n </div>\n );\n\n const completedTasks = record.checklist.filter((c) => c.completed).length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigate('/operations/operations-hub')}>\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{record.id}</GradientText>\n </h1>\n <Badge variant=\"outline\">{record.type}</Badge>\n <Badge variant={record.status === 'completed' ? 'default' : 'secondary'}>\n {record.status.replace('_', ' ')}\n </Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{record.title}</p>\n </div>\n </div>\n <Button size=\"sm\">\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Complete\n </Button>\n </div>\n\n <PagePurpose>\n Everything needed to carry out and sign off a single maintenance job: the asset, the\n schedule, the step-by-step checklist and live progress. Work through the checklist, log\n notes and mark it complete so the asset&apos;s service history stays accurate.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-maintenance-detail\"\n steps={[\n {\n id: 'complete',\n label: 'Work through the checklist',\n description: 'Tick off each task, then mark the job complete.',\n done: record.status === 'completed',\n },\n {\n id: 'asset',\n label: 'Open the related asset',\n description: 'Review the asset this maintenance is for.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'calendar',\n label: 'View the maintenance calendar',\n description: 'See how this fits with other scheduled work.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{record.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Asset</span>\n <p className=\"font-medium\">{record.assetId}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Type</span>\n <p className=\"font-medium capitalize\">{record.type}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Scheduled</span>\n <p className=\"font-medium\">\n {record.scheduledDate\n ? new Date(record.scheduledDate).toLocaleDateString()\n : 'Not scheduled'}\n </p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Completed</span>\n <p className=\"font-medium\">\n {record.completedDate\n ? new Date(record.completedDate).toLocaleDateString()\n : '—'}\n </p>\n </div>\n {record.estimatedCost != null && (\n <div>\n <span className=\"text-text-secondary\">Estimated Cost</span>\n <p className=\"font-medium\">${record.estimatedCost.toLocaleString()}</p>\n </div>\n )}\n {record.actualCost != null && (\n <div>\n <span className=\"text-text-secondary\">Actual Cost</span>\n <p className=\"font-medium\">${record.actualCost.toLocaleString()}</p>\n </div>\n )}\n </div>\n <Separator />\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary mb-3\">\n Checklist ({completedTasks}/{record.checklist.length})\n </h4>\n <div className=\"space-y-2\">\n {record.checklist.map((item, i) => (\n <div key={i} className=\"flex items-center gap-3 rounded border p-2.5\">\n <div\n className={`h-4 w-4 rounded border-2 flex items-center justify-center ${item.completed ? 'bg-action-primary-bg border-primary' : 'border-muted-foreground'}`}\n >\n {item.completed && (\n <CheckCircle className=\"h-3 w-3 text-action-primary-text\" />\n )}\n </div>\n <span\n className={`text-sm ${item.completed ? 'line-through text-text-secondary' : ''}`}\n >\n {item.task}\n </span>\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Progress</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"text-center mb-4\">\n <p className=\"text-4xl font-bold\">\n {Math.round((completedTasks / record.checklist.length) * 100)}%\n </p>\n <p className=\"text-sm text-text-secondary\">Complete</p>\n </div>\n <div className=\"h-3 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-all\"\n style={{ width: `${(completedTasks / record.checklist.length) * 100}%` }}\n />\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,IAAkC;CAChD,IAAM,IAAW,GAAa,EACxB,EAAE,qBAAkB,GAAsC,EAC1D,EAAE,0BAAuB,GAAsB,EAC/C,IACJ,EAAmB,MAAM,MAAS,EAAK,OAAO,EAAc,IAAI,EAAmB;AAErF,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,GAAD;IAAQ,MAAK;IAAK,eAAe,EAAS,6BAA6B;cAAE;IAEhE,CAAA;GAEX,CAAA;EACE,CAAA;CAGV,IAAM,IAAiB,EAAO,UAAU,QAAQ,MAAM,EAAE,UAAU,CAAC;AAEnE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAQ,MAAK;MAAO,eAAe,EAAS,6BAA6B;gBACvF,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MAC1B,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBACZ,kBAAC,GAAD,EAAA,UAAe,EAAO,IAAkB,CAAA;QACrC,CAAA;OACL,kBAAC,GAAD;QAAO,SAAQ;kBAAW,EAAO;QAAa,CAAA;OAC9C,kBAAC,GAAD;QAAO,SAAS,EAAO,WAAW,cAAc,YAAY;kBACzD,EAAO,OAAO,QAAQ,KAAK,IAAI;QAC1B,CAAA;OACJ;SACN,kBAAC,KAAD;MAAG,WAAU;gBAAoC,EAAO;MAAU,CAAA,CAC9D,EAAA,CAAA,CACF;QACN,kBAAC,GAAD;KAAQ,MAAK;eAAb,CACE,kBAAC,GAAD,EAAa,WAAU,gBAAiB,CAAA,EAAA,WAEjC;OACL;;GAEN,kBAAC,GAAD,EAAA,UAAa,0PAIC,CAAA;GAEd,kBAAC,GAAD;IACE,YAAW;IACX,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,EAAO,WAAW;MACzB;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,qBAAqB;MAC9C;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,oCAAoC;MAC7D;KACF;IACD,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAe,WAAU;eAAzB,CACE,kBAAC,GAAD;MAAY,WAAU;gBACpB,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA;MACnB,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAA0C;QAAgB,CAAA,EACxE,kBAAC,KAAD;QAAG,WAAU;kBAAgB,EAAO;QAAgB,CAAA,CAChD,EAAA,CAAA;OACN,kBAAC,GAAD,EAAa,CAAA;OACb,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAY,CAAA,EAClD,kBAAC,KAAD;UAAG,WAAU;oBAAe,EAAO;UAAY,CAAA,CAC3C,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAW,CAAA,EACjD,kBAAC,KAAD;UAAG,WAAU;oBAA0B,EAAO;UAAS,CAAA,CACnD,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAgB,CAAA,EACtD,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAO,gBACJ,IAAI,KAAK,EAAO,cAAc,CAAC,oBAAoB,GACnD;UACF,CAAA,CACA,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAgB,CAAA,EACtD,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAO,gBACJ,IAAI,KAAK,EAAO,cAAc,CAAC,oBAAoB,GACnD;UACF,CAAA,CACA,EAAA,CAAA;SACL,EAAO,iBAAiB,QACvB,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAqB,CAAA,EAC3D,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAA2B,KAAE,EAAO,cAAc,gBAAgB,CAAK;YACnE,EAAA,CAAA;SAEP,EAAO,cAAc,QACpB,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAkB,CAAA,EACxD,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAA2B,KAAE,EAAO,WAAW,gBAAgB,CAAK;YAChE,EAAA,CAAA;SAEJ;;OACN,kBAAC,GAAD,EAAa,CAAA;OACb,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAd;SAA6D;SAC/C;SAAe;SAAE,EAAO,UAAU;SAAO;SAClD;WACL,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAO,UAAU,KAAK,GAAM,MAC3B,kBAAC,OAAD;SAAa,WAAU;mBAAvB,CACE,kBAAC,OAAD;UACE,WAAW,6DAA6D,EAAK,YAAY,wCAAwC;oBAEhI,EAAK,aACJ,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;UAE1D,CAAA,EACN,kBAAC,QAAD;UACE,WAAW,WAAW,EAAK,YAAY,qCAAqC;oBAE3E,EAAK;UACD,CAAA,CACH;WAbI,EAaJ,CACN;QACE,CAAA,CACF,EAAA,CAAA;OACM;QACA;QAEhB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAW,WAAU;eAAY;KAAoB,CAAA,EAC1C,CAAA,EACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACG,KAAK,MAAO,IAAiB,EAAO,UAAU,SAAU,IAAI,EAAC,IAC5D;SACJ,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAY,CAAA,CACnD;QACN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,OAAO,GAAI,IAAiB,EAAO,UAAU,SAAU,IAAI,IAAI;MACxE,CAAA;KACE,CAAA,CACM,EAAA,CAAA,CACT,EAAA,CAAA,CACH;;GACF"}
1
+ {"version":3,"file":"OperationsMaintenanceDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsMaintenanceDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle } from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nexport function OperationsMaintenanceDetailPage() {\n const navigate = useNavigate();\n const { maintenanceId } = useParams<{ maintenanceId: string }>();\n const { maintenanceRecords } = useAssetHandlerStore();\n const record =\n maintenanceRecords.find((item) => item.id === maintenanceId) ?? maintenanceRecords[0];\n\n if (!record)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Maintenance record not found\"\n description=\"This record may have been completed or removed. Return to the operations hub to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/operations/operations-hub')}>\n Back to operations\n </Button>\n }\n />\n </div>\n );\n\n const completedTasks = record.checklist.filter((c) => c.completed).length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigate('/operations/operations-hub')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{record.id}</GradientText>\n </h1>\n <Badge variant=\"outline\">{record.type}</Badge>\n <Badge variant={record.status === 'completed' ? 'default' : 'secondary'}>\n {record.status.replace('_', ' ')}\n </Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{record.title}</p>\n </div>\n </div>\n <Button size=\"sm\">\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Complete\n </Button>\n </div>\n\n <PagePurpose>\n Everything needed to carry out and sign off a single maintenance job: the asset, the\n schedule, the step-by-step checklist and live progress. Work through the checklist, log\n notes and mark it complete so the asset&apos;s service history stays accurate.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-maintenance-detail\"\n steps={[\n {\n id: 'complete',\n label: 'Work through the checklist',\n description: 'Tick off each task, then mark the job complete.',\n done: record.status === 'completed',\n },\n {\n id: 'asset',\n label: 'Open the related asset',\n description: 'Review the asset this maintenance is for.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'calendar',\n label: 'View the maintenance calendar',\n description: 'See how this fits with other scheduled work.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{record.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Asset</span>\n <p className=\"font-medium\">{record.assetId}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Type</span>\n <p className=\"font-medium capitalize\">{record.type}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Scheduled</span>\n <p className=\"font-medium\">\n {record.scheduledDate\n ? new Date(record.scheduledDate).toLocaleDateString()\n : 'Not scheduled'}\n </p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Completed</span>\n <p className=\"font-medium\">\n {record.completedDate ? new Date(record.completedDate).toLocaleDateString() : '—'}\n </p>\n </div>\n {record.estimatedCost != null && (\n <div>\n <span className=\"text-text-secondary\">Estimated Cost</span>\n <p className=\"font-medium\">${record.estimatedCost.toLocaleString()}</p>\n </div>\n )}\n {record.actualCost != null && (\n <div>\n <span className=\"text-text-secondary\">Actual Cost</span>\n <p className=\"font-medium\">${record.actualCost.toLocaleString()}</p>\n </div>\n )}\n </div>\n <Separator />\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary mb-3\">\n Checklist ({completedTasks}/{record.checklist.length})\n </h4>\n <div className=\"space-y-2\">\n {record.checklist.map((item, i) => (\n <div key={i} className=\"flex items-center gap-3 rounded border p-2.5\">\n <div\n className={`h-4 w-4 rounded border-2 flex items-center justify-center ${item.completed ? 'bg-action-primary-bg border-primary' : 'border-muted-foreground'}`}\n >\n {item.completed && (\n <CheckCircle className=\"h-3 w-3 text-action-primary-text\" />\n )}\n </div>\n <span\n className={`text-sm ${item.completed ? 'line-through text-text-secondary' : ''}`}\n >\n {item.task}\n </span>\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Progress</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"text-center mb-4\">\n <p className=\"text-4xl font-bold\">\n {Math.round((completedTasks / record.checklist.length) * 100)}%\n </p>\n <p className=\"text-sm text-text-secondary\">Complete</p>\n </div>\n <div className=\"h-3 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-all\"\n style={{ width: `${(completedTasks / record.checklist.length) * 100}%` }}\n />\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OperationsOperationsHubPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsOperationsHubPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Wrench, ClipboardList, AlertTriangle, Plus } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst priorityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nexport function OperationsOperationsHubPage() {\n const navigate = useNavigate();\n const { workOrders, maintenanceRecords } = useAssetHandlerStore();\n\n const openWorkOrders = workOrders.filter(\n (w) => w.status !== 'completed' && w.status !== 'cancelled'\n );\n const scheduledMaintenance = maintenanceRecords.filter(\n (m) => m.status === 'scheduled' || m.status === 'in_progress'\n );\n const maintenanceCost = maintenanceRecords.reduce(\n (s, m) => s + (m.actualCost ?? m.estimatedCost ?? 0),\n 0\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Operations Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Work orders and maintenance operations</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n New Work Order\n </Button>\n </div>\n\n <PagePurpose>\n Where the hands-on work gets coordinated: raise and assign work orders, run scheduled and\n breakdown maintenance, and keep an eye on cost. Use this hub to see what is open, what is\n critical, and what is due — so your team always knows what to fix next.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-operations-hub\"\n steps={[\n {\n id: 'scheduler',\n label: 'Plan preventive maintenance',\n description: 'Schedule upcoming maintenance before assets fail.',\n onClick: () => navigate('/maintenance/maintenance-scheduler'),\n },\n {\n id: 'calendar',\n label: 'View the maintenance calendar',\n description: 'Spot clashes and overdue jobs at a glance.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n {\n id: 'assets',\n label: 'Open the asset inventory',\n description: 'Jump to an asset to log a work order against it.',\n onClick: () => navigate('/assets/asset-list'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <ClipboardList className=\"h-4 w-4\" />\n Open Work Orders\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums\">{openWorkOrders.length}</p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Wrench className=\"h-4 w-4\" />\n Active Maintenance\n </div>\n <p className=\"text-2xl font-bold mt-1\">{scheduledMaintenance.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <AlertTriangle className=\"h-4 w-4\" />\n Critical\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-error-text\">\n {workOrders.filter((w) => w.priority === 'critical').length}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n Maintenance Cost\n </div>\n <p className=\"text-2xl font-bold mt-1\">${maintenanceCost.toLocaleString()}</p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"work-orders\">\n <TabsList>\n <TabsTrigger value=\"work-orders\">Work Orders ({workOrders.length})</TabsTrigger>\n <TabsTrigger value=\"maintenance\">Maintenance ({maintenanceRecords.length})</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"work-orders\" className=\"mt-4\">\n {workOrders.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No work orders\"\n description=\"Raise a work order when an asset needs repair, inspection or attention.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Asset</th>\n <th className=\"text-left p-3 font-medium\">Priority</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Assigned To</th>\n </tr>\n </thead>\n <tbody>\n {workOrders.map((wo) => (\n <tr key={wo.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{wo.id}</td>\n <td className=\"p-3\">\n <p className=\"font-medium\">{wo.title}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {wo.description}\n </p>\n </td>\n <td className=\"p-3 text-xs\">{wo.assetId || '—'}</td>\n <td className=\"p-3\">\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{wo.assignedTo}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"maintenance\" className=\"mt-4\">\n {maintenanceRecords.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No maintenance scheduled\"\n description=\"Scheduled and completed maintenance for your assets will appear here.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Asset</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Priority</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n <th className=\"text-right p-3 font-medium\">Cost</th>\n </tr>\n </thead>\n <tbody>\n {maintenanceRecords.map((m) => (\n <tr key={m.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{m.id}</td>\n <td className=\"p-3 font-medium\">{m.title}</td>\n <td className=\"p-3 text-xs\">{m.assetId}</td>\n <td className=\"p-3 capitalize text-xs\">{m.type}</td>\n <td className=\"p-3\">\n <Badge variant={priorityColors[m.priority]}>{m.priority}</Badge>\n </td>\n <td className=\"p-3\">\n <Badge variant={m.status === 'completed' ? 'default' : 'outline'}>\n {m.status.replace('_', ' ')}\n </Badge>\n </td>\n <td className=\"p-3 text-xs\">\n {m.scheduledDate ? new Date(m.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3 text-right font-medium\">\n ${(m.actualCost ?? m.estimatedCost ?? 0).toLocaleString()}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OperationsOperationsHubPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsOperationsHubPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Wrench, ClipboardList, AlertTriangle, Plus } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst priorityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nexport function OperationsOperationsHubPage() {\n const navigate = useNavigate();\n const { workOrders, maintenanceRecords } = useAssetHandlerStore();\n\n const openWorkOrders = workOrders.filter(\n (w) => w.status !== 'completed' && w.status !== 'cancelled'\n );\n const scheduledMaintenance = maintenanceRecords.filter(\n (m) => m.status === 'scheduled' || m.status === 'in_progress'\n );\n const maintenanceCost = maintenanceRecords.reduce(\n (s, m) => s + (m.actualCost ?? m.estimatedCost ?? 0),\n 0\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Operations Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Work orders and maintenance operations</p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n New Work Order\n </Button>\n </div>\n\n <PagePurpose>\n Where the hands-on work gets coordinated: raise and assign work orders, run scheduled and\n breakdown maintenance, and keep an eye on cost. Use this hub to see what is open, what is\n critical, and what is due — so your team always knows what to fix next.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-operations-hub\"\n steps={[\n {\n id: 'scheduler',\n label: 'Plan preventive maintenance',\n description: 'Schedule upcoming maintenance before assets fail.',\n onClick: () => navigate('/maintenance/maintenance-scheduler'),\n },\n {\n id: 'calendar',\n label: 'View the maintenance calendar',\n description: 'Spot clashes and overdue jobs at a glance.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n {\n id: 'assets',\n label: 'Open the asset inventory',\n description: 'Jump to an asset to log a work order against it.',\n onClick: () => navigate('/assets/asset-list'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <ClipboardList className=\"h-4 w-4\" />\n Open Work Orders\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums\">{openWorkOrders.length}</p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Wrench className=\"h-4 w-4\" />\n Active Maintenance\n </div>\n <p className=\"text-2xl font-bold mt-1\">{scheduledMaintenance.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <AlertTriangle className=\"h-4 w-4\" />\n Critical\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-error-text\">\n {workOrders.filter((w) => w.priority === 'critical').length}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n Maintenance Cost\n </div>\n <p className=\"text-2xl font-bold mt-1\">${maintenanceCost.toLocaleString()}</p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"work-orders\">\n <TabsList>\n <TabsTrigger value=\"work-orders\">Work Orders ({workOrders.length})</TabsTrigger>\n <TabsTrigger value=\"maintenance\">Maintenance ({maintenanceRecords.length})</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"work-orders\" className=\"mt-4\">\n {workOrders.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No work orders\"\n description=\"Raise a work order when an asset needs repair, inspection or attention.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Asset</th>\n <th className=\"text-left p-3 font-medium\">Priority</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Assigned To</th>\n </tr>\n </thead>\n <tbody>\n {workOrders.map((wo) => (\n <tr key={wo.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{wo.id}</td>\n <td className=\"p-3\">\n <p className=\"font-medium\">{wo.title}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {wo.description}\n </p>\n </td>\n <td className=\"p-3 text-xs\">{wo.assetId || '—'}</td>\n <td className=\"p-3\">\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{wo.assignedTo}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"maintenance\" className=\"mt-4\">\n {maintenanceRecords.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No maintenance scheduled\"\n description=\"Scheduled and completed maintenance for your assets will appear here.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Asset</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Priority</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n <th className=\"text-right p-3 font-medium\">Cost</th>\n </tr>\n </thead>\n <tbody>\n {maintenanceRecords.map((m) => (\n <tr key={m.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{m.id}</td>\n <td className=\"p-3 font-medium\">{m.title}</td>\n <td className=\"p-3 text-xs\">{m.assetId}</td>\n <td className=\"p-3 capitalize text-xs\">{m.type}</td>\n <td className=\"p-3\">\n <Badge variant={priorityColors[m.priority]}>{m.priority}</Badge>\n </td>\n <td className=\"p-3\">\n <Badge variant={m.status === 'completed' ? 'default' : 'outline'}>\n {m.status.replace('_', ' ')}\n </Badge>\n </td>\n <td className=\"p-3 text-xs\">\n {m.scheduledDate ? new Date(m.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3 text-right font-medium\">\n ${(m.actualCost ?? m.estimatedCost ?? 0).toLocaleString()}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OperationsWorkOrderDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsWorkOrderDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle } from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst priorityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nexport function OperationsWorkOrderDetailPage() {\n const navigate = useNavigate();\n const { workOrderId } = useParams<{ workOrderId: string }>();\n const { workOrders } = useAssetHandlerStore();\n const wo = workOrders.find((item) => item.id === workOrderId) ?? workOrders[0];\n\n if (!wo)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Work order not found\"\n description=\"This work order may have been completed or removed. Return to the operations hub to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/operations/operations-hub')}>\n Back to operations\n </Button>\n }\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigate('/operations/operations-hub')}>\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{wo.id}</GradientText>\n </h1>\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{wo.title}</p>\n </div>\n </div>\n <Button size=\"sm\">\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Complete\n </Button>\n </div>\n\n <PagePurpose>\n The full brief for a single work order: what needs doing, on which asset and by whom. Use\n this page to track the job from open to complete and keep the asset&apos;s maintenance\n history accurate.\n </PagePurpose>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Work Order Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{wo.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Asset</span>\n <p className=\"font-medium\">{wo.assetId || 'Unassigned'}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Type</span>\n <p className=\"font-medium\">{wo.type}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Created</span>\n <p className=\"font-medium\">\n {wo.createdAt ? new Date(wo.createdAt).toLocaleDateString() : '—'}\n </p>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Assignment</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Assigned To</dt>\n <dd className=\"text-xs font-medium\">{wo.assignedTo}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Priority</dt>\n <dd>\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OperationsWorkOrderDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/OperationsWorkOrderDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, CheckCircle } from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst priorityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n};\n\nexport function OperationsWorkOrderDetailPage() {\n const navigate = useNavigate();\n const { workOrderId } = useParams<{ workOrderId: string }>();\n const { workOrders } = useAssetHandlerStore();\n const wo = workOrders.find((item) => item.id === workOrderId) ?? workOrders[0];\n\n if (!wo)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Work order not found\"\n description=\"This work order may have been completed or removed. Return to the operations hub to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/operations/operations-hub')}>\n Back to operations\n </Button>\n }\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigate('/operations/operations-hub')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{wo.id}</GradientText>\n </h1>\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">{wo.title}</p>\n </div>\n </div>\n <Button size=\"sm\">\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n Complete\n </Button>\n </div>\n\n <PagePurpose>\n The full brief for a single work order: what needs doing, on which asset and by whom. Use\n this page to track the job from open to complete and keep the asset&apos;s maintenance\n history accurate.\n </PagePurpose>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Work Order Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div>\n <h4 className=\"text-sm font-medium text-text-secondary\">Description</h4>\n <p className=\"text-sm mt-1\">{wo.description}</p>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4 text-sm\">\n <div>\n <span className=\"text-text-secondary\">Asset</span>\n <p className=\"font-medium\">{wo.assetId || 'Unassigned'}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Type</span>\n <p className=\"font-medium\">{wo.type}</p>\n </div>\n <div>\n <span className=\"text-text-secondary\">Created</span>\n <p className=\"font-medium\">\n {wo.createdAt ? new Date(wo.createdAt).toLocaleDateString() : '—'}\n </p>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Assignment</CardTitle>\n </CardHeader>\n <CardContent>\n <dl className=\"space-y-3 text-sm\">\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Assigned To</dt>\n <dd className=\"text-xs font-medium\">{wo.assignedTo}</dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Priority</dt>\n <dd>\n <Badge variant={priorityColors[wo.priority]}>{wo.priority}</Badge>\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">Status</dt>\n <dd>\n <Badge variant=\"outline\">{wo.status.replace('_', ' ')}</Badge>\n </dd>\n </div>\n </dl>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PortfolioPortfolioOverviewPage.js","names":[],"sources":["../../../src/assethandler/pages/PortfolioPortfolioOverviewPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n GradientText,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Package, CheckCircle2, Wrench, MapPin } from 'lucide-react';\nimport { useAssetHandlerStore, type Asset } from '../store/assethandlerStore';\n\nfunction countBy(assets: Asset[], key: (a: Asset) => string): Array<[string, number]> {\n const map = assets.reduce<Record<string, number>>((acc, a) => {\n const k = key(a);\n acc[k] = (acc[k] || 0) + 1;\n return acc;\n }, {});\n return Object.entries(map).sort((a, b) => b[1] - a[1]);\n}\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' =>\n status === 'active' ? 'default' : status === 'disposed' ? 'destructive' : 'secondary';\n\nexport function PortfolioPortfolioOverviewPage() {\n const { assets } = useAssetHandlerStore();\n\n const byCategory = useMemo(() => countBy(assets, (a) => a.category.replace(/_/g, ' ')), [assets]);\n const byStatus = useMemo(() => countBy(assets, (a) => a.status), [assets]);\n const byCondition = useMemo(() => countBy(assets, (a) => a.condition), [assets]);\n const byLocation = useMemo(\n () => countBy(assets, (a) => a.location.trim() || 'Unlocated'),\n [assets]\n );\n\n const activeCount = byStatus.find(([s]) => s === 'active')?.[1] ?? 0;\n const maintenanceCount = byStatus.find(([s]) => s === 'maintenance')?.[1] ?? 0;\n const maxCategoryCount = Math.max(...byCategory.map(([, c]) => c), 1);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Portfolio Overview</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n A comprehensive view of your asset portfolio and how it is distributed.\n </p>\n </div>\n\n <PagePurpose>\n The big-picture view of everything you own: how many assets you have and how they break down\n by category, status, condition and location. Use it to inform replacement planning and\n audit.\n </PagePurpose>\n\n {assets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets in your portfolio yet\"\n description=\"Once you add assets, this overview will summarise them by category, status, condition and location.\"\n />\n ) : (\n <>\n <div className=\"grid gap-4 md:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Assets</CardTitle>\n <Package className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {assets.length.toLocaleString()}\n </div>\n <p className=\"text-xs text-text-secondary\">Across all categories</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active</CardTitle>\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeCount}</div>\n <p className=\"text-xs text-text-secondary\">\n {assets.length > 0 ? Math.round((activeCount / assets.length) * 100) : 0}% of estate\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">In Maintenance</CardTitle>\n <Wrench className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{maintenanceCount}</div>\n <p className=\"text-xs text-text-secondary\">Currently being serviced</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Locations</CardTitle>\n <MapPin className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {byLocation.filter(([l]) => l !== 'Unlocated').length}\n </div>\n <p className=\"text-xs text-text-secondary\">Distinct asset locations</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Assets by Category</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {byCategory.map(([category, count]) => (\n <div key={category} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium capitalize\">{category}</span>\n <span className=\"text-text-secondary\">{count} assets</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${Math.round((count / maxCategoryCount) * 100)}%` }}\n />\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Location</CardTitle>\n </CardHeader>\n <CardContent>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Location</TableHead>\n <TableHead className=\"text-right\">Count</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {byLocation.map(([location, count]) => (\n <TableRow key={location}>\n <TableCell className=\"font-medium\">{location}</TableCell>\n <TableCell className=\"text-right\">{count}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Status</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex flex-wrap gap-3\">\n {byStatus.map(([status, count]) => (\n <div key={status} className=\"flex items-center gap-2 rounded-lg border p-3\">\n <Badge variant={statusVariant(status)} className=\"capitalize\">\n {status.replace(/_/g, ' ')}\n </Badge>\n <span className=\"text-lg font-bold\">{count}</span>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Condition</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex flex-wrap gap-3\">\n {byCondition.map(([condition, count]) => (\n <div key={condition} className=\"flex items-center gap-2 rounded-lg border p-3\">\n <Badge variant=\"outline\" className=\"capitalize\">\n {condition}\n </Badge>\n <span className=\"text-lg font-bold\">{count}</span>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PortfolioPortfolioOverviewPage.js","names":[],"sources":["../../../src/assethandler/pages/PortfolioPortfolioOverviewPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n GradientText,\n GlassCard,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Package, CheckCircle2, Wrench, MapPin } from 'lucide-react';\nimport { useAssetHandlerStore, type Asset } from '../store/assethandlerStore';\n\nfunction countBy(assets: Asset[], key: (a: Asset) => string): Array<[string, number]> {\n const map = assets.reduce<Record<string, number>>((acc, a) => {\n const k = key(a);\n acc[k] = (acc[k] || 0) + 1;\n return acc;\n }, {});\n return Object.entries(map).sort((a, b) => b[1] - a[1]);\n}\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' =>\n status === 'active' ? 'default' : status === 'disposed' ? 'destructive' : 'secondary';\n\nexport function PortfolioPortfolioOverviewPage() {\n const { assets } = useAssetHandlerStore();\n\n const byCategory = useMemo(() => countBy(assets, (a) => a.category.replace(/_/g, ' ')), [assets]);\n const byStatus = useMemo(() => countBy(assets, (a) => a.status), [assets]);\n const byCondition = useMemo(() => countBy(assets, (a) => a.condition), [assets]);\n const byLocation = useMemo(\n () => countBy(assets, (a) => a.location.trim() || 'Unlocated'),\n [assets]\n );\n\n const activeCount = byStatus.find(([s]) => s === 'active')?.[1] ?? 0;\n const maintenanceCount = byStatus.find(([s]) => s === 'maintenance')?.[1] ?? 0;\n const maxCategoryCount = Math.max(...byCategory.map(([, c]) => c), 1);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Portfolio Overview</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n A comprehensive view of your asset portfolio and how it is distributed.\n </p>\n </div>\n\n <PagePurpose>\n The big-picture view of everything you own: how many assets you have and how they break down\n by category, status, condition and location. Use it to inform replacement planning and\n audit.\n </PagePurpose>\n\n {assets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets in your portfolio yet\"\n description=\"Once you add assets, this overview will summarise them by category, status, condition and location.\"\n />\n ) : (\n <>\n <div className=\"grid gap-4 md:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Assets</CardTitle>\n <Package className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {assets.length.toLocaleString()}\n </div>\n <p className=\"text-xs text-text-secondary\">Across all categories</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active</CardTitle>\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeCount}</div>\n <p className=\"text-xs text-text-secondary\">\n {assets.length > 0 ? Math.round((activeCount / assets.length) * 100) : 0}% of\n estate\n </p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">In Maintenance</CardTitle>\n <Wrench className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{maintenanceCount}</div>\n <p className=\"text-xs text-text-secondary\">Currently being serviced</p>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Locations</CardTitle>\n <MapPin className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {byLocation.filter(([l]) => l !== 'Unlocated').length}\n </div>\n <p className=\"text-xs text-text-secondary\">Distinct asset locations</p>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Assets by Category</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {byCategory.map(([category, count]) => (\n <div key={category} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium capitalize\">{category}</span>\n <span className=\"text-text-secondary\">{count} assets</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${Math.round((count / maxCategoryCount) * 100)}%` }}\n />\n </div>\n </div>\n ))}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Location</CardTitle>\n </CardHeader>\n <CardContent>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Location</TableHead>\n <TableHead className=\"text-right\">Count</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {byLocation.map(([location, count]) => (\n <TableRow key={location}>\n <TableCell className=\"font-medium\">{location}</TableCell>\n <TableCell className=\"text-right\">{count}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Status</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex flex-wrap gap-3\">\n {byStatus.map(([status, count]) => (\n <div key={status} className=\"flex items-center gap-2 rounded-lg border p-3\">\n <Badge variant={statusVariant(status)} className=\"capitalize\">\n {status.replace(/_/g, ' ')}\n </Badge>\n <span className=\"text-lg font-bold\">{count}</span>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Assets by Condition</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"flex flex-wrap gap-3\">\n {byCondition.map(([condition, count]) => (\n <div key={condition} className=\"flex items-center gap-2 rounded-lg border p-3\">\n <Badge variant=\"outline\" className=\"capitalize\">\n {condition}\n </Badge>\n <span className=\"text-lg font-bold\">{count}</span>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ProvenancePage.js","names":[],"sources":["../../../src/assethandler/pages/ProvenancePage.tsx"],"sourcesContent":["import { ShieldCheck } from 'lucide-react';\nimport { GradientText, IllustratedEmptyState, EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\n\nconst PROVENANCE_RECORDS_QUERY = gql`\n query AssetHandlerProvenanceRecords {\n provenanceRecords {\n id\n assetId\n hash\n chainNetwork\n txHash\n attestedAt\n attestedBy\n }\n }\n`;\n\nconst RECORD_PROVENANCE_MUTATION = gql`\n mutation AssetHandlerRecordProvenance($input: RecordProvenanceInput!) {\n recordProvenance(input: $input) {\n id\n }\n }\n`;\n\nexport function ProvenancePage() {\n const [assetId, setAssetId] = useState('AST-001');\n const [chainNetwork, setChainNetwork] = useState('polygon-amoy');\n\n const { data, loading, refetch } = useQuery<{\n provenanceRecords: Array<{\n id: string;\n assetId: string;\n hash: string;\n chainNetwork: string;\n txHash: string | null;\n attestedAt: string;\n attestedBy: string;\n }>;\n }>(PROVENANCE_RECORDS_QUERY, { fetchPolicy: 'cache-and-network' });\n\n const [recordProvenance, { loading: recording }] = useMutation(RECORD_PROVENANCE_MUTATION, {\n onCompleted: () => {\n void refetch();\n },\n });\n\n const records = data?.provenanceRecords ?? [];\n\n return (\n <div className=\"space-y-4 p-4\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <ShieldCheck className=\"h-6 w-6\" /> <GradientText>Provenance</GradientText>\n </h1>\n <PagePurpose>\n Prove an asset&apos;s history is tamper-proof. Record cryptographic attestations of key lifecycle\n events to a blockchain network so ownership, custody and condition can be independently\n verified later — essential for high-value, regulated or resold assets.\n </PagePurpose>\n <EmphasisPanel>\n <h2 className=\"text-sm font-semibold mb-3\">Record an attestation</h2>\n <form\n className=\"grid gap-3 md:grid-cols-3\"\n onSubmit={(event) => {\n event.preventDefault();\n const hash = `${assetId}-${Date.now()}`;\n void recordProvenance({\n variables: {\n input: { assetId, hash, chainNetwork, metadata: { source: 'assethandler-ui' } },\n },\n });\n }}\n >\n <input\n className=\"rounded-md border px-3 py-2\"\n value={assetId}\n onChange={(event) => setAssetId(event.target.value)}\n aria-label=\"Asset ID\"\n />\n <input\n className=\"rounded-md border px-3 py-2\"\n value={chainNetwork}\n onChange={(event) => setChainNetwork(event.target.value)}\n aria-label=\"Chain network\"\n />\n <button\n className=\"rounded-md bg-action-primary-bg px-3 py-2 text-action-primary-text\"\n disabled={recording}\n type=\"submit\"\n >\n {recording ? 'Recording...' : 'Record Attestation'}\n </button>\n </form>\n </EmphasisPanel>\n <div className=\"rounded-lg border\">\n <div className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n <span>Asset</span>\n <span>Network</span>\n <span>Hash</span>\n <span>Tx</span>\n <span>Attested At</span>\n </div>\n {loading && records.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && records.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No provenance records yet\"\n description=\"Record an attestation above to start an immutable, verifiable history for your assets.\"\n />\n ) : null}\n {records.map((record) => (\n <div\n key={record.id}\n className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-sm last:border-b-0\"\n >\n <span>{record.assetId}</span>\n <span>{record.chainNetwork}</span>\n <span className=\"truncate\">{record.hash}</span>\n <span className=\"truncate text-text-secondary\">{record.txHash ?? 'pending'}</span>\n <span className=\"text-text-secondary\">\n {new Date(record.attestedAt).toLocaleString()}\n </span>\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAMA,IAAM,IAA2B,CAAG;;;;;;;;;;;;GAc9B,IAA6B,CAAG;;;;;;;AAQtC,SAAgB,IAAiB;CAC/B,IAAM,CAAC,GAAS,KAAc,EAAS,UAAU,EAC3C,CAAC,GAAc,KAAmB,EAAS,eAAe,EAE1D,EAAE,SAAM,YAAS,eAAY,EAUhC,GAA0B,EAAE,aAAa,qBAAqB,CAAC,EAE5D,CAAC,GAAkB,EAAE,SAAS,OAAe,EAAY,GAA4B,EACzF,mBAAmB;AACZ,KAAS;IAEjB,CAAC,EAEI,IAAU,GAAM,qBAAqB,EAAE;AAE7C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;;KAAC,kBAAC,GAAD,EAAA,UAAc,cAAyB,CAAA;KACxE;;GACL,kBAAC,GAAD,EAAA,UAAa,+PAIC,CAAA;GACd,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAA6B;IAA0B,CAAA,EACrE,kBAAC,QAAD;IACE,WAAU;IACV,WAAW,MAAU;AAGhB,KAFL,EAAM,gBAAgB,EAEjB,EAAiB,EACpB,WAAW,EACT,OAAO;MAAE;MAAS,MAHT,GAAG,EAAQ,GAAG,KAAK,KAAK;MAGT;MAAc,UAAU,EAAE,QAAQ,mBAAmB;MAAE,EAChF,EACF,CAAC;;cATJ;KAYE,kBAAC,SAAD;MACE,WAAU;MACV,OAAO;MACP,WAAW,MAAU,EAAW,EAAM,OAAO,MAAM;MACnD,cAAW;MACX,CAAA;KACF,kBAAC,SAAD;MACE,WAAU;MACV,OAAO;MACP,WAAW,MAAU,EAAgB,EAAM,OAAO,MAAM;MACxD,cAAW;MACX,CAAA;KACF,kBAAC,UAAD;MACE,WAAU;MACV,UAAU;MACV,MAAK;gBAEJ,IAAY,iBAAiB;MACvB,CAAA;KACJ;MACO,EAAA,CAAA;GAChB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD,EAAA,UAAM,SAAY,CAAA;OAClB,kBAAC,QAAD,EAAA,UAAM,WAAc,CAAA;OACpB,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA;OACjB,kBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;OACf,kBAAC,QAAD,EAAA,UAAM,eAAkB,CAAA;OACpB;;KACL,KAAW,EAAQ,WAAW,IAC7B,kBAAC,OAAD;MAAK,WAAU;gBACZ,MAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD,EAAa,WAAU,8DAA+D,EAA5E,EAA4E,CACtF;MACE,CAAA,GACJ;KACH,CAAC,KAAW,EAAQ,WAAW,IAC9B,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,GACA;KACH,EAAQ,KAAK,MACZ,kBAAC,OAAD;MAEE,WAAU;gBAFZ;OAIE,kBAAC,QAAD,EAAA,UAAO,EAAO,SAAe,CAAA;OAC7B,kBAAC,QAAD,EAAA,UAAO,EAAO,cAAoB,CAAA;OAClC,kBAAC,QAAD;QAAM,WAAU;kBAAY,EAAO;QAAY,CAAA;OAC/C,kBAAC,QAAD;QAAM,WAAU;kBAAgC,EAAO,UAAU;QAAiB,CAAA;OAClF,kBAAC,QAAD;QAAM,WAAU;kBACb,IAAI,KAAK,EAAO,WAAW,CAAC,gBAAgB;QACxC,CAAA;OACH;QAVC,EAAO,GAUR,CACN;KACE;;GACF"}
1
+ {"version":3,"file":"ProvenancePage.js","names":[],"sources":["../../../src/assethandler/pages/ProvenancePage.tsx"],"sourcesContent":["import { ShieldCheck } from 'lucide-react';\nimport {\n GradientText,\n IllustratedEmptyState,\n EmphasisPanel,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\n\nconst PROVENANCE_RECORDS_QUERY = gql`\n query AssetHandlerProvenanceRecords {\n provenanceRecords {\n id\n assetId\n hash\n chainNetwork\n txHash\n attestedAt\n attestedBy\n }\n }\n`;\n\nconst RECORD_PROVENANCE_MUTATION = gql`\n mutation AssetHandlerRecordProvenance($input: RecordProvenanceInput!) {\n recordProvenance(input: $input) {\n id\n }\n }\n`;\n\nexport function ProvenancePage() {\n const [assetId, setAssetId] = useState('AST-001');\n const [chainNetwork, setChainNetwork] = useState('polygon-amoy');\n\n const { data, loading, refetch } = useQuery<{\n provenanceRecords: Array<{\n id: string;\n assetId: string;\n hash: string;\n chainNetwork: string;\n txHash: string | null;\n attestedAt: string;\n attestedBy: string;\n }>;\n }>(PROVENANCE_RECORDS_QUERY, { fetchPolicy: 'cache-and-network' });\n\n const [recordProvenance, { loading: recording }] = useMutation(RECORD_PROVENANCE_MUTATION, {\n onCompleted: () => {\n void refetch();\n },\n });\n\n const records = data?.provenanceRecords ?? [];\n\n return (\n <div className=\"space-y-4 p-4\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <ShieldCheck className=\"h-6 w-6\" /> <GradientText>Provenance</GradientText>\n </h1>\n <PagePurpose>\n Prove an asset&apos;s history is tamper-proof. Record cryptographic attestations of key\n lifecycle events to a blockchain network so ownership, custody and condition can be\n independently verified later — essential for high-value, regulated or resold assets.\n </PagePurpose>\n <EmphasisPanel>\n <h2 className=\"text-sm font-semibold mb-3\">Record an attestation</h2>\n <form\n className=\"grid gap-3 md:grid-cols-3\"\n onSubmit={(event) => {\n event.preventDefault();\n const hash = `${assetId}-${Date.now()}`;\n void recordProvenance({\n variables: {\n input: { assetId, hash, chainNetwork, metadata: { source: 'assethandler-ui' } },\n },\n });\n }}\n >\n <input\n className=\"rounded-md border px-3 py-2\"\n value={assetId}\n onChange={(event) => setAssetId(event.target.value)}\n aria-label=\"Asset ID\"\n />\n <input\n className=\"rounded-md border px-3 py-2\"\n value={chainNetwork}\n onChange={(event) => setChainNetwork(event.target.value)}\n aria-label=\"Chain network\"\n />\n <button\n className=\"rounded-md bg-action-primary-bg px-3 py-2 text-action-primary-text\"\n disabled={recording}\n type=\"submit\"\n >\n {recording ? 'Recording...' : 'Record Attestation'}\n </button>\n </form>\n </EmphasisPanel>\n <div className=\"rounded-lg border\">\n <div className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n <span>Asset</span>\n <span>Network</span>\n <span>Hash</span>\n <span>Tx</span>\n <span>Attested At</span>\n </div>\n {loading && records.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && records.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No provenance records yet\"\n description=\"Record an attestation above to start an immutable, verifiable history for your assets.\"\n />\n ) : null}\n {records.map((record) => (\n <div\n key={record.id}\n className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-sm last:border-b-0\"\n >\n <span>{record.assetId}</span>\n <span>{record.chainNetwork}</span>\n <span className=\"truncate\">{record.hash}</span>\n <span className=\"truncate text-text-secondary\">{record.txHash ?? 'pending'}</span>\n <span className=\"text-text-secondary\">\n {new Date(record.attestedAt).toLocaleString()}\n </span>\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAWA,IAAM,IAA2B,CAAG;;;;;;;;;;;;GAc9B,IAA6B,CAAG;;;;;;;AAQtC,SAAgB,IAAiB;CAC/B,IAAM,CAAC,GAAS,KAAc,EAAS,UAAU,EAC3C,CAAC,GAAc,KAAmB,EAAS,eAAe,EAE1D,EAAE,SAAM,YAAS,eAAY,EAUhC,GAA0B,EAAE,aAAa,qBAAqB,CAAC,EAE5D,CAAC,GAAkB,EAAE,SAAS,OAAe,EAAY,GAA4B,EACzF,mBAAmB;AACZ,KAAS;IAEjB,CAAC,EAEI,IAAU,GAAM,qBAAqB,EAAE;AAE7C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;;KAAC,kBAAC,GAAD,EAAA,UAAc,cAAyB,CAAA;KACxE;;GACL,kBAAC,GAAD,EAAA,UAAa,+PAIC,CAAA;GACd,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAA6B;IAA0B,CAAA,EACrE,kBAAC,QAAD;IACE,WAAU;IACV,WAAW,MAAU;AAGd,KAFL,EAAM,gBAAgB,EAEjB,EAAiB,EACpB,WAAW,EACT,OAAO;MAAE;MAAS,MAHT,GAAG,EAAQ,GAAG,KAAK,KAAK;MAGT;MAAc,UAAU,EAAE,QAAQ,mBAAmB;MAAE,EAChF,EACF,CAAC;;cATN;KAYE,kBAAC,SAAD;MACE,WAAU;MACV,OAAO;MACP,WAAW,MAAU,EAAW,EAAM,OAAO,MAAM;MACnD,cAAW;MACX,CAAA;KACF,kBAAC,SAAD;MACE,WAAU;MACV,OAAO;MACP,WAAW,MAAU,EAAgB,EAAM,OAAO,MAAM;MACxD,cAAW;MACX,CAAA;KACF,kBAAC,UAAD;MACE,WAAU;MACV,UAAU;MACV,MAAK;gBAEJ,IAAY,iBAAiB;MACvB,CAAA;KACJ;MACO,EAAA,CAAA;GAChB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD,EAAA,UAAM,SAAY,CAAA;OAClB,kBAAC,QAAD,EAAA,UAAM,WAAc,CAAA;OACpB,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA;OACjB,kBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;OACf,kBAAC,QAAD,EAAA,UAAM,eAAkB,CAAA;OACpB;;KACL,KAAW,EAAQ,WAAW,IAC7B,kBAAC,OAAD;MAAK,WAAU;gBACZ,MAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD,EAAa,WAAU,8DAA+D,EAA5E,EAA4E,CACtF;MACE,CAAA,GACJ;KACH,CAAC,KAAW,EAAQ,WAAW,IAC9B,kBAAC,GAAD;MACE,cAAa;MACb,OAAM;MACN,aAAY;MACZ,CAAA,GACA;KACH,EAAQ,KAAK,MACZ,kBAAC,OAAD;MAEE,WAAU;gBAFZ;OAIE,kBAAC,QAAD,EAAA,UAAO,EAAO,SAAe,CAAA;OAC7B,kBAAC,QAAD,EAAA,UAAO,EAAO,cAAoB,CAAA;OAClC,kBAAC,QAAD;QAAM,WAAU;kBAAY,EAAO;QAAY,CAAA;OAC/C,kBAAC,QAAD;QAAM,WAAU;kBAAgC,EAAO,UAAU;QAAiB,CAAA;OAClF,kBAAC,QAAD;QAAM,WAAU;kBACb,IAAI,KAAK,EAAO,WAAW,CAAC,gBAAgB;QACxC,CAAA;OACH;QAVC,EAAO,GAUR,CACN;KACE;;GACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"SecuritySecurityHubPage.js","names":[],"sources":["../../../src/assethandler/pages/SecuritySecurityHubPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Shield, AlertTriangle, FileText, Eye } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst severityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n info: 'outline',\n};\n\nexport function SecuritySecurityHubPage() {\n const navigate = useNavigate();\n const { securityEvents, complianceFrameworks, securityPolicies } = useAssetHandlerStore();\n\n const unresolvedEvents = securityEvents.filter((e) => !e.resolved);\n const criticalEvents = securityEvents.filter(\n (e) => e.severity === 'critical' || e.severity === 'high'\n );\n const activePolicies = securityPolicies.filter((p) => p.status === 'active');\n const avgCompliance =\n complianceFrameworks.length > 0\n ? Math.round(\n complianceFrameworks.reduce((s, f) => s + f.score, 0) / complianceFrameworks.length\n )\n : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Security Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Security monitoring, compliance, and policy management\n </p>\n </div>\n <Button size=\"sm\">\n <Shield className=\"mr-2 h-4 w-4\" />\n Security Report\n </Button>\n </div>\n\n <PagePurpose>\n Your asset-security control room: watch security events as they happen, track how you score\n against compliance frameworks, and manage the policies that govern your estate. Use it to\n close out the highest-severity, unresolved events first and prove you are audit-ready.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-security-hub\"\n steps={[\n {\n id: 'events',\n label: 'Generate a security report',\n description: 'Summarise events, compliance and policy posture.',\n onClick: () => navigate('/reports/report-builder'),\n },\n {\n id: 'audit',\n label: 'Review the audit trail',\n description: 'See who changed what across your assets.',\n onClick: () => navigate('/audit-trail'),\n },\n {\n id: 'backup',\n label: 'Schedule a backup',\n description: 'Protect critical asset data on a recurring schedule.',\n onClick: () => navigate('/security/schedule-backup'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <AlertTriangle className=\"h-4 w-4\" />\n Unresolved Events\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums text-status-error-text\">\n {unresolvedEvents.length}\n </p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Shield className=\"h-4 w-4\" />\n Compliance Score\n </div>\n <p className=\"text-2xl font-bold mt-1\">{avgCompliance}%</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <FileText className=\"h-4 w-4\" />\n Active Policies\n </div>\n <p className=\"text-2xl font-bold mt-1\">{activePolicies.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Eye className=\"h-4 w-4\" />\n Total Events\n </div>\n <p className=\"text-2xl font-bold mt-1\">{securityEvents.length}</p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"events\">\n <TabsList>\n <TabsTrigger value=\"events\">Security Events</TabsTrigger>\n <TabsTrigger value=\"compliance\">Compliance</TabsTrigger>\n <TabsTrigger value=\"policies\">Policies</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"events\" className=\"mt-4\">\n {securityEvents.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title=\"No security events\"\n description=\"Security alerts detected across your assets will appear here for triage.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Severity</th>\n <th className=\"text-left p-3 font-medium\">Source</th>\n <th className=\"text-left p-3 font-medium\">Time</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n </tr>\n </thead>\n <tbody>\n {securityEvents.map((evt) => (\n <tr key={evt.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{evt.id}</td>\n <td className=\"p-3 capitalize text-xs\">{evt.type.replace('_', ' ')}</td>\n <td className=\"p-3\">\n <p className=\"font-medium\">{evt.title}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {evt.description}\n </p>\n </td>\n <td className=\"p-3\">\n <Badge variant={severityColors[evt.severity]}>{evt.severity}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{evt.source}</td>\n <td className=\"p-3 text-xs\">{new Date(evt.timestamp).toLocaleString()}</td>\n <td className=\"p-3\">\n {evt.resolved ? (\n <Badge variant=\"default\">Resolved</Badge>\n ) : (\n <Badge variant=\"destructive\">Open</Badge>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"compliance\" className=\"mt-4\">\n {complianceFrameworks.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No compliance frameworks\"\n description=\"Add frameworks (e.g. ISO 27001, SOC 2) to track your control coverage and score.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {complianceFrameworks.map((fw) => (\n <Card key={fw.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">\n {fw.name} {fw.version}\n </CardTitle>\n <Badge\n variant={\n fw.status === 'compliant'\n ? 'default'\n : fw.status === 'non_compliant'\n ? 'destructive'\n : 'secondary'\n }\n >\n {fw.status.replace('_', ' ')}\n </Badge>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"text-center\">\n <p className=\"text-3xl font-bold tabular-nums\">{fw.score}%</p>\n <p className=\"text-xs text-text-secondary\">Compliance Score</p>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full ${fw.score >= 90 ? 'bg-status-success-bg' : fw.score >= 70 ? 'bg-status-warning-bg' : 'bg-status-error-bg'}`}\n style={{ width: `${fw.score}%` }}\n />\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-bold text-status-success-text\">{fw.passedControls}</p>\n <p className=\"text-text-secondary\">Passed</p>\n </div>\n <div>\n <p className=\"font-bold text-status-error-text\">{fw.failedControls}</p>\n <p className=\"text-text-secondary\">Failed</p>\n </div>\n <div>\n <p className=\"font-bold\">{fw.totalControls}</p>\n <p className=\"text-text-secondary\">Total</p>\n </div>\n </div>\n <div className=\"text-xs text-text-secondary\">\n Last: {fw.lastAssessment} &middot; Next: {fw.nextAssessment}\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"policies\" className=\"mt-4\">\n {securityPolicies.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No security policies\"\n description=\"Define the policies that govern how your assets are secured and managed.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">Name</th>\n <th className=\"text-left p-3 font-medium\">Category</th>\n <th className=\"text-left p-3 font-medium\">Version</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Owner</th>\n <th className=\"text-left p-3 font-medium\">Review Date</th>\n </tr>\n </thead>\n <tbody>\n {securityPolicies.map((pol) => (\n <tr key={pol.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3\">\n <p className=\"font-medium\">{pol.name}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {pol.description}\n </p>\n </td>\n <td className=\"p-3 text-xs\">{pol.category}</td>\n <td className=\"p-3 text-xs\">v{pol.version}</td>\n <td className=\"p-3\">\n <Badge\n variant={\n pol.status === 'active'\n ? 'default'\n : pol.status === 'deprecated'\n ? 'destructive'\n : 'outline'\n }\n >\n {pol.status.replace('_', ' ')}\n </Badge>\n </td>\n <td className=\"p-3 text-xs\">{pol.owner}</td>\n <td className=\"p-3 text-xs\">{pol.reviewDate}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SecuritySecurityHubPage.js","names":[],"sources":["../../../src/assethandler/pages/SecuritySecurityHubPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Shield, AlertTriangle, FileText, Eye } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst severityColors: Record<string, 'destructive' | 'default' | 'secondary' | 'outline'> = {\n critical: 'destructive',\n high: 'destructive',\n medium: 'default',\n low: 'secondary',\n info: 'outline',\n};\n\nexport function SecuritySecurityHubPage() {\n const navigate = useNavigate();\n const { securityEvents, complianceFrameworks, securityPolicies } = useAssetHandlerStore();\n\n const unresolvedEvents = securityEvents.filter((e) => !e.resolved);\n const criticalEvents = securityEvents.filter(\n (e) => e.severity === 'critical' || e.severity === 'high'\n );\n const activePolicies = securityPolicies.filter((p) => p.status === 'active');\n const avgCompliance =\n complianceFrameworks.length > 0\n ? Math.round(\n complianceFrameworks.reduce((s, f) => s + f.score, 0) / complianceFrameworks.length\n )\n : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Security Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Security monitoring, compliance, and policy management\n </p>\n </div>\n <Button size=\"sm\">\n <Shield className=\"mr-2 h-4 w-4\" />\n Security Report\n </Button>\n </div>\n\n <PagePurpose>\n Your asset-security control room: watch security events as they happen, track how you score\n against compliance frameworks, and manage the policies that govern your estate. Use it to\n close out the highest-severity, unresolved events first and prove you are audit-ready.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-security-hub\"\n steps={[\n {\n id: 'events',\n label: 'Generate a security report',\n description: 'Summarise events, compliance and policy posture.',\n onClick: () => navigate('/reports/report-builder'),\n },\n {\n id: 'audit',\n label: 'Review the audit trail',\n description: 'See who changed what across your assets.',\n onClick: () => navigate('/audit-trail'),\n },\n {\n id: 'backup',\n label: 'Schedule a backup',\n description: 'Protect critical asset data on a recurring schedule.',\n onClick: () => navigate('/security/schedule-backup'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <AlertTriangle className=\"h-4 w-4\" />\n Unresolved Events\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums text-status-error-text\">\n {unresolvedEvents.length}\n </p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Shield className=\"h-4 w-4\" />\n Compliance Score\n </div>\n <p className=\"text-2xl font-bold mt-1\">{avgCompliance}%</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <FileText className=\"h-4 w-4\" />\n Active Policies\n </div>\n <p className=\"text-2xl font-bold mt-1\">{activePolicies.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Eye className=\"h-4 w-4\" />\n Total Events\n </div>\n <p className=\"text-2xl font-bold mt-1\">{securityEvents.length}</p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"events\">\n <TabsList>\n <TabsTrigger value=\"events\">Security Events</TabsTrigger>\n <TabsTrigger value=\"compliance\">Compliance</TabsTrigger>\n <TabsTrigger value=\"policies\">Policies</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"events\" className=\"mt-4\">\n {securityEvents.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title=\"No security events\"\n description=\"Security alerts detected across your assets will appear here for triage.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">ID</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Title</th>\n <th className=\"text-left p-3 font-medium\">Severity</th>\n <th className=\"text-left p-3 font-medium\">Source</th>\n <th className=\"text-left p-3 font-medium\">Time</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n </tr>\n </thead>\n <tbody>\n {securityEvents.map((evt) => (\n <tr key={evt.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3 font-mono text-xs\">{evt.id}</td>\n <td className=\"p-3 capitalize text-xs\">{evt.type.replace('_', ' ')}</td>\n <td className=\"p-3\">\n <p className=\"font-medium\">{evt.title}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {evt.description}\n </p>\n </td>\n <td className=\"p-3\">\n <Badge variant={severityColors[evt.severity]}>{evt.severity}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{evt.source}</td>\n <td className=\"p-3 text-xs\">\n {new Date(evt.timestamp).toLocaleString()}\n </td>\n <td className=\"p-3\">\n {evt.resolved ? (\n <Badge variant=\"default\">Resolved</Badge>\n ) : (\n <Badge variant=\"destructive\">Open</Badge>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"compliance\" className=\"mt-4\">\n {complianceFrameworks.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No compliance frameworks\"\n description=\"Add frameworks (e.g. ISO 27001, SOC 2) to track your control coverage and score.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {complianceFrameworks.map((fw) => (\n <Card key={fw.id}>\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">\n {fw.name} {fw.version}\n </CardTitle>\n <Badge\n variant={\n fw.status === 'compliant'\n ? 'default'\n : fw.status === 'non_compliant'\n ? 'destructive'\n : 'secondary'\n }\n >\n {fw.status.replace('_', ' ')}\n </Badge>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"text-center\">\n <p className=\"text-3xl font-bold tabular-nums\">{fw.score}%</p>\n <p className=\"text-xs text-text-secondary\">Compliance Score</p>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full ${fw.score >= 90 ? 'bg-status-success-bg' : fw.score >= 70 ? 'bg-status-warning-bg' : 'bg-status-error-bg'}`}\n style={{ width: `${fw.score}%` }}\n />\n </div>\n <div className=\"grid grid-cols-3 gap-2 text-center text-xs\">\n <div>\n <p className=\"font-bold text-status-success-text\">{fw.passedControls}</p>\n <p className=\"text-text-secondary\">Passed</p>\n </div>\n <div>\n <p className=\"font-bold text-status-error-text\">{fw.failedControls}</p>\n <p className=\"text-text-secondary\">Failed</p>\n </div>\n <div>\n <p className=\"font-bold\">{fw.totalControls}</p>\n <p className=\"text-text-secondary\">Total</p>\n </div>\n </div>\n <div className=\"text-xs text-text-secondary\">\n Last: {fw.lastAssessment} &middot; Next: {fw.nextAssessment}\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"policies\" className=\"mt-4\">\n {securityPolicies.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No security policies\"\n description=\"Define the policies that govern how your assets are secured and managed.\"\n />\n ) : (\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\">\n <th className=\"text-left p-3 font-medium\">Name</th>\n <th className=\"text-left p-3 font-medium\">Category</th>\n <th className=\"text-left p-3 font-medium\">Version</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Owner</th>\n <th className=\"text-left p-3 font-medium\">Review Date</th>\n </tr>\n </thead>\n <tbody>\n {securityPolicies.map((pol) => (\n <tr key={pol.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3\">\n <p className=\"font-medium\">{pol.name}</p>\n <p className=\"text-xs text-text-secondary truncate max-w-xs\">\n {pol.description}\n </p>\n </td>\n <td className=\"p-3 text-xs\">{pol.category}</td>\n <td className=\"p-3 text-xs\">v{pol.version}</td>\n <td className=\"p-3\">\n <Badge\n variant={\n pol.status === 'active'\n ? 'default'\n : pol.status === 'deprecated'\n ? 'destructive'\n : 'outline'\n }\n >\n {pol.status.replace('_', ' ')}\n </Badge>\n </td>\n <td className=\"p-3 text-xs\">{pol.owner}</td>\n <td className=\"p-3 text-xs\">{pol.reviewDate}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionsTransactionDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/TransactionsTransactionDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n ArrowLeft,\n Printer,\n CheckCircle2,\n XCircle,\n DollarSign,\n Calendar,\n Building,\n FileText,\n Package,\n} from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n pending: 'outline',\n approved: 'default',\n completed: 'secondary',\n rejected: 'destructive',\n cancelled: 'outline',\n};\n\nconst typeColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n purchase: 'default',\n lease: 'secondary',\n disposal: 'destructive',\n transfer: 'outline',\n maintenance: 'secondary',\n depreciation: 'outline',\n};\n\nconst statusTimeline = [\n { status: 'Created', date: '2026-01-15T10:30:00Z', actor: 'Procurement System' },\n { status: 'Pending Approval', date: '2026-01-15T10:30:00Z', actor: 'Auto-routed' },\n { status: 'Approved', date: '2026-01-16T14:20:00Z', actor: 'Michael Chen' },\n { status: 'Completed', date: '2026-01-17T09:00:00Z', actor: 'Finance System' },\n];\n\nexport function TransactionsTransactionDetailPage() {\n const navigate = useNavigate();\n const { transactionId } = useParams<{ transactionId: string }>();\n const { transactions } = useAssetHandlerStore();\n const transaction = transactions.find((item) => item.id === transactionId) ?? transactions[0];\n\n if (!transaction) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Transaction not found\"\n description=\"This transaction may have been removed. Return to the transaction list to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/transactions/transaction-list')}>\n Back to transactions\n </Button>\n }\n />\n </div>\n );\n }\n\n const formatAmount = (amount: number) => {\n return Math.abs(amount).toLocaleString('en-US', { style: 'currency', currency: 'USD' });\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-5xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigate('/transactions/transaction-list')}>\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-2\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{transaction.id}</GradientText>\n </h1>\n <Badge variant={statusColors[transaction.status]}>{transaction.status}</Badge>\n <Badge variant={typeColors[transaction.type]}>{transaction.type}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary\">{transaction.description}</p>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <Printer className=\"mr-2 h-4 w-4\" />\n Print\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <CheckCircle2 className=\"mr-2 h-4 w-4\" />\n Approve\n </Button>\n <Button variant=\"destructive\" size=\"sm\">\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n The complete record of a single financial transaction tied to your assets — what it was\n for, how much, against which budget and asset, and its approval timeline. Use this page to\n verify, approve or reject a transaction with a full audit trail.\n </PagePurpose>\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <FileText className=\"h-5 w-5\" />\n Transaction Information\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Transaction ID</p>\n <p className=\"font-mono font-medium\">{transaction.id}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Type</p>\n <Badge variant={typeColors[transaction.type]}>{transaction.type}</Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Category</p>\n <p className=\"font-medium\">{transaction.category}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <Badge variant={statusColors[transaction.status]}>{transaction.status}</Badge>\n </div>\n </div>\n <Separator />\n <div>\n <p className=\"text-sm text-text-secondary\">Description</p>\n <p className=\"mt-1\">{transaction.description}</p>\n </div>\n </CardContent>\n </Card>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <DollarSign className=\"h-5 w-5\" />\n Financial Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Amount</p>\n <p\n className={`text-2xl font-bold ${transaction.amount < 0 ? 'text-status-error-text' : ''}`}\n >\n {formatAmount(transaction.amount)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Currency</p>\n <p className=\"font-medium\">{transaction.currency}</p>\n </div>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Date</p>\n <div className=\"flex items-center gap-1 mt-1\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n <p className=\"font-medium\">{new Date(transaction.date).toLocaleDateString()}</p>\n </div>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5\" />\n Related Items\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n {transaction.vendor && (\n <div>\n <p className=\"text-sm text-text-secondary\">Vendor</p>\n <p className=\"font-medium\">{transaction.vendor}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Department</p>\n <div className=\"flex items-center gap-1 mt-1\">\n <Building className=\"h-4 w-4 text-text-secondary\" />\n <p className=\"font-medium\">{transaction.department}</p>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Status Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {statusTimeline.map((entry, i) => (\n <div key={i} className=\"flex gap-4\">\n <div className=\"flex flex-col items-center\">\n <div\n className={`h-3 w-3 rounded-full ${i === statusTimeline.length - 1 ? 'bg-status-success-bg' : 'bg-action-primary-bg'}`}\n />\n {i < statusTimeline.length - 1 && <div className=\"w-px flex-1 bg-border\" />}\n </div>\n <div className=\"pb-4\">\n <p className=\"font-medium text-sm\">{entry.status}</p>\n <p className=\"text-xs text-text-secondary\">\n {new Date(entry.date).toLocaleString()} by {entry.actor}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransactionsTransactionDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/TransactionsTransactionDetailPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Separator,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n ArrowLeft,\n Printer,\n CheckCircle2,\n XCircle,\n DollarSign,\n Calendar,\n Building,\n FileText,\n Package,\n} from 'lucide-react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n pending: 'outline',\n approved: 'default',\n completed: 'secondary',\n rejected: 'destructive',\n cancelled: 'outline',\n};\n\nconst typeColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n purchase: 'default',\n lease: 'secondary',\n disposal: 'destructive',\n transfer: 'outline',\n maintenance: 'secondary',\n depreciation: 'outline',\n};\n\nconst statusTimeline = [\n { status: 'Created', date: '2026-01-15T10:30:00Z', actor: 'Procurement System' },\n { status: 'Pending Approval', date: '2026-01-15T10:30:00Z', actor: 'Auto-routed' },\n { status: 'Approved', date: '2026-01-16T14:20:00Z', actor: 'Michael Chen' },\n { status: 'Completed', date: '2026-01-17T09:00:00Z', actor: 'Finance System' },\n];\n\nexport function TransactionsTransactionDetailPage() {\n const navigate = useNavigate();\n const { transactionId } = useParams<{ transactionId: string }>();\n const { transactions } = useAssetHandlerStore();\n const transaction = transactions.find((item) => item.id === transactionId) ?? transactions[0];\n\n if (!transaction) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Transaction not found\"\n description=\"This transaction may have been removed. Return to the transaction list to find it.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('/transactions/transaction-list')}>\n Back to transactions\n </Button>\n }\n />\n </div>\n );\n }\n\n const formatAmount = (amount: number) => {\n return Math.abs(amount).toLocaleString('en-US', { style: 'currency', currency: 'USD' });\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-5xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate('/transactions/transaction-list')}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-2\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{transaction.id}</GradientText>\n </h1>\n <Badge variant={statusColors[transaction.status]}>{transaction.status}</Badge>\n <Badge variant={typeColors[transaction.type]}>{transaction.type}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary\">{transaction.description}</p>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <Printer className=\"mr-2 h-4 w-4\" />\n Print\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <CheckCircle2 className=\"mr-2 h-4 w-4\" />\n Approve\n </Button>\n <Button variant=\"destructive\" size=\"sm\">\n <XCircle className=\"mr-2 h-4 w-4\" />\n Reject\n </Button>\n </div>\n </div>\n\n <PagePurpose>\n The complete record of a single financial transaction tied to your assets — what it was for,\n how much, against which budget and asset, and its approval timeline. Use this page to\n verify, approve or reject a transaction with a full audit trail.\n </PagePurpose>\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <FileText className=\"h-5 w-5\" />\n Transaction Information\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Transaction ID</p>\n <p className=\"font-mono font-medium\">{transaction.id}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Type</p>\n <Badge variant={typeColors[transaction.type]}>{transaction.type}</Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Category</p>\n <p className=\"font-medium\">{transaction.category}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <Badge variant={statusColors[transaction.status]}>{transaction.status}</Badge>\n </div>\n </div>\n <Separator />\n <div>\n <p className=\"text-sm text-text-secondary\">Description</p>\n <p className=\"mt-1\">{transaction.description}</p>\n </div>\n </CardContent>\n </Card>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle className=\"flex items-center gap-2\">\n <DollarSign className=\"h-5 w-5\" />\n Financial Details\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4 px-0 pb-0\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Amount</p>\n <p\n className={`text-2xl font-bold ${transaction.amount < 0 ? 'text-status-error-text' : ''}`}\n >\n {formatAmount(transaction.amount)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Currency</p>\n <p className=\"font-medium\">{transaction.currency}</p>\n </div>\n </div>\n <Separator />\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Date</p>\n <div className=\"flex items-center gap-1 mt-1\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n <p className=\"font-medium\">{new Date(transaction.date).toLocaleDateString()}</p>\n </div>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Package className=\"h-5 w-5\" />\n Related Items\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n {transaction.vendor && (\n <div>\n <p className=\"text-sm text-text-secondary\">Vendor</p>\n <p className=\"font-medium\">{transaction.vendor}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Department</p>\n <div className=\"flex items-center gap-1 mt-1\">\n <Building className=\"h-4 w-4 text-text-secondary\" />\n <p className=\"font-medium\">{transaction.department}</p>\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Status Timeline</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {statusTimeline.map((entry, i) => (\n <div key={i} className=\"flex gap-4\">\n <div className=\"flex flex-col items-center\">\n <div\n className={`h-3 w-3 rounded-full ${i === statusTimeline.length - 1 ? 'bg-status-success-bg' : 'bg-action-primary-bg'}`}\n />\n {i < statusTimeline.length - 1 && <div className=\"w-px flex-1 bg-border\" />}\n </div>\n <div className=\"pb-4\">\n <p className=\"font-medium text-sm\">{entry.status}</p>\n <p className=\"text-xs text-text-secondary\">\n {new Date(entry.date).toLocaleString()} by {entry.actor}\n </p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}