@burdenoff/microfe-assethandler 2026.719.2 → 2026.723.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assethandler/AssetHandlerRoutes.d.ts.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.js +17 -9
- package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
- package/dist/assethandler/pages/EsgDashboardPage.js +423 -0
- package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -0
- package/dist/assethandler/pages/KnowledgeBasePage.js +521 -0
- package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetHandlerRoutes.d.ts","sourceRoot":"","sources":["../../src/assethandler/AssetHandlerRoutes.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssetHandlerRoutes.d.ts","sourceRoot":"","sources":["../../src/assethandler/AssetHandlerRoutes.tsx"],"names":[],"mappings":"AAmKA,wBAAgB,kBAAkB,gCA6DjC"}
|
|
@@ -4,16 +4,16 @@ import { Loader2 as r } from "lucide-react";
|
|
|
4
4
|
import { Navigate as i, Route as a, Routes as o } from "react-router-dom";
|
|
5
5
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
6
|
//#region src/assethandler/AssetHandlerRoutes.tsx
|
|
7
|
-
var l = n(() => import("./pages/AssetsAssetCategoriesPage.js").then((e) => ({ default: e.AssetsAssetCategoriesPage }))), u = n(() => import("./pages/AssetsAssetCheckInOutPage.js").then((e) => ({ default: e.AssetsAssetCheckInOutPage }))), d = n(() => import("./pages/AssetsAssetCreatePage.js").then((e) => ({ default: e.AssetsAssetCreatePage }))), f = n(() => import("./pages/AssetsAssetDetailPage.js").then((e) => ({ default: e.AssetsAssetDetailPage }))), p = n(() => import("./pages/AssetsAssetListPage.js").then((e) => ({ default: e.AssetsAssetListPage }))), m = n(() => import("./pages/AssetsAssetTrackingPage.js").then((e) => ({ default: e.AssetsAssetTrackingPage }))), h = n(() => import("./pages/AnalyticsPage.js").then((e) => ({ default: e.AnalyticsPage }))), g = n(() => import("./pages/FinanceBudgetDetailPage.js").then((e) => ({ default: e.FinanceBudgetDetailPage }))), _ = n(() => import("./pages/FinanceFinanceHubPage.js").then((e) => ({ default: e.FinanceFinanceHubPage }))), v = n(() => import("./pages/FinanceInvoiceDetailPage.js").then((e) => ({ default: e.FinanceInvoiceDetailPage }))), y = n(() => import("./pages/ItilChangeDetailPage.js").then((e) => ({ default: e.ItilChangeDetailPage }))), b = n(() => import("./pages/ItilChangeManagementPage.js").then((e) => ({ default: e.ItilChangeManagementPage }))), x = n(() => import("./pages/ItilItilhubPage.js").then((e) => ({ default: e.ItilItilhubPage }))), S = n(() => import("./pages/ItilIncidentDetailPage.js").then((e) => ({ default: e.ItilIncidentDetailPage }))), C = n(() => import("./pages/ItilIncidentManagementPage.js").then((e) => ({ default: e.ItilIncidentManagementPage }))), w = n(() => import("./pages/ItilProblemDetailPage.js").then((e) => ({ default: e.ItilProblemDetailPage }))), T = n(() => import("./pages/ItilProblemManagementPage.js").then((e) => ({ default: e.ItilProblemManagementPage }))), E = n(() => import("./pages/MaintenanceMaintenanceCalendarPage.js").then((e) => ({ default: e.MaintenanceMaintenanceCalendarPage }))), D = n(() => import("./pages/MaintenanceMaintenanceSchedulerPage.js").then((e) => ({ default: e.MaintenanceMaintenanceSchedulerPage }))), O = n(() => import("./pages/OperationsMaintenanceDetailPage.js").then((e) => ({ default: e.OperationsMaintenanceDetailPage }))), k = n(() => import("./pages/OperationsOperationsHubPage.js").then((e) => ({ default: e.OperationsOperationsHubPage }))), A = n(() => import("./pages/OperationsWorkOrderDetailPage.js").then((e) => ({ default: e.OperationsWorkOrderDetailPage }))), j = n(() => import("./pages/PortfolioPortfolioOverviewPage.js").then((e) => ({ default: e.PortfolioPortfolioOverviewPage }))), M = n(() => import("./pages/SecurityComplianceDetailPage.js").then((e) => ({ default: e.SecurityComplianceDetailPage }))), N = n(() => import("./pages/SecurityPolicyDetailPage.js").then((e) => ({ default: e.SecurityPolicyDetailPage }))), P = n(() => import("./pages/SecuritySecurityEventDetailPage.js").then((e) => ({ default: e.SecuritySecurityEventDetailPage }))), F = n(() => import("./pages/SecuritySecurityHubPage.js").then((e) => ({ default: e.SecuritySecurityHubPage }))), I = n(() => import("./pages/TransactionsTransactionDetailPage.js").then((e) => ({ default: e.TransactionsTransactionDetailPage }))), L = n(() => import("./pages/TransactionsTransactionListPage.js").then((e) => ({ default: e.TransactionsTransactionListPage }))), R = n(() => import("./pages/AiPredictionsPage.js").then((e) => ({ default: e.AiPredictionsPage }))), z = n(() => import("./pages/CmdbBrowserPage.js").then((e) => ({ default: e.CmdbBrowserPage }))), B = n(() => import("./pages/DiscoveryJobsPage.js").then((e) => ({ default: e.DiscoveryJobsPage }))), V = n(() => import("./pages/DigitalTwinPage.js").then((e) => ({ default: e.DigitalTwinPage }))), H = n(() => import("./pages/IotDevicesPage.js").then((e) => ({ default: e.IotDevicesPage }))),
|
|
8
|
-
function
|
|
7
|
+
var l = n(() => import("./pages/AssetsAssetCategoriesPage.js").then((e) => ({ default: e.AssetsAssetCategoriesPage }))), u = n(() => import("./pages/AssetsAssetCheckInOutPage.js").then((e) => ({ default: e.AssetsAssetCheckInOutPage }))), d = n(() => import("./pages/AssetsAssetCreatePage.js").then((e) => ({ default: e.AssetsAssetCreatePage }))), f = n(() => import("./pages/AssetsAssetDetailPage.js").then((e) => ({ default: e.AssetsAssetDetailPage }))), p = n(() => import("./pages/AssetsAssetListPage.js").then((e) => ({ default: e.AssetsAssetListPage }))), m = n(() => import("./pages/AssetsAssetTrackingPage.js").then((e) => ({ default: e.AssetsAssetTrackingPage }))), h = n(() => import("./pages/AnalyticsPage.js").then((e) => ({ default: e.AnalyticsPage }))), g = n(() => import("./pages/FinanceBudgetDetailPage.js").then((e) => ({ default: e.FinanceBudgetDetailPage }))), _ = n(() => import("./pages/FinanceFinanceHubPage.js").then((e) => ({ default: e.FinanceFinanceHubPage }))), v = n(() => import("./pages/FinanceInvoiceDetailPage.js").then((e) => ({ default: e.FinanceInvoiceDetailPage }))), y = n(() => import("./pages/ItilChangeDetailPage.js").then((e) => ({ default: e.ItilChangeDetailPage }))), b = n(() => import("./pages/ItilChangeManagementPage.js").then((e) => ({ default: e.ItilChangeManagementPage }))), x = n(() => import("./pages/ItilItilhubPage.js").then((e) => ({ default: e.ItilItilhubPage }))), S = n(() => import("./pages/ItilIncidentDetailPage.js").then((e) => ({ default: e.ItilIncidentDetailPage }))), C = n(() => import("./pages/ItilIncidentManagementPage.js").then((e) => ({ default: e.ItilIncidentManagementPage }))), w = n(() => import("./pages/ItilProblemDetailPage.js").then((e) => ({ default: e.ItilProblemDetailPage }))), T = n(() => import("./pages/ItilProblemManagementPage.js").then((e) => ({ default: e.ItilProblemManagementPage }))), E = n(() => import("./pages/MaintenanceMaintenanceCalendarPage.js").then((e) => ({ default: e.MaintenanceMaintenanceCalendarPage }))), D = n(() => import("./pages/MaintenanceMaintenanceSchedulerPage.js").then((e) => ({ default: e.MaintenanceMaintenanceSchedulerPage }))), O = n(() => import("./pages/OperationsMaintenanceDetailPage.js").then((e) => ({ default: e.OperationsMaintenanceDetailPage }))), k = n(() => import("./pages/OperationsOperationsHubPage.js").then((e) => ({ default: e.OperationsOperationsHubPage }))), A = n(() => import("./pages/OperationsWorkOrderDetailPage.js").then((e) => ({ default: e.OperationsWorkOrderDetailPage }))), j = n(() => import("./pages/PortfolioPortfolioOverviewPage.js").then((e) => ({ default: e.PortfolioPortfolioOverviewPage }))), M = n(() => import("./pages/SecurityComplianceDetailPage.js").then((e) => ({ default: e.SecurityComplianceDetailPage }))), N = n(() => import("./pages/SecurityPolicyDetailPage.js").then((e) => ({ default: e.SecurityPolicyDetailPage }))), P = n(() => import("./pages/SecuritySecurityEventDetailPage.js").then((e) => ({ default: e.SecuritySecurityEventDetailPage }))), F = n(() => import("./pages/SecuritySecurityHubPage.js").then((e) => ({ default: e.SecuritySecurityHubPage }))), I = n(() => import("./pages/TransactionsTransactionDetailPage.js").then((e) => ({ default: e.TransactionsTransactionDetailPage }))), L = n(() => import("./pages/TransactionsTransactionListPage.js").then((e) => ({ default: e.TransactionsTransactionListPage }))), R = n(() => import("./pages/AiPredictionsPage.js").then((e) => ({ default: e.AiPredictionsPage }))), z = n(() => import("./pages/CmdbBrowserPage.js").then((e) => ({ default: e.CmdbBrowserPage }))), B = n(() => import("./pages/DiscoveryJobsPage.js").then((e) => ({ default: e.DiscoveryJobsPage }))), V = n(() => import("./pages/DigitalTwinPage.js").then((e) => ({ default: e.DigitalTwinPage }))), H = n(() => import("./pages/EsgDashboardPage.js").then((e) => ({ default: e.EsgDashboardPage }))), U = n(() => import("./pages/KnowledgeBasePage.js").then((e) => ({ default: e.KnowledgeBasePage }))), W = n(() => import("./pages/IotDevicesPage.js").then((e) => ({ default: e.IotDevicesPage }))), G = n(() => import("./pages/ProvenancePage.js").then((e) => ({ default: e.ProvenancePage }))), K = n(() => import("./pages/SamLicensesPage.js").then((e) => ({ default: e.SamLicensesPage }))), q = n(() => import("./pages/ReportsDashboardPage.js").then((e) => ({ default: e.ReportsDashboardPage })));
|
|
8
|
+
function J() {
|
|
9
9
|
return /* @__PURE__ */ s("div", {
|
|
10
10
|
className: "flex min-h-[320px] items-center justify-center",
|
|
11
11
|
children: /* @__PURE__ */ s(r, { className: "h-8 w-8 animate-spin text-primary" })
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
|
-
function
|
|
14
|
+
function Y() {
|
|
15
15
|
return /* @__PURE__ */ s(t, {
|
|
16
|
-
fallback: /* @__PURE__ */ s(
|
|
16
|
+
fallback: /* @__PURE__ */ s(J, {}),
|
|
17
17
|
children: /* @__PURE__ */ c(o, { children: [
|
|
18
18
|
/* @__PURE__ */ s(a, {
|
|
19
19
|
index: !0,
|
|
@@ -120,7 +120,7 @@ function q() {
|
|
|
120
120
|
}),
|
|
121
121
|
/* @__PURE__ */ s(a, {
|
|
122
122
|
path: "reports/reports-dashboard",
|
|
123
|
-
element: /* @__PURE__ */ s(
|
|
123
|
+
element: /* @__PURE__ */ s(q, {})
|
|
124
124
|
}),
|
|
125
125
|
/* @__PURE__ */ s(a, {
|
|
126
126
|
path: "security/compliance/:frameworkId",
|
|
@@ -148,7 +148,7 @@ function q() {
|
|
|
148
148
|
}),
|
|
149
149
|
/* @__PURE__ */ s(a, {
|
|
150
150
|
path: "advanced/iot-devices",
|
|
151
|
-
element: /* @__PURE__ */ s(
|
|
151
|
+
element: /* @__PURE__ */ s(W, {})
|
|
152
152
|
}),
|
|
153
153
|
/* @__PURE__ */ s(a, {
|
|
154
154
|
path: "advanced/digital-twin",
|
|
@@ -156,7 +156,7 @@ function q() {
|
|
|
156
156
|
}),
|
|
157
157
|
/* @__PURE__ */ s(a, {
|
|
158
158
|
path: "advanced/sam-licenses",
|
|
159
|
-
element: /* @__PURE__ */ s(
|
|
159
|
+
element: /* @__PURE__ */ s(K, {})
|
|
160
160
|
}),
|
|
161
161
|
/* @__PURE__ */ s(a, {
|
|
162
162
|
path: "advanced/cmdb-browser",
|
|
@@ -167,9 +167,17 @@ function q() {
|
|
|
167
167
|
element: /* @__PURE__ */ s(B, {})
|
|
168
168
|
}),
|
|
169
169
|
/* @__PURE__ */ s(a, {
|
|
170
|
-
path: "advanced/
|
|
170
|
+
path: "advanced/knowledge-base",
|
|
171
171
|
element: /* @__PURE__ */ s(U, {})
|
|
172
172
|
}),
|
|
173
|
+
/* @__PURE__ */ s(a, {
|
|
174
|
+
path: "advanced/esg-dashboard",
|
|
175
|
+
element: /* @__PURE__ */ s(H, {})
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ s(a, {
|
|
178
|
+
path: "advanced/provenance",
|
|
179
|
+
element: /* @__PURE__ */ s(G, {})
|
|
180
|
+
}),
|
|
173
181
|
/* @__PURE__ */ s(a, {
|
|
174
182
|
path: "advanced/ai-predictions",
|
|
175
183
|
element: /* @__PURE__ */ s(R, {})
|
|
@@ -185,6 +193,6 @@ function q() {
|
|
|
185
193
|
});
|
|
186
194
|
}
|
|
187
195
|
//#endregion
|
|
188
|
-
export {
|
|
196
|
+
export { Y as AssetHandlerRoutes };
|
|
189
197
|
|
|
190
198
|
//# sourceMappingURL=AssetHandlerRoutes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetHandlerRoutes.js","names":[],"sources":["../../src/assethandler/AssetHandlerRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Navigate, Route, Routes } from 'react-router-dom';\nimport { Loader2 } from 'lucide-react';\nimport { DashboardPage as IndexPage } from './pages/DashboardPage';\n\nconst AssetsAssetCategoriesPage = lazy(() =>\n import('./pages/AssetsAssetCategoriesPage').then((m) => ({\n default: m.AssetsAssetCategoriesPage,\n }))\n);\nconst AssetsAssetCheckInOutPage = lazy(() =>\n import('./pages/AssetsAssetCheckInOutPage').then((m) => ({\n default: m.AssetsAssetCheckInOutPage,\n }))\n);\nconst AssetsAssetCreatePage = lazy(() =>\n import('./pages/AssetsAssetCreatePage').then((m) => ({ default: m.AssetsAssetCreatePage }))\n);\nconst AssetsAssetDetailPage = lazy(() =>\n import('./pages/AssetsAssetDetailPage').then((m) => ({ default: m.AssetsAssetDetailPage }))\n);\nconst AssetsAssetListPage = lazy(() =>\n import('./pages/AssetsAssetListPage').then((m) => ({ default: m.AssetsAssetListPage }))\n);\nconst AssetsAssetTrackingPage = lazy(() =>\n import('./pages/AssetsAssetTrackingPage').then((m) => ({ default: m.AssetsAssetTrackingPage }))\n);\nconst AnalyticsPage = lazy(() =>\n import('./pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\nconst FinanceBudgetDetailPage = lazy(() =>\n import('./pages/FinanceBudgetDetailPage').then((m) => ({ default: m.FinanceBudgetDetailPage }))\n);\nconst FinanceFinanceHubPage = lazy(() =>\n import('./pages/FinanceFinanceHubPage').then((m) => ({ default: m.FinanceFinanceHubPage }))\n);\nconst FinanceInvoiceDetailPage = lazy(() =>\n import('./pages/FinanceInvoiceDetailPage').then((m) => ({ default: m.FinanceInvoiceDetailPage }))\n);\nconst ItilChangeDetailPage = lazy(() =>\n import('./pages/ItilChangeDetailPage').then((m) => ({ default: m.ItilChangeDetailPage }))\n);\nconst ItilChangeManagementPage = lazy(() =>\n import('./pages/ItilChangeManagementPage').then((m) => ({ default: m.ItilChangeManagementPage }))\n);\nconst ItilItilhubPage = lazy(() =>\n import('./pages/ItilItilhubPage').then((m) => ({ default: m.ItilItilhubPage }))\n);\nconst ItilIncidentDetailPage = lazy(() =>\n import('./pages/ItilIncidentDetailPage').then((m) => ({ default: m.ItilIncidentDetailPage }))\n);\nconst ItilIncidentManagementPage = lazy(() =>\n import('./pages/ItilIncidentManagementPage').then((m) => ({\n default: m.ItilIncidentManagementPage,\n }))\n);\nconst ItilProblemDetailPage = lazy(() =>\n import('./pages/ItilProblemDetailPage').then((m) => ({ default: m.ItilProblemDetailPage }))\n);\nconst ItilProblemManagementPage = lazy(() =>\n import('./pages/ItilProblemManagementPage').then((m) => ({\n default: m.ItilProblemManagementPage,\n }))\n);\nconst MaintenanceMaintenanceCalendarPage = lazy(() =>\n import('./pages/MaintenanceMaintenanceCalendarPage').then((m) => ({\n default: m.MaintenanceMaintenanceCalendarPage,\n }))\n);\nconst MaintenanceMaintenanceSchedulerPage = lazy(() =>\n import('./pages/MaintenanceMaintenanceSchedulerPage').then((m) => ({\n default: m.MaintenanceMaintenanceSchedulerPage,\n }))\n);\nconst OperationsMaintenanceDetailPage = lazy(() =>\n import('./pages/OperationsMaintenanceDetailPage').then((m) => ({\n default: m.OperationsMaintenanceDetailPage,\n }))\n);\nconst OperationsOperationsHubPage = lazy(() =>\n import('./pages/OperationsOperationsHubPage').then((m) => ({\n default: m.OperationsOperationsHubPage,\n }))\n);\nconst OperationsWorkOrderDetailPage = lazy(() =>\n import('./pages/OperationsWorkOrderDetailPage').then((m) => ({\n default: m.OperationsWorkOrderDetailPage,\n }))\n);\nconst PortfolioPortfolioOverviewPage = lazy(() =>\n import('./pages/PortfolioPortfolioOverviewPage').then((m) => ({\n default: m.PortfolioPortfolioOverviewPage,\n }))\n);\nconst SecurityComplianceDetailPage = lazy(() =>\n import('./pages/SecurityComplianceDetailPage').then((m) => ({\n default: m.SecurityComplianceDetailPage,\n }))\n);\nconst SecurityPolicyDetailPage = lazy(() =>\n import('./pages/SecurityPolicyDetailPage').then((m) => ({ default: m.SecurityPolicyDetailPage }))\n);\nconst SecuritySecurityEventDetailPage = lazy(() =>\n import('./pages/SecuritySecurityEventDetailPage').then((m) => ({\n default: m.SecuritySecurityEventDetailPage,\n }))\n);\nconst SecuritySecurityHubPage = lazy(() =>\n import('./pages/SecuritySecurityHubPage').then((m) => ({ default: m.SecuritySecurityHubPage }))\n);\nconst TransactionsTransactionDetailPage = lazy(() =>\n import('./pages/TransactionsTransactionDetailPage').then((m) => ({\n default: m.TransactionsTransactionDetailPage,\n }))\n);\nconst TransactionsTransactionListPage = lazy(() =>\n import('./pages/TransactionsTransactionListPage').then((m) => ({\n default: m.TransactionsTransactionListPage,\n }))\n);\nconst AiPredictionsPage = lazy(() =>\n import('./pages/AiPredictionsPage').then((m) => ({ default: m.AiPredictionsPage }))\n);\nconst CmdbBrowserPage = lazy(() =>\n import('./pages/CmdbBrowserPage').then((m) => ({ default: m.CmdbBrowserPage }))\n);\nconst DiscoveryJobsPage = lazy(() =>\n import('./pages/DiscoveryJobsPage').then((m) => ({ default: m.DiscoveryJobsPage }))\n);\nconst DigitalTwinPage = lazy(() =>\n import('./pages/DigitalTwinPage').then((m) => ({ default: m.DigitalTwinPage }))\n);\n// EsgDashboardPage and KnowledgeBasePage are intentionally NOT routed (BOFF-3948):\n// both query GraphQL fields (esgMetrics/upsertEsgMetric, knowledgeArticles/\n// createKnowledgeArticle) that do not exist anywhere in the federation graph —\n// neither in this subgraph nor in the suggested owner services\n// (wspace-ecoimpacthub-svc, wspace-botlit-svc) — so rendering them throws a\n// GraphQL validation error for any user who reaches the route. The page\n// components remain in ./pages/ for when the real federated data lands (or are\n// dropped entirely, per product decision — see BOFF-3948).\nconst IotDevicesPage = lazy(() =>\n import('./pages/IotDevicesPage').then((m) => ({ default: m.IotDevicesPage }))\n);\nconst ProvenancePage = lazy(() =>\n import('./pages/ProvenancePage').then((m) => ({ default: m.ProvenancePage }))\n);\nconst SamLicensesPage = lazy(() =>\n import('./pages/SamLicensesPage').then((m) => ({ default: m.SamLicensesPage }))\n);\nconst ReportsDashboardPage = lazy(() =>\n import('./pages/ReportsDashboardPage').then((m) => ({ default: m.ReportsDashboardPage }))\n);\n\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n}\n\nexport function AssetHandlerRoutes() {\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={<IndexPage />} />\n <Route path=\"assets/asset-categories\" element={<AssetsAssetCategoriesPage />} />\n <Route path=\"assets/asset-check-in-out\" element={<AssetsAssetCheckInOutPage />} />\n <Route path=\"assets/asset-create\" element={<AssetsAssetCreatePage />} />\n <Route path=\"assets/:assetId\" element={<AssetsAssetDetailPage />} />\n <Route path=\"assets/asset-list\" element={<AssetsAssetListPage />} />\n <Route path=\"assets/asset-tracking\" element={<AssetsAssetTrackingPage />} />\n <Route path=\"analytics\" element={<AnalyticsPage />} />\n <Route path=\"finance/budgets/:budgetId\" element={<FinanceBudgetDetailPage />} />\n <Route path=\"finance/finance-hub\" element={<FinanceFinanceHubPage />} />\n <Route path=\"finance/invoices/:invoiceId\" element={<FinanceInvoiceDetailPage />} />\n <Route path=\"itil/changes/:changeId\" element={<ItilChangeDetailPage />} />\n <Route path=\"itil/change-management\" element={<ItilChangeManagementPage />} />\n <Route path=\"itil/itilhub\" element={<ItilItilhubPage />} />\n <Route path=\"itil/incidents/:incidentId\" element={<ItilIncidentDetailPage />} />\n <Route path=\"itil/incident-management\" element={<ItilIncidentManagementPage />} />\n <Route path=\"itil/problems/:problemId\" element={<ItilProblemDetailPage />} />\n <Route path=\"itil/problem-management\" element={<ItilProblemManagementPage />} />\n <Route\n path=\"maintenance/maintenance-calendar\"\n element={<MaintenanceMaintenanceCalendarPage />}\n />\n <Route\n path=\"maintenance/maintenance-scheduler\"\n element={<MaintenanceMaintenanceSchedulerPage />}\n />\n <Route\n path=\"operations/maintenance/:maintenanceId\"\n element={<OperationsMaintenanceDetailPage />}\n />\n <Route path=\"operations/operations-hub\" element={<OperationsOperationsHubPage />} />\n <Route\n path=\"operations/work-orders/:workOrderId\"\n element={<OperationsWorkOrderDetailPage />}\n />\n <Route path=\"portfolio/portfolio-overview\" element={<PortfolioPortfolioOverviewPage />} />\n <Route path=\"reports\" element={<Navigate to=\"reports-dashboard\" replace />} />\n <Route path=\"reports/reports-dashboard\" element={<ReportsDashboardPage />} />\n <Route path=\"security/compliance/:frameworkId\" element={<SecurityComplianceDetailPage />} />\n <Route path=\"security/policies/:policyId\" element={<SecurityPolicyDetailPage />} />\n <Route path=\"security/events/:eventId\" element={<SecuritySecurityEventDetailPage />} />\n <Route path=\"security/security-hub\" element={<SecuritySecurityHubPage />} />\n <Route path=\"transactions/:transactionId\" element={<TransactionsTransactionDetailPage />} />\n <Route path=\"transactions/transaction-list\" element={<TransactionsTransactionListPage />} />\n <Route path=\"advanced/iot-devices\" element={<IotDevicesPage />} />\n <Route path=\"advanced/digital-twin\" element={<DigitalTwinPage />} />\n <Route path=\"advanced/sam-licenses\" element={<SamLicensesPage />} />\n <Route path=\"advanced/cmdb-browser\" element={<CmdbBrowserPage />} />\n <Route path=\"advanced/discovery-jobs\" element={<DiscoveryJobsPage />} />\n {/* advanced/knowledge-base and advanced/esg-dashboard intentionally\n unrouted — see the comment above the (removed) lazy imports. */}\n <Route path=\"advanced/provenance\" element={<ProvenancePage />} />\n <Route path=\"advanced/ai-predictions\" element={<AiPredictionsPage />} />\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetHandlerRoutes.js","names":[],"sources":["../../src/assethandler/AssetHandlerRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Navigate, Route, Routes } from 'react-router-dom';\nimport { Loader2 } from 'lucide-react';\nimport { DashboardPage as IndexPage } from './pages/DashboardPage';\n\nconst AssetsAssetCategoriesPage = lazy(() =>\n import('./pages/AssetsAssetCategoriesPage').then((m) => ({\n default: m.AssetsAssetCategoriesPage,\n }))\n);\nconst AssetsAssetCheckInOutPage = lazy(() =>\n import('./pages/AssetsAssetCheckInOutPage').then((m) => ({\n default: m.AssetsAssetCheckInOutPage,\n }))\n);\nconst AssetsAssetCreatePage = lazy(() =>\n import('./pages/AssetsAssetCreatePage').then((m) => ({ default: m.AssetsAssetCreatePage }))\n);\nconst AssetsAssetDetailPage = lazy(() =>\n import('./pages/AssetsAssetDetailPage').then((m) => ({ default: m.AssetsAssetDetailPage }))\n);\nconst AssetsAssetListPage = lazy(() =>\n import('./pages/AssetsAssetListPage').then((m) => ({ default: m.AssetsAssetListPage }))\n);\nconst AssetsAssetTrackingPage = lazy(() =>\n import('./pages/AssetsAssetTrackingPage').then((m) => ({ default: m.AssetsAssetTrackingPage }))\n);\nconst AnalyticsPage = lazy(() =>\n import('./pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\nconst FinanceBudgetDetailPage = lazy(() =>\n import('./pages/FinanceBudgetDetailPage').then((m) => ({ default: m.FinanceBudgetDetailPage }))\n);\nconst FinanceFinanceHubPage = lazy(() =>\n import('./pages/FinanceFinanceHubPage').then((m) => ({ default: m.FinanceFinanceHubPage }))\n);\nconst FinanceInvoiceDetailPage = lazy(() =>\n import('./pages/FinanceInvoiceDetailPage').then((m) => ({ default: m.FinanceInvoiceDetailPage }))\n);\nconst ItilChangeDetailPage = lazy(() =>\n import('./pages/ItilChangeDetailPage').then((m) => ({ default: m.ItilChangeDetailPage }))\n);\nconst ItilChangeManagementPage = lazy(() =>\n import('./pages/ItilChangeManagementPage').then((m) => ({ default: m.ItilChangeManagementPage }))\n);\nconst ItilItilhubPage = lazy(() =>\n import('./pages/ItilItilhubPage').then((m) => ({ default: m.ItilItilhubPage }))\n);\nconst ItilIncidentDetailPage = lazy(() =>\n import('./pages/ItilIncidentDetailPage').then((m) => ({ default: m.ItilIncidentDetailPage }))\n);\nconst ItilIncidentManagementPage = lazy(() =>\n import('./pages/ItilIncidentManagementPage').then((m) => ({\n default: m.ItilIncidentManagementPage,\n }))\n);\nconst ItilProblemDetailPage = lazy(() =>\n import('./pages/ItilProblemDetailPage').then((m) => ({ default: m.ItilProblemDetailPage }))\n);\nconst ItilProblemManagementPage = lazy(() =>\n import('./pages/ItilProblemManagementPage').then((m) => ({\n default: m.ItilProblemManagementPage,\n }))\n);\nconst MaintenanceMaintenanceCalendarPage = lazy(() =>\n import('./pages/MaintenanceMaintenanceCalendarPage').then((m) => ({\n default: m.MaintenanceMaintenanceCalendarPage,\n }))\n);\nconst MaintenanceMaintenanceSchedulerPage = lazy(() =>\n import('./pages/MaintenanceMaintenanceSchedulerPage').then((m) => ({\n default: m.MaintenanceMaintenanceSchedulerPage,\n }))\n);\nconst OperationsMaintenanceDetailPage = lazy(() =>\n import('./pages/OperationsMaintenanceDetailPage').then((m) => ({\n default: m.OperationsMaintenanceDetailPage,\n }))\n);\nconst OperationsOperationsHubPage = lazy(() =>\n import('./pages/OperationsOperationsHubPage').then((m) => ({\n default: m.OperationsOperationsHubPage,\n }))\n);\nconst OperationsWorkOrderDetailPage = lazy(() =>\n import('./pages/OperationsWorkOrderDetailPage').then((m) => ({\n default: m.OperationsWorkOrderDetailPage,\n }))\n);\nconst PortfolioPortfolioOverviewPage = lazy(() =>\n import('./pages/PortfolioPortfolioOverviewPage').then((m) => ({\n default: m.PortfolioPortfolioOverviewPage,\n }))\n);\nconst SecurityComplianceDetailPage = lazy(() =>\n import('./pages/SecurityComplianceDetailPage').then((m) => ({\n default: m.SecurityComplianceDetailPage,\n }))\n);\nconst SecurityPolicyDetailPage = lazy(() =>\n import('./pages/SecurityPolicyDetailPage').then((m) => ({ default: m.SecurityPolicyDetailPage }))\n);\nconst SecuritySecurityEventDetailPage = lazy(() =>\n import('./pages/SecuritySecurityEventDetailPage').then((m) => ({\n default: m.SecuritySecurityEventDetailPage,\n }))\n);\nconst SecuritySecurityHubPage = lazy(() =>\n import('./pages/SecuritySecurityHubPage').then((m) => ({ default: m.SecuritySecurityHubPage }))\n);\nconst TransactionsTransactionDetailPage = lazy(() =>\n import('./pages/TransactionsTransactionDetailPage').then((m) => ({\n default: m.TransactionsTransactionDetailPage,\n }))\n);\nconst TransactionsTransactionListPage = lazy(() =>\n import('./pages/TransactionsTransactionListPage').then((m) => ({\n default: m.TransactionsTransactionListPage,\n }))\n);\nconst AiPredictionsPage = lazy(() =>\n import('./pages/AiPredictionsPage').then((m) => ({ default: m.AiPredictionsPage }))\n);\nconst CmdbBrowserPage = lazy(() =>\n import('./pages/CmdbBrowserPage').then((m) => ({ default: m.CmdbBrowserPage }))\n);\nconst DiscoveryJobsPage = lazy(() =>\n import('./pages/DiscoveryJobsPage').then((m) => ({ default: m.DiscoveryJobsPage }))\n);\nconst DigitalTwinPage = lazy(() =>\n import('./pages/DigitalTwinPage').then((m) => ({ default: m.DigitalTwinPage }))\n);\n// Re-routed (BOFF-3948): esgMetrics/upsertEsgMetric and knowledgeArticles/\n// createKnowledgeArticle are now real fields owned by wspace-assethandler-svc,\n// so these two pages resolve against live data instead of crashing on a GraphQL\n// validation error.\nconst EsgDashboardPage = lazy(() =>\n import('./pages/EsgDashboardPage').then((m) => ({ default: m.EsgDashboardPage }))\n);\nconst KnowledgeBasePage = lazy(() =>\n import('./pages/KnowledgeBasePage').then((m) => ({ default: m.KnowledgeBasePage }))\n);\nconst IotDevicesPage = lazy(() =>\n import('./pages/IotDevicesPage').then((m) => ({ default: m.IotDevicesPage }))\n);\nconst ProvenancePage = lazy(() =>\n import('./pages/ProvenancePage').then((m) => ({ default: m.ProvenancePage }))\n);\nconst SamLicensesPage = lazy(() =>\n import('./pages/SamLicensesPage').then((m) => ({ default: m.SamLicensesPage }))\n);\nconst ReportsDashboardPage = lazy(() =>\n import('./pages/ReportsDashboardPage').then((m) => ({ default: m.ReportsDashboardPage }))\n);\n\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n}\n\nexport function AssetHandlerRoutes() {\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={<IndexPage />} />\n <Route path=\"assets/asset-categories\" element={<AssetsAssetCategoriesPage />} />\n <Route path=\"assets/asset-check-in-out\" element={<AssetsAssetCheckInOutPage />} />\n <Route path=\"assets/asset-create\" element={<AssetsAssetCreatePage />} />\n <Route path=\"assets/:assetId\" element={<AssetsAssetDetailPage />} />\n <Route path=\"assets/asset-list\" element={<AssetsAssetListPage />} />\n <Route path=\"assets/asset-tracking\" element={<AssetsAssetTrackingPage />} />\n <Route path=\"analytics\" element={<AnalyticsPage />} />\n <Route path=\"finance/budgets/:budgetId\" element={<FinanceBudgetDetailPage />} />\n <Route path=\"finance/finance-hub\" element={<FinanceFinanceHubPage />} />\n <Route path=\"finance/invoices/:invoiceId\" element={<FinanceInvoiceDetailPage />} />\n <Route path=\"itil/changes/:changeId\" element={<ItilChangeDetailPage />} />\n <Route path=\"itil/change-management\" element={<ItilChangeManagementPage />} />\n <Route path=\"itil/itilhub\" element={<ItilItilhubPage />} />\n <Route path=\"itil/incidents/:incidentId\" element={<ItilIncidentDetailPage />} />\n <Route path=\"itil/incident-management\" element={<ItilIncidentManagementPage />} />\n <Route path=\"itil/problems/:problemId\" element={<ItilProblemDetailPage />} />\n <Route path=\"itil/problem-management\" element={<ItilProblemManagementPage />} />\n <Route\n path=\"maintenance/maintenance-calendar\"\n element={<MaintenanceMaintenanceCalendarPage />}\n />\n <Route\n path=\"maintenance/maintenance-scheduler\"\n element={<MaintenanceMaintenanceSchedulerPage />}\n />\n <Route\n path=\"operations/maintenance/:maintenanceId\"\n element={<OperationsMaintenanceDetailPage />}\n />\n <Route path=\"operations/operations-hub\" element={<OperationsOperationsHubPage />} />\n <Route\n path=\"operations/work-orders/:workOrderId\"\n element={<OperationsWorkOrderDetailPage />}\n />\n <Route path=\"portfolio/portfolio-overview\" element={<PortfolioPortfolioOverviewPage />} />\n <Route path=\"reports\" element={<Navigate to=\"reports-dashboard\" replace />} />\n <Route path=\"reports/reports-dashboard\" element={<ReportsDashboardPage />} />\n <Route path=\"security/compliance/:frameworkId\" element={<SecurityComplianceDetailPage />} />\n <Route path=\"security/policies/:policyId\" element={<SecurityPolicyDetailPage />} />\n <Route path=\"security/events/:eventId\" element={<SecuritySecurityEventDetailPage />} />\n <Route path=\"security/security-hub\" element={<SecuritySecurityHubPage />} />\n <Route path=\"transactions/:transactionId\" element={<TransactionsTransactionDetailPage />} />\n <Route path=\"transactions/transaction-list\" element={<TransactionsTransactionListPage />} />\n <Route path=\"advanced/iot-devices\" element={<IotDevicesPage />} />\n <Route path=\"advanced/digital-twin\" element={<DigitalTwinPage />} />\n <Route path=\"advanced/sam-licenses\" element={<SamLicensesPage />} />\n <Route path=\"advanced/cmdb-browser\" element={<CmdbBrowserPage />} />\n <Route path=\"advanced/discovery-jobs\" element={<DiscoveryJobsPage />} />\n <Route path=\"advanced/knowledge-base\" element={<KnowledgeBasePage />} />\n <Route path=\"advanced/esg-dashboard\" element={<EsgDashboardPage />} />\n <Route path=\"advanced/provenance\" element={<ProvenancePage />} />\n <Route path=\"advanced/ai-predictions\" element={<AiPredictionsPage />} />\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { notify as t } from "../utils/toast.js";
|
|
3
|
+
import { formatNumber as n, seriesColor as r } from "../components/charts/chartTheme.js";
|
|
4
|
+
import { BarsChart as i } from "../components/charts/BarsChart.js";
|
|
5
|
+
import { DonutChart as a } from "../components/charts/DonutChart.js";
|
|
6
|
+
import { Pagination as o, usePagination as s } from "../components/Pagination.js";
|
|
7
|
+
import { StatTile as c } from "../components/StatTile.js";
|
|
8
|
+
import { ChartCard as l } from "../components/ChartCard.js";
|
|
9
|
+
import { SectionHeader as u } from "../components/SectionHeader.js";
|
|
10
|
+
import "../components/index.js";
|
|
11
|
+
import { useMemo as d, useState as f } from "react";
|
|
12
|
+
import { Leaf as p, Minus as m, Plus as h, TrendingDown as g, TrendingUp as _ } from "lucide-react";
|
|
13
|
+
import { gql as v } from "@apollo/client";
|
|
14
|
+
import { useMutation as y, useQuery as b } from "@apollo/client/react";
|
|
15
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
16
|
+
import { Button as w, GlassCard as T, IllustratedEmptyState as E, Input as D, Label as O, PagePurpose as k, ResponsiveDialog as A, ResponsiveDialogContent as j, ResponsiveDialogDescription as M, ResponsiveDialogFooter as N, ResponsiveDialogHeader as P, ResponsiveDialogTitle as F, Select as I, SelectContent as L, SelectItem as R, SelectTrigger as z, SelectValue as B } from "@burdenoff/fe-libs/ui";
|
|
17
|
+
//#region src/assethandler/pages/EsgDashboardPage.tsx
|
|
18
|
+
var V = v`
|
|
19
|
+
query AssetHandlerEsgMetrics {
|
|
20
|
+
esgMetrics {
|
|
21
|
+
id
|
|
22
|
+
metricKey
|
|
23
|
+
metricName
|
|
24
|
+
category
|
|
25
|
+
unit
|
|
26
|
+
value
|
|
27
|
+
target
|
|
28
|
+
trend
|
|
29
|
+
periodStart
|
|
30
|
+
periodEnd
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`, H = v`
|
|
34
|
+
mutation AssetHandlerUpsertEsgMetric($input: UpsertEsgMetricInput!) {
|
|
35
|
+
upsertEsgMetric(input: $input) {
|
|
36
|
+
id
|
|
37
|
+
metricName
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`, U = [
|
|
41
|
+
"environment",
|
|
42
|
+
"social",
|
|
43
|
+
"governance"
|
|
44
|
+
], W = [
|
|
45
|
+
"improving",
|
|
46
|
+
"stable",
|
|
47
|
+
"declining"
|
|
48
|
+
], G = {
|
|
49
|
+
improving: {
|
|
50
|
+
label: "Improving",
|
|
51
|
+
icon: _,
|
|
52
|
+
tone: "positive",
|
|
53
|
+
dir: "up"
|
|
54
|
+
},
|
|
55
|
+
declining: {
|
|
56
|
+
label: "Declining",
|
|
57
|
+
icon: g,
|
|
58
|
+
tone: "negative",
|
|
59
|
+
dir: "down"
|
|
60
|
+
},
|
|
61
|
+
stable: {
|
|
62
|
+
label: "Stable",
|
|
63
|
+
icon: m,
|
|
64
|
+
tone: "neutral",
|
|
65
|
+
dir: "neutral"
|
|
66
|
+
}
|
|
67
|
+
}, K = {
|
|
68
|
+
positive: "bg-status-success-bg-subtle text-status-success-text",
|
|
69
|
+
negative: "bg-status-error-bg-subtle text-status-error-text",
|
|
70
|
+
neutral: "bg-bg-sunken text-text-secondary"
|
|
71
|
+
}, q = (e) => e.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
72
|
+
function J() {
|
|
73
|
+
let e = /* @__PURE__ */ new Date();
|
|
74
|
+
return new Date(e.getFullYear(), e.getMonth(), 1).toISOString().slice(0, 10);
|
|
75
|
+
}
|
|
76
|
+
function Y() {
|
|
77
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
78
|
+
}
|
|
79
|
+
function X({ trend: t }) {
|
|
80
|
+
let n = G[t ?? "stable"] ?? G.stable, r = n.icon;
|
|
81
|
+
return /* @__PURE__ */ C("span", {
|
|
82
|
+
className: e("inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium", K[n.tone]),
|
|
83
|
+
children: [/* @__PURE__ */ S(r, { className: "h-3 w-3" }), n.label]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function Z({ open: e, onOpenChange: n, onSaved: r }) {
|
|
87
|
+
let [i, a] = f(""), [o, s] = f("environment"), [c, l] = f(""), [u, d] = f(""), [p, m] = f(""), [h, g] = f("stable"), [_, v] = f(J()), [b, x] = f(Y()), [T, { loading: E }] = y(H, {
|
|
88
|
+
onCompleted: (e) => {
|
|
89
|
+
t.success("Metric saved", `${e.upsertEsgMetric.metricName} was recorded.`), a(""), l(""), d(""), m(""), n(!1), r();
|
|
90
|
+
},
|
|
91
|
+
onError: (e) => t.error("Could not save metric", e.message)
|
|
92
|
+
});
|
|
93
|
+
return /* @__PURE__ */ S(A, {
|
|
94
|
+
open: e,
|
|
95
|
+
onOpenChange: n,
|
|
96
|
+
children: /* @__PURE__ */ C(j, {
|
|
97
|
+
className: "max-h-[85vh] overflow-y-auto sm:max-w-2xl",
|
|
98
|
+
children: [/* @__PURE__ */ C(P, { children: [/* @__PURE__ */ S(F, { children: "Save Metric" }), /* @__PURE__ */ S(M, { children: "Record an ESG metric to track progress toward your sustainability targets." })] }), /* @__PURE__ */ C("form", {
|
|
99
|
+
className: "space-y-3",
|
|
100
|
+
onSubmit: (e) => {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
let n = Number(u);
|
|
103
|
+
if (!i.trim() || !c.trim()) {
|
|
104
|
+
t.warning("Missing details", "Metric name and unit are required.");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!Number.isFinite(n) || u.trim() === "") {
|
|
108
|
+
t.warning("Invalid value", "Enter a numeric metric value.");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (!_ || !b) {
|
|
112
|
+
t.warning("Missing period", "Period start and end are required.");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
let r = p.trim() === "" ? null : Number(p);
|
|
116
|
+
T({ variables: { input: {
|
|
117
|
+
metricKey: q(i),
|
|
118
|
+
metricName: i.trim(),
|
|
119
|
+
category: o,
|
|
120
|
+
unit: c.trim(),
|
|
121
|
+
value: n,
|
|
122
|
+
target: r != null && Number.isFinite(r) ? r : null,
|
|
123
|
+
trend: h,
|
|
124
|
+
periodStart: new Date(_).toISOString(),
|
|
125
|
+
periodEnd: new Date(b).toISOString()
|
|
126
|
+
} } });
|
|
127
|
+
},
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ C("div", {
|
|
130
|
+
className: "grid gap-3 md:grid-cols-3",
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ C("div", {
|
|
133
|
+
className: "space-y-2",
|
|
134
|
+
children: [/* @__PURE__ */ S(O, { children: "Metric Name *" }), /* @__PURE__ */ S(D, {
|
|
135
|
+
placeholder: "e.g., Scope 2 carbon emissions",
|
|
136
|
+
value: i,
|
|
137
|
+
onChange: (e) => a(e.target.value)
|
|
138
|
+
})]
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ C("div", {
|
|
141
|
+
className: "space-y-2",
|
|
142
|
+
children: [/* @__PURE__ */ S(O, { children: "Category" }), /* @__PURE__ */ C(I, {
|
|
143
|
+
value: o,
|
|
144
|
+
onValueChange: (e) => s(e),
|
|
145
|
+
children: [/* @__PURE__ */ S(z, { children: /* @__PURE__ */ S(B, {}) }), /* @__PURE__ */ S(L, { children: U.map((e) => /* @__PURE__ */ S(R, {
|
|
146
|
+
value: e,
|
|
147
|
+
className: "capitalize",
|
|
148
|
+
children: e
|
|
149
|
+
}, e)) })]
|
|
150
|
+
})]
|
|
151
|
+
}),
|
|
152
|
+
/* @__PURE__ */ C("div", {
|
|
153
|
+
className: "space-y-2",
|
|
154
|
+
children: [/* @__PURE__ */ S(O, { children: "Unit *" }), /* @__PURE__ */ S(D, {
|
|
155
|
+
placeholder: "e.g., tCO2e",
|
|
156
|
+
value: c,
|
|
157
|
+
onChange: (e) => l(e.target.value)
|
|
158
|
+
})]
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ C("div", {
|
|
163
|
+
className: "grid gap-3 md:grid-cols-3",
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ C("div", {
|
|
166
|
+
className: "space-y-2",
|
|
167
|
+
children: [/* @__PURE__ */ S(O, { children: "Value *" }), /* @__PURE__ */ S(D, {
|
|
168
|
+
type: "number",
|
|
169
|
+
step: "any",
|
|
170
|
+
value: u,
|
|
171
|
+
onChange: (e) => d(e.target.value)
|
|
172
|
+
})]
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ C("div", {
|
|
175
|
+
className: "space-y-2",
|
|
176
|
+
children: [/* @__PURE__ */ S(O, { children: "Target" }), /* @__PURE__ */ S(D, {
|
|
177
|
+
type: "number",
|
|
178
|
+
step: "any",
|
|
179
|
+
value: p,
|
|
180
|
+
onChange: (e) => m(e.target.value)
|
|
181
|
+
})]
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ C("div", {
|
|
184
|
+
className: "space-y-2",
|
|
185
|
+
children: [/* @__PURE__ */ S(O, { children: "Trend" }), /* @__PURE__ */ C(I, {
|
|
186
|
+
value: h,
|
|
187
|
+
onValueChange: (e) => g(e),
|
|
188
|
+
children: [/* @__PURE__ */ S(z, { children: /* @__PURE__ */ S(B, {}) }), /* @__PURE__ */ S(L, { children: W.map((e) => /* @__PURE__ */ S(R, {
|
|
189
|
+
value: e,
|
|
190
|
+
className: "capitalize",
|
|
191
|
+
children: e
|
|
192
|
+
}, e)) })]
|
|
193
|
+
})]
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ C("div", {
|
|
198
|
+
className: "grid gap-3 md:grid-cols-2",
|
|
199
|
+
children: [/* @__PURE__ */ C("div", {
|
|
200
|
+
className: "space-y-2",
|
|
201
|
+
children: [/* @__PURE__ */ S(O, { children: "Period Start *" }), /* @__PURE__ */ S(D, {
|
|
202
|
+
type: "date",
|
|
203
|
+
value: _,
|
|
204
|
+
onChange: (e) => v(e.target.value)
|
|
205
|
+
})]
|
|
206
|
+
}), /* @__PURE__ */ C("div", {
|
|
207
|
+
className: "space-y-2",
|
|
208
|
+
children: [/* @__PURE__ */ S(O, { children: "Period End *" }), /* @__PURE__ */ S(D, {
|
|
209
|
+
type: "date",
|
|
210
|
+
value: b,
|
|
211
|
+
onChange: (e) => x(e.target.value)
|
|
212
|
+
})]
|
|
213
|
+
})]
|
|
214
|
+
}),
|
|
215
|
+
/* @__PURE__ */ C(N, { children: [/* @__PURE__ */ S(w, {
|
|
216
|
+
type: "button",
|
|
217
|
+
variant: "outline",
|
|
218
|
+
onClick: () => n(!1),
|
|
219
|
+
disabled: E,
|
|
220
|
+
children: "Cancel"
|
|
221
|
+
}), /* @__PURE__ */ S(w, {
|
|
222
|
+
type: "submit",
|
|
223
|
+
disabled: E,
|
|
224
|
+
children: E ? "Saving…" : "Save Metric"
|
|
225
|
+
})] })
|
|
226
|
+
]
|
|
227
|
+
})]
|
|
228
|
+
})
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function Q() {
|
|
232
|
+
let [t, m] = f(!1), [g, _] = f("ALL"), { data: v, loading: y, refetch: D } = b(V, { fetchPolicy: "cache-and-network" }), O = d(() => v?.esgMetrics ?? [], [v?.esgMetrics]), A = d(() => O.slice(0, 4), [O]), j = d(() => g === "ALL" ? O : O.filter((e) => e.category === g), [O, g]), M = d(() => {
|
|
233
|
+
let e = O.reduce((e, t) => (e[t.category] = (e[t.category] ?? 0) + 1, e), {});
|
|
234
|
+
return Object.entries(e).map(([e, t], n) => ({
|
|
235
|
+
name: e.charAt(0).toUpperCase() + e.slice(1),
|
|
236
|
+
value: t,
|
|
237
|
+
color: r(n)
|
|
238
|
+
}));
|
|
239
|
+
}, [O]), N = d(() => O.filter((e) => e.target != null).slice(0, 8).map((e) => ({
|
|
240
|
+
name: e.metricName,
|
|
241
|
+
value: e.value,
|
|
242
|
+
target: e.target
|
|
243
|
+
})), [O]), P = d(() => {
|
|
244
|
+
let e = { ALL: O.length };
|
|
245
|
+
for (let t of O) e[t.category] = (e[t.category] ?? 0) + 1;
|
|
246
|
+
return e;
|
|
247
|
+
}, [O]), F = s(j, {
|
|
248
|
+
pageSize: 8,
|
|
249
|
+
resetKey: g
|
|
250
|
+
});
|
|
251
|
+
return /* @__PURE__ */ C("div", {
|
|
252
|
+
className: "space-y-5 p-4 sm:p-6",
|
|
253
|
+
children: [
|
|
254
|
+
/* @__PURE__ */ S(u, {
|
|
255
|
+
hero: !0,
|
|
256
|
+
icon: p,
|
|
257
|
+
title: "ESG Dashboard",
|
|
258
|
+
description: "Measure the environmental and governance impact of your estate against targets.",
|
|
259
|
+
actions: /* @__PURE__ */ C(w, {
|
|
260
|
+
className: "w-full sm:w-auto",
|
|
261
|
+
onClick: () => m(!0),
|
|
262
|
+
children: [/* @__PURE__ */ S(h, { className: "mr-2 h-4 w-4" }), "Save Metric"]
|
|
263
|
+
})
|
|
264
|
+
}),
|
|
265
|
+
/* @__PURE__ */ S(k, { children: "Track energy use, carbon emissions and responsible disposal against targets — and produce the evidence ESG reporting and audits require." }),
|
|
266
|
+
/* @__PURE__ */ S(Z, {
|
|
267
|
+
open: t,
|
|
268
|
+
onOpenChange: m,
|
|
269
|
+
onSaved: () => void D()
|
|
270
|
+
}),
|
|
271
|
+
y && O.length === 0 ? /* @__PURE__ */ S("div", {
|
|
272
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
273
|
+
children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ S("div", { className: "h-28 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer" }, t))
|
|
274
|
+
}) : null,
|
|
275
|
+
!y && O.length === 0 ? /* @__PURE__ */ S(E, {
|
|
276
|
+
illustration: "empty-data",
|
|
277
|
+
title: "No ESG metrics recorded yet",
|
|
278
|
+
description: "Save a metric to start tracking sustainability progress against your targets."
|
|
279
|
+
}) : null,
|
|
280
|
+
A.length > 0 ? /* @__PURE__ */ S("div", {
|
|
281
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
282
|
+
children: A.map((e) => {
|
|
283
|
+
let t = G[e.trend ?? "stable"] ?? G.stable;
|
|
284
|
+
return /* @__PURE__ */ S(c, {
|
|
285
|
+
label: `${e.metricName} (${e.unit})`,
|
|
286
|
+
value: e.value,
|
|
287
|
+
format: n,
|
|
288
|
+
delta: t.label,
|
|
289
|
+
deltaDirection: t.dir,
|
|
290
|
+
deltaTone: t.tone,
|
|
291
|
+
icon: p
|
|
292
|
+
}, e.id);
|
|
293
|
+
})
|
|
294
|
+
}) : null,
|
|
295
|
+
O.length > 0 ? /* @__PURE__ */ C("div", {
|
|
296
|
+
className: "grid gap-4 lg:grid-cols-2",
|
|
297
|
+
children: [/* @__PURE__ */ S(l, {
|
|
298
|
+
title: "Value vs. target",
|
|
299
|
+
subtitle: "Metrics measured against their targets",
|
|
300
|
+
children: N.length > 0 ? /* @__PURE__ */ S(i, {
|
|
301
|
+
data: N,
|
|
302
|
+
xKey: "name",
|
|
303
|
+
series: [{
|
|
304
|
+
key: "value",
|
|
305
|
+
label: "Value"
|
|
306
|
+
}, {
|
|
307
|
+
key: "target",
|
|
308
|
+
label: "Target"
|
|
309
|
+
}],
|
|
310
|
+
orientation: "horizontal",
|
|
311
|
+
height: 240,
|
|
312
|
+
categoryWidth: 150,
|
|
313
|
+
ariaLabel: "Metric value versus target"
|
|
314
|
+
}) : /* @__PURE__ */ S("div", {
|
|
315
|
+
className: "flex h-[240px] items-center justify-center text-sm text-text-secondary",
|
|
316
|
+
children: "Set a target on a metric to compare value against target."
|
|
317
|
+
})
|
|
318
|
+
}), /* @__PURE__ */ S(l, {
|
|
319
|
+
title: "By category",
|
|
320
|
+
subtitle: "Metrics across E / S / G",
|
|
321
|
+
children: /* @__PURE__ */ S(a, {
|
|
322
|
+
data: M,
|
|
323
|
+
height: 240,
|
|
324
|
+
centerLabel: "Metrics",
|
|
325
|
+
centerValue: O.length,
|
|
326
|
+
ariaLabel: "Metrics by category"
|
|
327
|
+
})
|
|
328
|
+
})]
|
|
329
|
+
}) : null,
|
|
330
|
+
O.length > 0 ? /* @__PURE__ */ C(x, { children: [
|
|
331
|
+
/* @__PURE__ */ S("div", {
|
|
332
|
+
className: "flex flex-wrap items-center gap-2",
|
|
333
|
+
children: ["ALL", ...U].map((t) => /* @__PURE__ */ C("button", {
|
|
334
|
+
type: "button",
|
|
335
|
+
onClick: () => _(t),
|
|
336
|
+
className: e("rounded-full px-3.5 py-1.5 text-sm font-medium capitalize transition-colors", g === t ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
|
|
337
|
+
children: [t === "ALL" ? "All" : t, /* @__PURE__ */ S("span", {
|
|
338
|
+
className: "ml-1.5 text-xs opacity-70 tabular-nums",
|
|
339
|
+
children: P[t] ?? 0
|
|
340
|
+
})]
|
|
341
|
+
}, t))
|
|
342
|
+
}),
|
|
343
|
+
/* @__PURE__ */ S("div", {
|
|
344
|
+
className: "grid gap-4 sm:grid-cols-2",
|
|
345
|
+
children: F.pageItems.map((e) => {
|
|
346
|
+
let t = e.target && e.target > 0 ? Math.min(100, Math.round(e.value / e.target * 100)) : null;
|
|
347
|
+
return /* @__PURE__ */ S(T, {
|
|
348
|
+
treatment: "glass",
|
|
349
|
+
className: "border-border-seam",
|
|
350
|
+
children: /* @__PURE__ */ C("div", {
|
|
351
|
+
className: "space-y-3 p-4",
|
|
352
|
+
children: [
|
|
353
|
+
/* @__PURE__ */ C("div", {
|
|
354
|
+
className: "flex items-start justify-between gap-2",
|
|
355
|
+
children: [/* @__PURE__ */ C("div", {
|
|
356
|
+
className: "min-w-0",
|
|
357
|
+
children: [/* @__PURE__ */ S("p", {
|
|
358
|
+
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
359
|
+
children: e.category
|
|
360
|
+
}), /* @__PURE__ */ S("h2", {
|
|
361
|
+
className: "mt-0.5 text-base font-semibold text-text-primary",
|
|
362
|
+
children: e.metricName
|
|
363
|
+
})]
|
|
364
|
+
}), /* @__PURE__ */ S(X, { trend: e.trend })]
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ C("div", {
|
|
367
|
+
className: "flex items-baseline gap-2",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ S("span", {
|
|
370
|
+
className: "text-2xl font-bold tabular-nums text-text-primary",
|
|
371
|
+
children: n(e.value)
|
|
372
|
+
}),
|
|
373
|
+
/* @__PURE__ */ S("span", {
|
|
374
|
+
className: "text-sm text-text-secondary",
|
|
375
|
+
children: e.unit
|
|
376
|
+
}),
|
|
377
|
+
e.target == null ? null : /* @__PURE__ */ C("span", {
|
|
378
|
+
className: "text-xs text-text-muted",
|
|
379
|
+
children: ["target ", n(e.target)]
|
|
380
|
+
})
|
|
381
|
+
]
|
|
382
|
+
}),
|
|
383
|
+
t == null ? null : /* @__PURE__ */ C("div", {
|
|
384
|
+
className: "space-y-1",
|
|
385
|
+
children: [/* @__PURE__ */ C("div", {
|
|
386
|
+
className: "flex items-center justify-between text-xs text-text-secondary",
|
|
387
|
+
children: [/* @__PURE__ */ S("span", { children: "Progress to target" }), /* @__PURE__ */ C("span", {
|
|
388
|
+
className: "font-medium tabular-nums",
|
|
389
|
+
children: [t, "%"]
|
|
390
|
+
})]
|
|
391
|
+
}), /* @__PURE__ */ S("div", {
|
|
392
|
+
className: "h-2 overflow-hidden rounded-full bg-bg-sunken",
|
|
393
|
+
children: /* @__PURE__ */ S("div", {
|
|
394
|
+
className: "h-full rounded-full bg-action-primary-bg",
|
|
395
|
+
style: { width: `${t}%` }
|
|
396
|
+
})
|
|
397
|
+
})]
|
|
398
|
+
})
|
|
399
|
+
]
|
|
400
|
+
})
|
|
401
|
+
}, e.id);
|
|
402
|
+
})
|
|
403
|
+
}),
|
|
404
|
+
/* @__PURE__ */ S(o, {
|
|
405
|
+
page: F.page,
|
|
406
|
+
pageCount: F.pageCount,
|
|
407
|
+
rangeStart: F.rangeStart,
|
|
408
|
+
rangeEnd: F.rangeEnd,
|
|
409
|
+
totalItems: F.totalItems,
|
|
410
|
+
canPrev: F.canPrev,
|
|
411
|
+
canNext: F.canNext,
|
|
412
|
+
onPrev: F.prevPage,
|
|
413
|
+
onNext: F.nextPage,
|
|
414
|
+
itemLabel: "metrics"
|
|
415
|
+
})
|
|
416
|
+
] }) : null
|
|
417
|
+
]
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
421
|
+
export { Q as EsgDashboardPage };
|
|
422
|
+
|
|
423
|
+
//# sourceMappingURL=EsgDashboardPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EsgDashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/EsgDashboardPage.tsx"],"sourcesContent":["import { Leaf, Plus, TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport type React from 'react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n StatTile,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n formatNumber,\n type DonutSlice,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst ESG_METRICS_QUERY = gql`\n query AssetHandlerEsgMetrics {\n esgMetrics {\n id\n metricKey\n metricName\n category\n unit\n value\n target\n trend\n periodStart\n periodEnd\n }\n }\n`;\n\nconst UPSERT_ESG_METRIC_MUTATION = gql`\n mutation AssetHandlerUpsertEsgMetric($input: UpsertEsgMetricInput!) {\n upsertEsgMetric(input: $input) {\n id\n metricName\n }\n }\n`;\n\ninterface EsgMetric {\n id: string;\n metricKey: string;\n metricName: string;\n category: string;\n unit: string;\n value: number;\n target: number | null;\n trend: string | null;\n periodStart: string;\n periodEnd: string;\n}\n\ninterface UpsertEsgMetricResult {\n upsertEsgMetric: { id: string; metricName: string };\n}\n\nconst ESG_CATEGORIES = ['environment', 'social', 'governance'] as const;\nconst ESG_TRENDS = ['improving', 'stable', 'declining'] as const;\n\nconst TREND_META: Record<\n string,\n {\n label: string;\n icon: typeof TrendingUp;\n tone: 'positive' | 'negative' | 'neutral';\n dir: 'up' | 'down' | 'neutral';\n }\n> = {\n improving: { label: 'Improving', icon: TrendingUp, tone: 'positive', dir: 'up' },\n declining: { label: 'Declining', icon: TrendingDown, tone: 'negative', dir: 'down' },\n stable: { label: 'Stable', icon: Minus, tone: 'neutral', dir: 'neutral' },\n};\n\nconst TREND_PILL: Record<'positive' | 'negative' | 'neutral', string> = {\n positive: 'bg-status-success-bg-subtle text-status-success-text',\n negative: 'bg-status-error-bg-subtle text-status-error-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n};\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\nfunction firstOfMonthISO(): string {\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10);\n}\n\nfunction todayISO(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nfunction TrendBadge({ trend }: { trend: string | null }) {\n const meta = TREND_META[trend ?? 'stable'] ?? TREND_META.stable;\n const Icon = meta.icon;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium',\n TREND_PILL[meta.tone]\n )}\n >\n <Icon className=\"h-3 w-3\" />\n {meta.label}\n </span>\n );\n}\n\nfunction RecordMetricDialog({\n open,\n onOpenChange,\n onSaved,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onSaved: () => void;\n}) {\n const [metricName, setMetricName] = useState('');\n const [category, setCategory] = useState<(typeof ESG_CATEGORIES)[number]>('environment');\n const [unit, setUnit] = useState('');\n const [value, setValue] = useState('');\n const [target, setTarget] = useState('');\n const [trend, setTrend] = useState<(typeof ESG_TRENDS)[number]>('stable');\n const [periodStart, setPeriodStart] = useState(firstOfMonthISO());\n const [periodEnd, setPeriodEnd] = useState(todayISO());\n\n const [upsertEsgMetric, { loading: saving }] = useMutation<UpsertEsgMetricResult>(\n UPSERT_ESG_METRIC_MUTATION,\n {\n onCompleted: (result) => {\n notify.success('Metric saved', `${result.upsertEsgMetric.metricName} was recorded.`);\n setMetricName('');\n setUnit('');\n setValue('');\n setTarget('');\n onOpenChange(false);\n onSaved();\n },\n onError: (error) => notify.error('Could not save metric', error.message),\n }\n );\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n const parsedValue = Number(value);\n if (!metricName.trim() || !unit.trim()) {\n notify.warning('Missing details', 'Metric name and unit are required.');\n return;\n }\n if (!Number.isFinite(parsedValue) || value.trim() === '') {\n notify.warning('Invalid value', 'Enter a numeric metric value.');\n return;\n }\n if (!periodStart || !periodEnd) {\n notify.warning('Missing period', 'Period start and end are required.');\n return;\n }\n const parsedTarget = target.trim() === '' ? null : Number(target);\n void upsertEsgMetric({\n variables: {\n input: {\n metricKey: slugify(metricName),\n metricName: metricName.trim(),\n category,\n unit: unit.trim(),\n value: parsedValue,\n target: parsedTarget != null && Number.isFinite(parsedTarget) ? parsedTarget : null,\n trend,\n periodStart: new Date(periodStart).toISOString(),\n periodEnd: new Date(periodEnd).toISOString(),\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Save Metric</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Record an ESG metric to track progress toward your sustainability targets.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-3\" onSubmit={handleSubmit}>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Metric Name *</Label>\n <Input\n placeholder=\"e.g., Scope 2 carbon emissions\"\n value={metricName}\n onChange={(e) => setMetricName(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Category</Label>\n <Select value={category} onValueChange={(v) => setCategory(v as typeof category)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_CATEGORIES.map((c) => (\n <SelectItem key={c} value={c} className=\"capitalize\">\n {c}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Unit *</Label>\n <Input\n placeholder=\"e.g., tCO2e\"\n value={unit}\n onChange={(e) => setUnit(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-3\">\n <div className=\"space-y-2\">\n <Label>Value *</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Target</Label>\n <Input\n type=\"number\"\n step=\"any\"\n value={target}\n onChange={(e) => setTarget(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Trend</Label>\n <Select value={trend} onValueChange={(v) => setTrend(v as typeof trend)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ESG_TRENDS.map((t) => (\n <SelectItem key={t} value={t} className=\"capitalize\">\n {t}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period Start *</Label>\n <Input\n type=\"date\"\n value={periodStart}\n onChange={(e) => setPeriodStart(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Period End *</Label>\n <Input type=\"date\" value={periodEnd} onChange={(e) => setPeriodEnd(e.target.value)} />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={saving}>\n {saving ? 'Saving…' : 'Save Metric'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function EsgDashboardPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [category, setCategory] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ esgMetrics: EsgMetric[] }>(ESG_METRICS_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const metrics = useMemo(() => data?.esgMetrics ?? [], [data?.esgMetrics]);\n\n const headline = useMemo(() => metrics.slice(0, 4), [metrics]);\n\n const filtered = useMemo(\n () => (category === 'ALL' ? metrics : metrics.filter((m) => m.category === category)),\n [metrics, category]\n );\n\n const categoryMix = useMemo<DonutSlice[]>(() => {\n const counts = metrics.reduce<Record<string, number>>((acc, m) => {\n acc[m.category] = (acc[m.category] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([cat, value], i) => ({\n name: cat.charAt(0).toUpperCase() + cat.slice(1),\n value,\n color: seriesColor(i),\n }));\n }, [metrics]);\n\n const valueVsTarget = useMemo(\n () =>\n metrics\n .filter((m) => m.target != null)\n .slice(0, 8)\n .map((m) => ({ name: m.metricName, value: m.value, target: m.target as number })),\n [metrics]\n );\n\n const categoryCounts = useMemo(() => {\n const counts: Record<string, number> = { ALL: metrics.length };\n for (const m of metrics) counts[m.category] = (counts[m.category] ?? 0) + 1;\n return counts;\n }, [metrics]);\n\n const pagination = usePagination(filtered, { pageSize: 8, resetKey: category });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={Leaf}\n title=\"ESG Dashboard\"\n description=\"Measure the environmental and governance impact of your estate against targets.\"\n actions={\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Save Metric\n </Button>\n }\n />\n <PagePurpose>\n Track energy use, carbon emissions and responsible disposal against targets — and produce\n the evidence ESG reporting and audits require.\n </PagePurpose>\n\n <RecordMetricDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onSaved={() => void refetch()}\n />\n\n {loading && metrics.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-28 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {!loading && metrics.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No ESG metrics recorded yet\"\n description=\"Save a metric to start tracking sustainability progress against your targets.\"\n />\n ) : null}\n\n {headline.length > 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {headline.map((m) => {\n const meta = TREND_META[m.trend ?? 'stable'] ?? TREND_META.stable;\n return (\n <StatTile\n key={m.id}\n label={`${m.metricName} (${m.unit})`}\n value={m.value}\n format={formatNumber}\n delta={meta.label}\n deltaDirection={meta.dir}\n deltaTone={meta.tone}\n icon={Leaf}\n />\n );\n })}\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Value vs. target\" subtitle=\"Metrics measured against their targets\">\n {valueVsTarget.length > 0 ? (\n <BarsChart\n data={valueVsTarget}\n xKey=\"name\"\n series={[\n { key: 'value', label: 'Value' },\n { key: 'target', label: 'Target' },\n ]}\n orientation=\"horizontal\"\n height={240}\n categoryWidth={150}\n ariaLabel=\"Metric value versus target\"\n />\n ) : (\n <div className=\"flex h-[240px] items-center justify-center text-sm text-text-secondary\">\n Set a target on a metric to compare value against target.\n </div>\n )}\n </ChartCard>\n <ChartCard title=\"By category\" subtitle=\"Metrics across E / S / G\">\n <DonutChart\n data={categoryMix}\n height={240}\n centerLabel=\"Metrics\"\n centerValue={metrics.length}\n ariaLabel=\"Metrics by category\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n {metrics.length > 0 ? (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n {(['ALL', ...ESG_CATEGORIES] as const).map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setCategory(c)}\n className={cn(\n 'rounded-full px-3.5 py-1.5 text-sm font-medium capitalize transition-colors',\n category === c\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {c === 'ALL' ? 'All' : c}\n <span className=\"ml-1.5 text-xs opacity-70 tabular-nums\">\n {categoryCounts[c] ?? 0}\n </span>\n </button>\n ))}\n </div>\n\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {pagination.pageItems.map((metric) => {\n const pct =\n metric.target && metric.target > 0\n ? Math.min(100, Math.round((metric.value / metric.target) * 100))\n : null;\n return (\n <GlassCard key={metric.id} treatment=\"glass\" className=\"border-border-seam\">\n <div className=\"space-y-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n {metric.category}\n </p>\n <h2 className=\"mt-0.5 text-base font-semibold text-text-primary\">\n {metric.metricName}\n </h2>\n </div>\n <TrendBadge trend={metric.trend} />\n </div>\n <div className=\"flex items-baseline gap-2\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {formatNumber(metric.value)}\n </span>\n <span className=\"text-sm text-text-secondary\">{metric.unit}</span>\n {metric.target != null ? (\n <span className=\"text-xs text-text-muted\">\n target {formatNumber(metric.target)}\n </span>\n ) : null}\n </div>\n {pct != null ? (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Progress to target</span>\n <span className=\"font-medium tabular-nums\">{pct}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"metrics\"\n />\n </>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { useAssetHandlerNavigate as e } from "../hooks/useAssetHandlerNavigate.js";
|
|
2
|
+
import { cn as t } from "../utils/cn.js";
|
|
3
|
+
import { notify as n } from "../utils/toast.js";
|
|
4
|
+
import { seriesColor as r } from "../components/charts/chartTheme.js";
|
|
5
|
+
import { BarsChart as i } from "../components/charts/BarsChart.js";
|
|
6
|
+
import { DonutChart as a } from "../components/charts/DonutChart.js";
|
|
7
|
+
import { Pagination as o, usePagination as s } from "../components/Pagination.js";
|
|
8
|
+
import { ChartCard as c } from "../components/ChartCard.js";
|
|
9
|
+
import { SectionHeader as l } from "../components/SectionHeader.js";
|
|
10
|
+
import "../components/index.js";
|
|
11
|
+
import { useMemo as u, useState as d } from "react";
|
|
12
|
+
import { BookOpen as f, ExternalLink as p, Eye as m, Link2 as h, Plus as g, Search as _, User as v } from "lucide-react";
|
|
13
|
+
import { gql as y } from "@apollo/client";
|
|
14
|
+
import { useMutation as b, useQuery as x } from "@apollo/client/react";
|
|
15
|
+
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
16
|
+
import { Button as T, GlassCard as E, IllustratedEmptyState as D, Input as O, Label as k, PagePurpose as ee, ResponsiveDialog as A, ResponsiveDialogContent as j, ResponsiveDialogDescription as M, ResponsiveDialogFooter as N, ResponsiveDialogHeader as P, ResponsiveDialogTitle as F, Select as I, SelectContent as L, SelectItem as R, SelectTrigger as z, SelectValue as B, Textarea as V } from "@burdenoff/fe-libs/ui";
|
|
17
|
+
//#region src/assethandler/pages/KnowledgeBasePage.tsx
|
|
18
|
+
var H = y`
|
|
19
|
+
query AssetHandlerKnowledgeArticles {
|
|
20
|
+
knowledgeArticles {
|
|
21
|
+
id
|
|
22
|
+
title
|
|
23
|
+
slug
|
|
24
|
+
summary
|
|
25
|
+
content
|
|
26
|
+
status
|
|
27
|
+
tags
|
|
28
|
+
views
|
|
29
|
+
createdBy
|
|
30
|
+
updatedBy
|
|
31
|
+
publishedAt
|
|
32
|
+
createdAt
|
|
33
|
+
updatedAt
|
|
34
|
+
relatedAssetId
|
|
35
|
+
relatedIncidentId
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
`, U = y`
|
|
39
|
+
mutation AssetHandlerCreateKnowledgeArticle($input: CreateKnowledgeArticleInput!) {
|
|
40
|
+
createKnowledgeArticle(input: $input) {
|
|
41
|
+
id
|
|
42
|
+
title
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`, W = [
|
|
46
|
+
"DRAFT",
|
|
47
|
+
"PUBLISHED",
|
|
48
|
+
"ARCHIVED"
|
|
49
|
+
], G = {
|
|
50
|
+
PUBLISHED: {
|
|
51
|
+
label: "Published",
|
|
52
|
+
className: "bg-status-success-bg-subtle text-status-success-text"
|
|
53
|
+
},
|
|
54
|
+
DRAFT: {
|
|
55
|
+
label: "Draft",
|
|
56
|
+
className: "bg-bg-sunken text-text-secondary"
|
|
57
|
+
},
|
|
58
|
+
ARCHIVED: {
|
|
59
|
+
label: "Archived",
|
|
60
|
+
className: "bg-status-warning-bg-subtle text-status-warning-text"
|
|
61
|
+
}
|
|
62
|
+
}, K = (e) => e.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, ""), q = (e) => e ? new Date(e).toLocaleDateString(void 0, {
|
|
63
|
+
year: "numeric",
|
|
64
|
+
month: "short",
|
|
65
|
+
day: "numeric"
|
|
66
|
+
}) : "—";
|
|
67
|
+
function te(e) {
|
|
68
|
+
if (e.summary && e.summary.trim()) return e.summary.trim();
|
|
69
|
+
let t = e.content.replace(/\s+/g, " ").trim();
|
|
70
|
+
return t.length > 160 ? `${t.slice(0, 160)}…` : t;
|
|
71
|
+
}
|
|
72
|
+
function ne(e) {
|
|
73
|
+
return (e.replace(/[^a-zA-Z0-9]/g, "").slice(0, 2) || "?").toUpperCase();
|
|
74
|
+
}
|
|
75
|
+
function J({ status: e }) {
|
|
76
|
+
let n = G[e] ?? {
|
|
77
|
+
label: e,
|
|
78
|
+
className: "bg-bg-sunken text-text-secondary"
|
|
79
|
+
};
|
|
80
|
+
return /* @__PURE__ */ C("span", {
|
|
81
|
+
className: t("inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium", n.className),
|
|
82
|
+
children: n.label
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function re({ open: e, onOpenChange: t, onPublished: r }) {
|
|
86
|
+
let [i, a] = d(""), [o, s] = d(""), [c, l] = d(!1), [u, f] = d(""), [p, m] = d(""), [h, g] = d(""), [_, v] = d("PUBLISHED"), y = () => {
|
|
87
|
+
a(""), s(""), l(!1), f(""), m(""), g(""), v("PUBLISHED");
|
|
88
|
+
}, [x, { loading: S }] = b(U, {
|
|
89
|
+
onCompleted: (e) => {
|
|
90
|
+
n.success("Article published", `${e.createKnowledgeArticle.title} is now available.`), y(), t(!1), r();
|
|
91
|
+
},
|
|
92
|
+
onError: (e) => n.error("Could not publish article", e.message)
|
|
93
|
+
}), E = (e) => {
|
|
94
|
+
a(e), c || s(K(e));
|
|
95
|
+
};
|
|
96
|
+
return /* @__PURE__ */ C(A, {
|
|
97
|
+
open: e,
|
|
98
|
+
onOpenChange: t,
|
|
99
|
+
children: /* @__PURE__ */ w(j, {
|
|
100
|
+
className: "max-h-[85vh] overflow-y-auto sm:max-w-2xl",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ w(P, { children: [/* @__PURE__ */ C(F, { children: "New Article" }), /* @__PURE__ */ C(M, { children: "Capture a runbook or fix so your team can find it later." })] }),
|
|
103
|
+
/* @__PURE__ */ w("div", {
|
|
104
|
+
className: "space-y-4",
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ w("div", {
|
|
107
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
108
|
+
children: [/* @__PURE__ */ w("div", {
|
|
109
|
+
className: "space-y-2",
|
|
110
|
+
children: [/* @__PURE__ */ C(k, { children: "Title *" }), /* @__PURE__ */ C(O, {
|
|
111
|
+
value: i,
|
|
112
|
+
onChange: (e) => E(e.target.value)
|
|
113
|
+
})]
|
|
114
|
+
}), /* @__PURE__ */ w("div", {
|
|
115
|
+
className: "space-y-2",
|
|
116
|
+
children: [/* @__PURE__ */ C(k, { children: "Slug *" }), /* @__PURE__ */ C(O, {
|
|
117
|
+
value: o,
|
|
118
|
+
onChange: (e) => {
|
|
119
|
+
l(!0), s(e.target.value);
|
|
120
|
+
}
|
|
121
|
+
})]
|
|
122
|
+
})]
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ w("div", {
|
|
125
|
+
className: "space-y-2",
|
|
126
|
+
children: [/* @__PURE__ */ C(k, { children: "Summary" }), /* @__PURE__ */ C(O, {
|
|
127
|
+
placeholder: "One-line description",
|
|
128
|
+
value: u,
|
|
129
|
+
onChange: (e) => f(e.target.value)
|
|
130
|
+
})]
|
|
131
|
+
}),
|
|
132
|
+
/* @__PURE__ */ w("div", {
|
|
133
|
+
className: "space-y-2",
|
|
134
|
+
children: [/* @__PURE__ */ C(k, { children: "Body *" }), /* @__PURE__ */ C(V, {
|
|
135
|
+
placeholder: "Write the full article body — steps, context, links…",
|
|
136
|
+
value: p,
|
|
137
|
+
onChange: (e) => m(e.target.value),
|
|
138
|
+
rows: 8
|
|
139
|
+
})]
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ w("div", {
|
|
142
|
+
className: "grid gap-4 md:grid-cols-2",
|
|
143
|
+
children: [/* @__PURE__ */ w("div", {
|
|
144
|
+
className: "space-y-2",
|
|
145
|
+
children: [/* @__PURE__ */ C(k, { children: "Category tags" }), /* @__PURE__ */ C(O, {
|
|
146
|
+
placeholder: "Runbooks, Fixes, Procedures…",
|
|
147
|
+
value: h,
|
|
148
|
+
onChange: (e) => g(e.target.value)
|
|
149
|
+
})]
|
|
150
|
+
}), /* @__PURE__ */ w("div", {
|
|
151
|
+
className: "space-y-2",
|
|
152
|
+
children: [/* @__PURE__ */ C(k, { children: "Status" }), /* @__PURE__ */ w(I, {
|
|
153
|
+
value: _,
|
|
154
|
+
onValueChange: (e) => v(e),
|
|
155
|
+
children: [/* @__PURE__ */ C(z, { children: /* @__PURE__ */ C(B, {}) }), /* @__PURE__ */ C(L, { children: W.map((e) => /* @__PURE__ */ C(R, {
|
|
156
|
+
value: e,
|
|
157
|
+
children: e
|
|
158
|
+
}, e)) })]
|
|
159
|
+
})]
|
|
160
|
+
})]
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ w(N, { children: [/* @__PURE__ */ C(T, {
|
|
165
|
+
variant: "outline",
|
|
166
|
+
onClick: () => t(!1),
|
|
167
|
+
disabled: S,
|
|
168
|
+
children: "Cancel"
|
|
169
|
+
}), /* @__PURE__ */ C(T, {
|
|
170
|
+
onClick: () => {
|
|
171
|
+
if (!i.trim() || !o.trim()) {
|
|
172
|
+
n.warning("Missing details", "Title and slug are required.");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (!p.trim()) {
|
|
176
|
+
n.warning("Body required", "Write the article body before publishing.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
let e = h.split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
180
|
+
x({ variables: { input: {
|
|
181
|
+
title: i.trim(),
|
|
182
|
+
slug: o.trim(),
|
|
183
|
+
summary: u.trim() || null,
|
|
184
|
+
content: p.trim(),
|
|
185
|
+
tags: e,
|
|
186
|
+
status: _
|
|
187
|
+
} } });
|
|
188
|
+
},
|
|
189
|
+
disabled: S,
|
|
190
|
+
children: S ? "Publishing…" : "Publish article"
|
|
191
|
+
})] })
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function ie({ article: t, onOpenChange: n }) {
|
|
197
|
+
let r = e();
|
|
198
|
+
return /* @__PURE__ */ C(A, {
|
|
199
|
+
open: !!t,
|
|
200
|
+
onOpenChange: n,
|
|
201
|
+
children: /* @__PURE__ */ C(j, {
|
|
202
|
+
className: "max-h-[85vh] overflow-y-auto sm:max-w-2xl",
|
|
203
|
+
children: t ? /* @__PURE__ */ w(S, { children: [
|
|
204
|
+
/* @__PURE__ */ w(P, { children: [
|
|
205
|
+
/* @__PURE__ */ w("div", {
|
|
206
|
+
className: "flex flex-wrap items-center gap-2",
|
|
207
|
+
children: [/* @__PURE__ */ C(J, { status: t.status }), t.tags.map((e) => /* @__PURE__ */ C("span", {
|
|
208
|
+
className: "rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary",
|
|
209
|
+
children: e
|
|
210
|
+
}, e))]
|
|
211
|
+
}),
|
|
212
|
+
/* @__PURE__ */ C(F, {
|
|
213
|
+
className: "mt-1",
|
|
214
|
+
children: t.title
|
|
215
|
+
}),
|
|
216
|
+
/* @__PURE__ */ w(M, { children: [
|
|
217
|
+
"Updated ",
|
|
218
|
+
q(t.updatedAt),
|
|
219
|
+
" · ",
|
|
220
|
+
t.views.toLocaleString(),
|
|
221
|
+
" views"
|
|
222
|
+
] })
|
|
223
|
+
] }),
|
|
224
|
+
/* @__PURE__ */ C("div", {
|
|
225
|
+
className: "whitespace-pre-wrap text-sm leading-relaxed text-text-primary",
|
|
226
|
+
children: t.content
|
|
227
|
+
}),
|
|
228
|
+
t.relatedAssetId || t.relatedIncidentId ? /* @__PURE__ */ w("div", {
|
|
229
|
+
className: "mt-4 space-y-2 border-t border-border-seam pt-4",
|
|
230
|
+
children: [/* @__PURE__ */ w("h4", {
|
|
231
|
+
className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-text-secondary",
|
|
232
|
+
children: [/* @__PURE__ */ C(h, { className: "h-3.5 w-3.5" }), "Linked records"]
|
|
233
|
+
}), /* @__PURE__ */ w("div", {
|
|
234
|
+
className: "flex flex-wrap gap-2",
|
|
235
|
+
children: [t.relatedAssetId ? /* @__PURE__ */ w(T, {
|
|
236
|
+
variant: "outline",
|
|
237
|
+
size: "sm",
|
|
238
|
+
onClick: () => {
|
|
239
|
+
n(!1), r(`/assets/${t.relatedAssetId}`);
|
|
240
|
+
},
|
|
241
|
+
children: ["View linked asset", /* @__PURE__ */ C(p, { className: "ml-1.5 h-3.5 w-3.5" })]
|
|
242
|
+
}) : null, t.relatedIncidentId ? /* @__PURE__ */ w(T, {
|
|
243
|
+
variant: "outline",
|
|
244
|
+
size: "sm",
|
|
245
|
+
onClick: () => {
|
|
246
|
+
n(!1), r(`/itil/incidents/${t.relatedIncidentId}`);
|
|
247
|
+
},
|
|
248
|
+
children: ["View linked incident", /* @__PURE__ */ C(p, { className: "ml-1.5 h-3.5 w-3.5" })]
|
|
249
|
+
}) : null]
|
|
250
|
+
})]
|
|
251
|
+
}) : null
|
|
252
|
+
] }) : null
|
|
253
|
+
})
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function Y() {
|
|
257
|
+
let [e, n] = d(!1), [p, h] = d(""), [y, b] = d("ALL"), [S, A] = d("ALL"), [j, M] = d("recent"), [N, P] = d(null), { data: F, loading: V, refetch: U } = x(H, { fetchPolicy: "cache-and-network" }), K = u(() => F?.knowledgeArticles ?? [], [F?.knowledgeArticles]), Y = u(() => {
|
|
258
|
+
let e = /* @__PURE__ */ new Map();
|
|
259
|
+
for (let t of K) for (let n of t.tags) e.set(n, (e.get(n) ?? 0) + 1);
|
|
260
|
+
return [...e.entries()].sort((e, t) => t[1] - e[1]);
|
|
261
|
+
}, [K]), X = u(() => {
|
|
262
|
+
let e = p.trim().toLowerCase();
|
|
263
|
+
return [...K.filter((t) => y !== "ALL" && !t.tags.includes(y) || S !== "ALL" && t.status !== S ? !1 : e ? [
|
|
264
|
+
t.title,
|
|
265
|
+
t.summary ?? "",
|
|
266
|
+
t.content,
|
|
267
|
+
t.tags.join(" ")
|
|
268
|
+
].join(" ").toLowerCase().includes(e) : !0)].sort((e, t) => j === "views" ? t.views - e.views : new Date(t.updatedAt).getTime() - new Date(e.updatedAt).getTime());
|
|
269
|
+
}, [
|
|
270
|
+
K,
|
|
271
|
+
p,
|
|
272
|
+
y,
|
|
273
|
+
S,
|
|
274
|
+
j
|
|
275
|
+
]), Z = u(() => {
|
|
276
|
+
let e = K.reduce((e, t) => (e[t.status] = (e[t.status] ?? 0) + 1, e), {});
|
|
277
|
+
return Object.entries(e).map(([e, t], n) => ({
|
|
278
|
+
name: G[e]?.label ?? e,
|
|
279
|
+
value: t,
|
|
280
|
+
color: r(n)
|
|
281
|
+
}));
|
|
282
|
+
}, [K]), Q = u(() => [...K].filter((e) => e.views > 0).sort((e, t) => t.views - e.views).slice(0, 6).map((e) => ({
|
|
283
|
+
name: e.title,
|
|
284
|
+
views: e.views
|
|
285
|
+
})), [K]), $ = s(X, {
|
|
286
|
+
pageSize: 9,
|
|
287
|
+
resetKey: `${p}|${y}|${S}|${j}`
|
|
288
|
+
});
|
|
289
|
+
return /* @__PURE__ */ w("div", {
|
|
290
|
+
className: "space-y-5 p-4 sm:p-6",
|
|
291
|
+
children: [
|
|
292
|
+
/* @__PURE__ */ C(l, {
|
|
293
|
+
hero: !0,
|
|
294
|
+
icon: f,
|
|
295
|
+
title: "Knowledge Base",
|
|
296
|
+
description: "Turn one-off fixes and runbooks into repeatable, searchable operational knowledge.",
|
|
297
|
+
actions: /* @__PURE__ */ w(T, {
|
|
298
|
+
className: "w-full sm:w-auto",
|
|
299
|
+
onClick: () => n(!0),
|
|
300
|
+
children: [/* @__PURE__ */ C(g, { className: "mr-2 h-4 w-4" }), "New Article"]
|
|
301
|
+
})
|
|
302
|
+
}),
|
|
303
|
+
/* @__PURE__ */ C(ee, { children: "Capture the fixes and runbooks your team relies on so the next person doesn't start from scratch. Link articles to incidents and assets, then search them when troubleshooting." }),
|
|
304
|
+
/* @__PURE__ */ C(re, {
|
|
305
|
+
open: e,
|
|
306
|
+
onOpenChange: n,
|
|
307
|
+
onPublished: () => void U()
|
|
308
|
+
}),
|
|
309
|
+
/* @__PURE__ */ C(ie, {
|
|
310
|
+
article: N,
|
|
311
|
+
onOpenChange: (e) => !e && P(null)
|
|
312
|
+
}),
|
|
313
|
+
/* @__PURE__ */ w("div", {
|
|
314
|
+
className: "relative",
|
|
315
|
+
children: [/* @__PURE__ */ C(_, { className: "absolute left-3.5 top-1/2 h-4.5 w-4.5 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ C(O, {
|
|
316
|
+
className: "h-12 pl-11 text-base",
|
|
317
|
+
placeholder: "Search runbooks, fixes and procedures…",
|
|
318
|
+
value: p,
|
|
319
|
+
onChange: (e) => h(e.target.value),
|
|
320
|
+
"aria-label": "Search knowledge articles"
|
|
321
|
+
})]
|
|
322
|
+
}),
|
|
323
|
+
K.length > 0 && (Z.length > 0 || Q.length > 0) ? /* @__PURE__ */ w("div", {
|
|
324
|
+
className: "grid gap-4 lg:grid-cols-2",
|
|
325
|
+
children: [/* @__PURE__ */ C(c, {
|
|
326
|
+
title: "Publishing status",
|
|
327
|
+
subtitle: "Articles by status",
|
|
328
|
+
children: /* @__PURE__ */ C(a, {
|
|
329
|
+
data: Z,
|
|
330
|
+
height: 200,
|
|
331
|
+
centerLabel: "Articles",
|
|
332
|
+
centerValue: K.length,
|
|
333
|
+
ariaLabel: "Articles by status"
|
|
334
|
+
})
|
|
335
|
+
}), /* @__PURE__ */ C(c, {
|
|
336
|
+
title: "Most consulted",
|
|
337
|
+
subtitle: "Top articles by views",
|
|
338
|
+
children: /* @__PURE__ */ C(i, {
|
|
339
|
+
data: Q,
|
|
340
|
+
xKey: "name",
|
|
341
|
+
series: [{
|
|
342
|
+
key: "views",
|
|
343
|
+
label: "Views"
|
|
344
|
+
}],
|
|
345
|
+
orientation: "horizontal",
|
|
346
|
+
height: 200,
|
|
347
|
+
categoryWidth: 150,
|
|
348
|
+
emptyLabel: "No views recorded yet",
|
|
349
|
+
ariaLabel: "Top articles by views"
|
|
350
|
+
})
|
|
351
|
+
})]
|
|
352
|
+
}) : null,
|
|
353
|
+
/* @__PURE__ */ w("div", {
|
|
354
|
+
className: "grid gap-5 lg:grid-cols-[200px_1fr]",
|
|
355
|
+
children: [/* @__PURE__ */ w("aside", {
|
|
356
|
+
className: "space-y-3",
|
|
357
|
+
children: [
|
|
358
|
+
/* @__PURE__ */ w("div", {
|
|
359
|
+
className: "flex items-center justify-between gap-2",
|
|
360
|
+
children: [/* @__PURE__ */ C("h3", {
|
|
361
|
+
className: "text-sm font-semibold text-text-primary",
|
|
362
|
+
children: "Category"
|
|
363
|
+
}), /* @__PURE__ */ w(I, {
|
|
364
|
+
value: j,
|
|
365
|
+
onValueChange: (e) => M(e),
|
|
366
|
+
children: [/* @__PURE__ */ C(z, {
|
|
367
|
+
className: "h-8 w-[130px] text-xs lg:hidden",
|
|
368
|
+
children: /* @__PURE__ */ C(B, {})
|
|
369
|
+
}), /* @__PURE__ */ w(L, { children: [/* @__PURE__ */ C(R, {
|
|
370
|
+
value: "recent",
|
|
371
|
+
children: "Recently updated"
|
|
372
|
+
}), /* @__PURE__ */ C(R, {
|
|
373
|
+
value: "views",
|
|
374
|
+
children: "Most viewed"
|
|
375
|
+
})] })]
|
|
376
|
+
})]
|
|
377
|
+
}),
|
|
378
|
+
/* @__PURE__ */ w("div", {
|
|
379
|
+
className: "flex gap-2 overflow-x-auto pb-1 lg:flex-col lg:overflow-visible lg:pb-0",
|
|
380
|
+
children: [/* @__PURE__ */ w("button", {
|
|
381
|
+
type: "button",
|
|
382
|
+
onClick: () => b("ALL"),
|
|
383
|
+
className: t("shrink-0 rounded-md px-3 py-1.5 text-left text-sm font-medium transition-colors lg:w-full", y === "ALL" ? "bg-action-primary-bg/10 text-primary" : "text-text-secondary hover:text-text-primary"),
|
|
384
|
+
children: ["All articles", /* @__PURE__ */ C("span", {
|
|
385
|
+
className: "ml-1.5 text-xs text-text-muted tabular-nums",
|
|
386
|
+
children: K.length
|
|
387
|
+
})]
|
|
388
|
+
}), Y.map(([e, n]) => /* @__PURE__ */ w("button", {
|
|
389
|
+
type: "button",
|
|
390
|
+
onClick: () => b(e),
|
|
391
|
+
className: t("flex shrink-0 items-center justify-between gap-2 rounded-md px-3 py-1.5 text-left text-sm font-medium transition-colors lg:w-full", y === e ? "bg-action-primary-bg/10 text-primary" : "text-text-secondary hover:text-text-primary"),
|
|
392
|
+
children: [/* @__PURE__ */ C("span", {
|
|
393
|
+
className: "truncate",
|
|
394
|
+
children: e
|
|
395
|
+
}), /* @__PURE__ */ C("span", {
|
|
396
|
+
className: "text-xs text-text-muted tabular-nums",
|
|
397
|
+
children: n
|
|
398
|
+
})]
|
|
399
|
+
}, e))]
|
|
400
|
+
}),
|
|
401
|
+
/* @__PURE__ */ w("div", {
|
|
402
|
+
className: "hidden space-y-1.5 border-t border-border-seam pt-3 lg:block",
|
|
403
|
+
children: [
|
|
404
|
+
/* @__PURE__ */ C(k, {
|
|
405
|
+
className: "text-xs",
|
|
406
|
+
children: "Status"
|
|
407
|
+
}),
|
|
408
|
+
/* @__PURE__ */ w(I, {
|
|
409
|
+
value: S,
|
|
410
|
+
onValueChange: A,
|
|
411
|
+
children: [/* @__PURE__ */ C(z, {
|
|
412
|
+
className: "h-9",
|
|
413
|
+
children: /* @__PURE__ */ C(B, {})
|
|
414
|
+
}), /* @__PURE__ */ w(L, { children: [/* @__PURE__ */ C(R, {
|
|
415
|
+
value: "ALL",
|
|
416
|
+
children: "All statuses"
|
|
417
|
+
}), W.map((e) => /* @__PURE__ */ C(R, {
|
|
418
|
+
value: e,
|
|
419
|
+
children: e
|
|
420
|
+
}, e))] })]
|
|
421
|
+
}),
|
|
422
|
+
/* @__PURE__ */ C(k, {
|
|
423
|
+
className: "text-xs",
|
|
424
|
+
children: "Sort"
|
|
425
|
+
}),
|
|
426
|
+
/* @__PURE__ */ w(I, {
|
|
427
|
+
value: j,
|
|
428
|
+
onValueChange: (e) => M(e),
|
|
429
|
+
children: [/* @__PURE__ */ C(z, {
|
|
430
|
+
className: "h-9",
|
|
431
|
+
children: /* @__PURE__ */ C(B, {})
|
|
432
|
+
}), /* @__PURE__ */ w(L, { children: [/* @__PURE__ */ C(R, {
|
|
433
|
+
value: "recent",
|
|
434
|
+
children: "Recently updated"
|
|
435
|
+
}), /* @__PURE__ */ C(R, {
|
|
436
|
+
value: "views",
|
|
437
|
+
children: "Most viewed"
|
|
438
|
+
})] })]
|
|
439
|
+
})
|
|
440
|
+
]
|
|
441
|
+
})
|
|
442
|
+
]
|
|
443
|
+
}), /* @__PURE__ */ w("div", { children: [
|
|
444
|
+
V && K.length === 0 ? /* @__PURE__ */ C("div", {
|
|
445
|
+
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3",
|
|
446
|
+
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ C("div", { className: "h-40 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer" }, t))
|
|
447
|
+
}) : null,
|
|
448
|
+
!V && X.length === 0 ? /* @__PURE__ */ C(D, {
|
|
449
|
+
illustration: p || y !== "ALL" || S !== "ALL" ? "empty-search" : "empty-data",
|
|
450
|
+
title: p || y !== "ALL" || S !== "ALL" ? "No articles match your filters" : "No knowledge articles found",
|
|
451
|
+
description: p || y !== "ALL" || S !== "ALL" ? "Try a different term, category or status." : "Publish an article to start building your knowledge base."
|
|
452
|
+
}) : null,
|
|
453
|
+
/* @__PURE__ */ C("div", {
|
|
454
|
+
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3",
|
|
455
|
+
children: $.pageItems.map((e) => /* @__PURE__ */ C(E, {
|
|
456
|
+
treatment: "glass",
|
|
457
|
+
className: "border-border-seam",
|
|
458
|
+
children: /* @__PURE__ */ w("button", {
|
|
459
|
+
type: "button",
|
|
460
|
+
onClick: () => P(e),
|
|
461
|
+
className: "flex h-full w-full flex-col gap-3 p-4 text-left",
|
|
462
|
+
children: [
|
|
463
|
+
/* @__PURE__ */ w("div", {
|
|
464
|
+
className: "flex flex-wrap items-center gap-1.5",
|
|
465
|
+
children: [/* @__PURE__ */ C(J, { status: e.status }), e.tags.slice(0, 1).map((e) => /* @__PURE__ */ C("span", {
|
|
466
|
+
className: "rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary",
|
|
467
|
+
children: e
|
|
468
|
+
}, e))]
|
|
469
|
+
}),
|
|
470
|
+
/* @__PURE__ */ C("h2", {
|
|
471
|
+
className: "line-clamp-2 text-base font-semibold text-text-primary",
|
|
472
|
+
children: e.title
|
|
473
|
+
}),
|
|
474
|
+
/* @__PURE__ */ C("p", {
|
|
475
|
+
className: "line-clamp-2 flex-1 text-sm text-text-secondary",
|
|
476
|
+
children: te(e)
|
|
477
|
+
}),
|
|
478
|
+
/* @__PURE__ */ w("div", {
|
|
479
|
+
className: "flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3",
|
|
480
|
+
children: [/* @__PURE__ */ w("div", {
|
|
481
|
+
className: "flex min-w-0 items-center gap-2",
|
|
482
|
+
children: [/* @__PURE__ */ C("span", {
|
|
483
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary",
|
|
484
|
+
children: e.updatedBy ? ne(e.updatedBy) : /* @__PURE__ */ C(v, { className: "h-3 w-3" })
|
|
485
|
+
}), /* @__PURE__ */ w("span", {
|
|
486
|
+
className: "truncate text-xs text-text-secondary",
|
|
487
|
+
children: ["Updated ", q(e.updatedAt)]
|
|
488
|
+
})]
|
|
489
|
+
}), /* @__PURE__ */ w("span", {
|
|
490
|
+
className: "flex shrink-0 items-center gap-1 text-xs text-text-muted tabular-nums",
|
|
491
|
+
children: [/* @__PURE__ */ C(m, { className: "h-3.5 w-3.5" }), e.views.toLocaleString()]
|
|
492
|
+
})]
|
|
493
|
+
})
|
|
494
|
+
]
|
|
495
|
+
})
|
|
496
|
+
}, e.id))
|
|
497
|
+
}),
|
|
498
|
+
/* @__PURE__ */ C("div", {
|
|
499
|
+
className: "mt-4",
|
|
500
|
+
children: /* @__PURE__ */ C(o, {
|
|
501
|
+
page: $.page,
|
|
502
|
+
pageCount: $.pageCount,
|
|
503
|
+
rangeStart: $.rangeStart,
|
|
504
|
+
rangeEnd: $.rangeEnd,
|
|
505
|
+
totalItems: $.totalItems,
|
|
506
|
+
canPrev: $.canPrev,
|
|
507
|
+
canNext: $.canNext,
|
|
508
|
+
onPrev: $.prevPage,
|
|
509
|
+
onNext: $.nextPage,
|
|
510
|
+
itemLabel: "articles"
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
] })]
|
|
514
|
+
})
|
|
515
|
+
]
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
//#endregion
|
|
519
|
+
export { Y as KnowledgeBasePage };
|
|
520
|
+
|
|
521
|
+
//# sourceMappingURL=KnowledgeBasePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnowledgeBasePage.js","names":[],"sources":["../../../src/assethandler/pages/KnowledgeBasePage.tsx"],"sourcesContent":["import { BookOpen, Plus, Search, Eye, User, Link2, ExternalLink } from 'lucide-react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n ChartCard,\n DonutChart,\n BarsChart,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst KNOWLEDGE_ARTICLES_QUERY = gql`\n query AssetHandlerKnowledgeArticles {\n knowledgeArticles {\n id\n title\n slug\n summary\n content\n status\n tags\n views\n createdBy\n updatedBy\n publishedAt\n createdAt\n updatedAt\n relatedAssetId\n relatedIncidentId\n }\n }\n`;\n\nconst CREATE_KNOWLEDGE_ARTICLE_MUTATION = gql`\n mutation AssetHandlerCreateKnowledgeArticle($input: CreateKnowledgeArticleInput!) {\n createKnowledgeArticle(input: $input) {\n id\n title\n }\n }\n`;\n\ninterface KnowledgeArticle {\n id: string;\n title: string;\n slug: string;\n summary: string | null;\n content: string;\n status: string;\n tags: string[];\n views: number;\n createdBy: string;\n updatedBy: string;\n publishedAt: string | null;\n createdAt: string;\n updatedAt: string;\n relatedAssetId: string | null;\n relatedIncidentId: string | null;\n}\n\ninterface CreateKnowledgeArticleResult {\n createKnowledgeArticle: { id: string; title: string };\n}\n\nconst ARTICLE_STATUSES = ['DRAFT', 'PUBLISHED', 'ARCHIVED'] as const;\n\nconst STATUS_META: Record<string, { label: string; className: string }> = {\n PUBLISHED: {\n label: 'Published',\n className: 'bg-status-success-bg-subtle text-status-success-text',\n },\n DRAFT: { label: 'Draft', className: 'bg-bg-sunken text-text-secondary' },\n ARCHIVED: {\n label: 'Archived',\n className: 'bg-status-warning-bg-subtle text-status-warning-text',\n },\n};\n\nconst slugify = (value: string): string =>\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n\nconst formatDate = (value: string | null): string =>\n value\n ? new Date(value).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n : '—';\n\n/** A 2-line excerpt: the summary if present, otherwise the opening of the body. */\nfunction excerptOf(article: KnowledgeArticle): string {\n if (article.summary && article.summary.trim()) return article.summary.trim();\n const body = article.content.replace(/\\s+/g, ' ').trim();\n return body.length > 160 ? `${body.slice(0, 160)}…` : body;\n}\n\n/** Short avatar initials from an actor id (best-effort, no fabricated names). */\nfunction initialsOf(actor: string): string {\n const clean = actor.replace(/[^a-zA-Z0-9]/g, '');\n return (clean.slice(0, 2) || '?').toUpperCase();\n}\n\nfunction StatusPill({ status }: { status: string }) {\n const meta = STATUS_META[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-secondary',\n };\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium',\n meta.className\n )}\n >\n {meta.label}\n </span>\n );\n}\n\nfunction PublishArticleDialog({\n open,\n onOpenChange,\n onPublished,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onPublished: () => void;\n}) {\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [slugTouched, setSlugTouched] = useState(false);\n const [summary, setSummary] = useState('');\n const [content, setContent] = useState('');\n const [tags, setTags] = useState('');\n const [status, setStatus] = useState<(typeof ARTICLE_STATUSES)[number]>('PUBLISHED');\n\n const reset = () => {\n setTitle('');\n setSlug('');\n setSlugTouched(false);\n setSummary('');\n setContent('');\n setTags('');\n setStatus('PUBLISHED');\n };\n\n const [createArticle, { loading }] = useMutation<CreateKnowledgeArticleResult>(\n CREATE_KNOWLEDGE_ARTICLE_MUTATION,\n {\n onCompleted: (data) => {\n notify.success(\n 'Article published',\n `${data.createKnowledgeArticle.title} is now available.`\n );\n reset();\n onOpenChange(false);\n onPublished();\n },\n onError: (error) => notify.error('Could not publish article', error.message),\n }\n );\n\n const handleTitleChange = (next: string) => {\n setTitle(next);\n if (!slugTouched) setSlug(slugify(next));\n };\n\n const handleSubmit = () => {\n if (!title.trim() || !slug.trim()) {\n notify.warning('Missing details', 'Title and slug are required.');\n return;\n }\n if (!content.trim()) {\n notify.warning('Body required', 'Write the article body before publishing.');\n return;\n }\n const parsedTags = tags\n .split(',')\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n void createArticle({\n variables: {\n input: {\n title: title.trim(),\n slug: slug.trim(),\n summary: summary.trim() || null,\n content: content.trim(),\n tags: parsedTags,\n status,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Article</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Capture a runbook or fix so your team can find it later.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Title *</Label>\n <Input value={title} onChange={(e) => handleTitleChange(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Slug *</Label>\n <Input\n value={slug}\n onChange={(e) => {\n setSlugTouched(true);\n setSlug(e.target.value);\n }}\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Summary</Label>\n <Input\n placeholder=\"One-line description\"\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Body *</Label>\n <Textarea\n placeholder=\"Write the full article body — steps, context, links…\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n rows={8}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category tags</Label>\n <Input\n placeholder=\"Runbooks, Fixes, Procedures…\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ARTICLE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? 'Publishing…' : 'Publish article'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nfunction ArticleReader({\n article,\n onOpenChange,\n}: {\n article: KnowledgeArticle | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const navigate = useAssetHandlerNavigate();\n return (\n <ResponsiveDialog open={Boolean(article)} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\">\n {article ? (\n <>\n <ResponsiveDialogHeader>\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusPill status={article.status} />\n {article.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {tag}\n </span>\n ))}\n </div>\n <ResponsiveDialogTitle className=\"mt-1\">{article.title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Updated {formatDate(article.updatedAt)} · {article.views.toLocaleString()} views\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-primary\">\n {article.content}\n </div>\n {article.relatedAssetId || article.relatedIncidentId ? (\n <div className=\"mt-4 space-y-2 border-t border-border-seam pt-4\">\n <h4 className=\"flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n <Link2 className=\"h-3.5 w-3.5\" />\n Linked records\n </h4>\n <div className=\"flex flex-wrap gap-2\">\n {article.relatedAssetId ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n onOpenChange(false);\n navigate(`/assets/${article.relatedAssetId}`);\n }}\n >\n View linked asset\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </Button>\n ) : null}\n {article.relatedIncidentId ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n onOpenChange(false);\n navigate(`/itil/incidents/${article.relatedIncidentId}`);\n }}\n >\n View linked incident\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </Button>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n ) : null}\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\ntype SortKey = 'recent' | 'views';\n\nexport function KnowledgeBasePage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const [search, setSearch] = useState('');\n const [category, setCategory] = useState<string>('ALL');\n const [statusFilter, setStatusFilter] = useState<string>('ALL');\n const [sort, setSort] = useState<SortKey>('recent');\n const [reading, setReading] = useState<KnowledgeArticle | null>(null);\n\n const { data, loading, refetch } = useQuery<{ knowledgeArticles: KnowledgeArticle[] }>(\n KNOWLEDGE_ARTICLES_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const articles = useMemo(() => data?.knowledgeArticles ?? [], [data?.knowledgeArticles]);\n\n const categories = useMemo(() => {\n const counts = new Map<string, number>();\n for (const a of articles) {\n for (const tag of a.tags) counts.set(tag, (counts.get(tag) ?? 0) + 1);\n }\n return [...counts.entries()].sort((a, b) => b[1] - a[1]);\n }, [articles]);\n\n const filtered = useMemo(() => {\n const term = search.trim().toLowerCase();\n const list = articles.filter((article) => {\n if (category !== 'ALL' && !article.tags.includes(category)) return false;\n if (statusFilter !== 'ALL' && article.status !== statusFilter) return false;\n if (!term) return true;\n const haystack = [\n article.title,\n article.summary ?? '',\n article.content,\n article.tags.join(' '),\n ]\n .join(' ')\n .toLowerCase();\n return haystack.includes(term);\n });\n return [...list].sort((a, b) =>\n sort === 'views'\n ? b.views - a.views\n : new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()\n );\n }, [articles, search, category, statusFilter, sort]);\n\n const statusMix = useMemo<DonutSlice[]>(() => {\n const counts = articles.reduce<Record<string, number>>((acc, a) => {\n acc[a.status] = (acc[a.status] ?? 0) + 1;\n return acc;\n }, {});\n return Object.entries(counts).map(([status, value], i) => ({\n name: STATUS_META[status]?.label ?? status,\n value,\n color: seriesColor(i),\n }));\n }, [articles]);\n\n const topByViews = useMemo(\n () =>\n [...articles]\n .filter((a) => a.views > 0)\n .sort((a, b) => b.views - a.views)\n .slice(0, 6)\n .map((a) => ({ name: a.title, views: a.views })),\n [articles]\n );\n\n const pagination = usePagination(filtered, {\n pageSize: 9,\n resetKey: `${search}|${category}|${statusFilter}|${sort}`,\n });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={BookOpen}\n title=\"Knowledge Base\"\n description=\"Turn one-off fixes and runbooks into repeatable, searchable operational knowledge.\"\n actions={\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n New Article\n </Button>\n }\n />\n <PagePurpose>\n Capture the fixes and runbooks your team relies on so the next person doesn't start\n from scratch. Link articles to incidents and assets, then search them when troubleshooting.\n </PagePurpose>\n\n <PublishArticleDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onPublished={() => void refetch()}\n />\n <ArticleReader article={reading} onOpenChange={(open) => !open && setReading(null)} />\n\n <div className=\"relative\">\n <Search className=\"absolute left-3.5 top-1/2 h-4.5 w-4.5 -translate-y-1/2 text-text-secondary\" />\n <Input\n className=\"h-12 pl-11 text-base\"\n placeholder=\"Search runbooks, fixes and procedures…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label=\"Search knowledge articles\"\n />\n </div>\n\n {articles.length > 0 && (statusMix.length > 0 || topByViews.length > 0) ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Publishing status\" subtitle=\"Articles by status\">\n <DonutChart\n data={statusMix}\n height={200}\n centerLabel=\"Articles\"\n centerValue={articles.length}\n ariaLabel=\"Articles by status\"\n />\n </ChartCard>\n <ChartCard title=\"Most consulted\" subtitle=\"Top articles by views\">\n <BarsChart\n data={topByViews}\n xKey=\"name\"\n series={[{ key: 'views', label: 'Views' }]}\n orientation=\"horizontal\"\n height={200}\n categoryWidth={150}\n emptyLabel=\"No views recorded yet\"\n ariaLabel=\"Top articles by views\"\n />\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"grid gap-5 lg:grid-cols-[200px_1fr]\">\n {/* Category facet rail */}\n <aside className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Category</h3>\n <Select value={sort} onValueChange={(v) => setSort(v as SortKey)}>\n <SelectTrigger className=\"h-8 w-[130px] text-xs lg:hidden\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"recent\">Recently updated</SelectItem>\n <SelectItem value=\"views\">Most viewed</SelectItem>\n </SelectContent>\n </Select>\n </div>\n {/* Mobile: horizontal chips; desktop: vertical list */}\n <div className=\"flex gap-2 overflow-x-auto pb-1 lg:flex-col lg:overflow-visible lg:pb-0\">\n <button\n type=\"button\"\n onClick={() => setCategory('ALL')}\n className={cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-left text-sm font-medium transition-colors lg:w-full',\n category === 'ALL'\n ? 'bg-action-primary-bg/10 text-primary'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n All articles\n <span className=\"ml-1.5 text-xs text-text-muted tabular-nums\">{articles.length}</span>\n </button>\n {categories.map(([tag, count]) => (\n <button\n key={tag}\n type=\"button\"\n onClick={() => setCategory(tag)}\n className={cn(\n 'flex shrink-0 items-center justify-between gap-2 rounded-md px-3 py-1.5 text-left text-sm font-medium transition-colors lg:w-full',\n category === tag\n ? 'bg-action-primary-bg/10 text-primary'\n : 'text-text-secondary hover:text-text-primary'\n )}\n >\n <span className=\"truncate\">{tag}</span>\n <span className=\"text-xs text-text-muted tabular-nums\">{count}</span>\n </button>\n ))}\n </div>\n <div className=\"hidden space-y-1.5 border-t border-border-seam pt-3 lg:block\">\n <Label className=\"text-xs\">Status</Label>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"h-9\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All statuses</SelectItem>\n {ARTICLE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Label className=\"text-xs\">Sort</Label>\n <Select value={sort} onValueChange={(v) => setSort(v as SortKey)}>\n <SelectTrigger className=\"h-9\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"recent\">Recently updated</SelectItem>\n <SelectItem value=\"views\">Most viewed</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </aside>\n\n {/* Article grid */}\n <div>\n {loading && articles.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div\n key={i}\n className=\"h-40 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : null}\n {!loading && filtered.length === 0 ? (\n <IllustratedEmptyState\n illustration={\n search || category !== 'ALL' || statusFilter !== 'ALL'\n ? 'empty-search'\n : 'empty-data'\n }\n title={\n search || category !== 'ALL' || statusFilter !== 'ALL'\n ? 'No articles match your filters'\n : 'No knowledge articles found'\n }\n description={\n search || category !== 'ALL' || statusFilter !== 'ALL'\n ? 'Try a different term, category or status.'\n : 'Publish an article to start building your knowledge base.'\n }\n />\n ) : null}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-3\">\n {pagination.pageItems.map((article) => (\n <GlassCard key={article.id} treatment=\"glass\" className=\"border-border-seam\">\n <button\n type=\"button\"\n onClick={() => setReading(article)}\n className=\"flex h-full w-full flex-col gap-3 p-4 text-left\"\n >\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusPill status={article.status} />\n {article.tags.slice(0, 1).map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-action-primary-bg/10 px-2 py-0.5 text-xs font-medium text-primary\"\n >\n {tag}\n </span>\n ))}\n </div>\n <h2 className=\"line-clamp-2 text-base font-semibold text-text-primary\">\n {article.title}\n </h2>\n <p className=\"line-clamp-2 flex-1 text-sm text-text-secondary\">\n {excerptOf(article)}\n </p>\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-[10px] font-semibold text-text-secondary\">\n {article.updatedBy ? (\n initialsOf(article.updatedBy)\n ) : (\n <User className=\"h-3 w-3\" />\n )}\n </span>\n <span className=\"truncate text-xs text-text-secondary\">\n Updated {formatDate(article.updatedAt)}\n </span>\n </div>\n <span className=\"flex shrink-0 items-center gap-1 text-xs text-text-muted tabular-nums\">\n <Eye className=\"h-3.5 w-3.5\" />\n {article.views.toLocaleString()}\n </span>\n </div>\n </button>\n </GlassCard>\n ))}\n </div>\n <div className=\"mt-4\">\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"articles\"\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|