@burdenoff/microfe-admin 2026.625.1 → 2026.712.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/admin/AdminRoot.js +2 -2
- package/dist/admin/AdminRoot.js.map +1 -1
- package/dist/admin/AdminRoutes.js +130 -78
- package/dist/admin/AdminRoutes.js.map +1 -1
- package/dist/admin/components/AccessDenied.js +2 -2
- package/dist/admin/components/AccessDenied.js.map +1 -1
- package/dist/admin/components/ActivityFeed.js +4 -4
- package/dist/admin/components/ActivityFeed.js.map +1 -1
- package/dist/admin/components/Charts.js.map +1 -1
- package/dist/admin/components/ConfirmDialog.js +1 -1
- package/dist/admin/components/ConfirmDialog.js.map +1 -1
- package/dist/admin/components/DataTable.js.map +1 -1
- package/dist/admin/components/FormSheet.js +1 -1
- package/dist/admin/components/FormSheet.js.map +1 -1
- package/dist/admin/components/TenantSsoPanel.js +1 -1
- package/dist/admin/components/TenantSsoPanel.js.map +1 -1
- package/dist/admin/components/Toast.js +11 -11
- package/dist/admin/components/Toast.js.map +1 -1
- package/dist/admin/components/forms/SubscriptionForm.js +2 -2
- package/dist/admin/components/forms/SubscriptionForm.js.map +1 -1
- package/dist/admin/components/forms/TenantForm.js +1 -1
- package/dist/admin/components/forms/UserForm.js +1 -1
- package/dist/admin/components/ui.js +3 -3
- package/dist/admin/components/ui.js.map +1 -1
- package/dist/admin/constants/featureFlags.js +12 -0
- package/dist/admin/constants/featureFlags.js.map +1 -0
- package/dist/admin/constants/index.js +33 -24
- package/dist/admin/constants/index.js.map +1 -1
- package/dist/admin/pages/AuditLogsPage.js +92 -77
- package/dist/admin/pages/AuditLogsPage.js.map +1 -1
- package/dist/admin/pages/BillingPage.js +95 -51
- package/dist/admin/pages/BillingPage.js.map +1 -1
- package/dist/admin/pages/CommunicationsPage.js +97 -92
- package/dist/admin/pages/CommunicationsPage.js.map +1 -1
- package/dist/admin/pages/ContentPagesPage.js +274 -259
- package/dist/admin/pages/ContentPagesPage.js.map +1 -1
- package/dist/admin/pages/DashboardPage.js +113 -84
- package/dist/admin/pages/DashboardPage.js.map +1 -1
- package/dist/admin/pages/FeatureFlagsPage.js +93 -75
- package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
- package/dist/admin/pages/OrganizationsListPage.js +105 -87
- package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
- package/dist/admin/pages/ProductsPage.js +138 -130
- package/dist/admin/pages/ProductsPage.js.map +1 -1
- package/dist/admin/pages/ReferralsPage.js +70 -52
- package/dist/admin/pages/ReferralsPage.js.map +1 -1
- package/dist/admin/pages/RolesPermissionsPage.js +136 -118
- package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
- package/dist/admin/pages/SREPage.js +34 -32
- package/dist/admin/pages/SREPage.js.map +1 -1
- package/dist/admin/pages/SandboxSettingsPage.js +360 -322
- package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage.js +64 -61
- package/dist/admin/pages/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SyncFailuresPage.js +120 -118
- package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
- package/dist/admin/pages/TenantDetailPage.js +286 -231
- package/dist/admin/pages/TenantDetailPage.js.map +1 -1
- package/dist/admin/pages/TenantFormRoutePage.js +78 -73
- package/dist/admin/pages/TenantFormRoutePage.js.map +1 -1
- package/dist/admin/pages/TenantsListPage.js +182 -155
- package/dist/admin/pages/TenantsListPage.js.map +1 -1
- package/dist/admin/pages/UsersListPage.js +128 -113
- package/dist/admin/pages/UsersListPage.js.map +1 -1
- package/dist/admin/pages/WaitlistPage.js +78 -63
- package/dist/admin/pages/WaitlistPage.js.map +1 -1
- package/dist/admin/pages/WorkflowsPage.js +107 -102
- package/dist/admin/pages/WorkflowsPage.js.map +1 -1
- package/dist/admin/pages/WorkspacesListPage.js +61 -49
- package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
- package/dist/node_modules/@hookform/resolvers/dist/resolvers.js +2 -2
- package/dist/node_modules/@hookform/resolvers/dist/resolvers.js.map +1 -1
- package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js +35 -26
- package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js.map +1 -1
- package/dist/node_modules/react-hook-form/dist/index.esm.js +609 -516
- package/dist/node_modules/react-hook-form/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RolesPermissionsPage.js","names":[],"sources":["../../../src/admin/pages/RolesPermissionsPage.tsx"],"sourcesContent":["import { Shield, Search, Plus, Pencil, Trash2 } from 'lucide-react';\nimport { useState, useMemo } from 'react';\nimport { PageLayout, Input, Button, EmptyState, DataTable, Badge, RowActions } from '../components';\nimport { useListRolesQuery, useGetResourceTypesQuery } from '../../generated/global-operations';\n\nexport function RolesPermissionsPage() {\n const [searchQuery, setSearchQuery] = useState('');\n\n const {\n data: rolesData,\n loading: rolesLoading,\n error: rolesError,\n } = useListRolesQuery({\n variables: { scopeId: 'global' },\n });\n\n const { data: resourceTypesData } = useGetResourceTypesQuery();\n\n const roles = useMemo(() => rolesData?.roles ?? [], [rolesData]);\n\n const filteredRoles = useMemo(() => {\n if (!searchQuery.trim()) return roles;\n const query = searchQuery.toLowerCase();\n return roles.filter(\n (role: any) =>\n role.name.toLowerCase().includes(query) || role.description?.toLowerCase().includes(query)\n );\n }, [roles, searchQuery]);\n\n const columns = [\n {\n key: 'name',\n header: 'Role Name',\n render: (role: any) => (\n <div className=\"flex flex-col text-left\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-semibold text-text-primary\">{role.name}</span>\n {role.isSystem && (\n <Badge variant=\"secondary\" className=\"h-4 px-1 text-[10px]\">\n System\n </Badge>\n )}\n </div>\n {role.description && (\n <span className=\"mt-0.5 line-clamp-1 text-xs text-text-secondary\">\n {role.description}\n </span>\n )}\n </div>\n ),\n },\n {\n key: 'priority',\n header: 'Priority',\n align: 'center' as const,\n width: '80px',\n render: (role: any) => (\n <span className=\"rounded bg-bg-sunken px-2 py-0.5 text-xs font-medium\"
|
|
1
|
+
{"version":3,"file":"RolesPermissionsPage.js","names":[],"sources":["../../../src/admin/pages/RolesPermissionsPage.tsx"],"sourcesContent":["import { Shield, Search, Plus, Pencil, Trash2 } from 'lucide-react';\nimport { useState, useMemo } from 'react';\nimport { PageLayout, Input, Button, EmptyState, DataTable, Badge, RowActions } from '../components';\nimport { PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { useListRolesQuery, useGetResourceTypesQuery } from '../../generated/global-operations';\n\nexport function RolesPermissionsPage() {\n const [searchQuery, setSearchQuery] = useState('');\n\n const {\n data: rolesData,\n loading: rolesLoading,\n error: rolesError,\n } = useListRolesQuery({\n variables: { scopeId: 'global' },\n });\n\n const { data: resourceTypesData } = useGetResourceTypesQuery();\n\n const roles = useMemo(() => rolesData?.roles ?? [], [rolesData]);\n\n const filteredRoles = useMemo(() => {\n if (!searchQuery.trim()) return roles;\n const query = searchQuery.toLowerCase();\n return roles.filter(\n (role: any) =>\n role.name.toLowerCase().includes(query) || role.description?.toLowerCase().includes(query)\n );\n }, [roles, searchQuery]);\n\n const columns = [\n {\n key: 'name',\n header: 'Role Name',\n render: (role: any) => (\n <div className=\"flex flex-col text-left\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-semibold text-text-primary\">{role.name}</span>\n {role.isSystem && (\n <Badge variant=\"secondary\" className=\"h-4 px-1 text-[10px]\">\n System\n </Badge>\n )}\n </div>\n {role.description && (\n <span className=\"mt-0.5 line-clamp-1 text-xs text-text-secondary\">\n {role.description}\n </span>\n )}\n </div>\n ),\n },\n {\n key: 'priority',\n header: 'Priority',\n align: 'center' as const,\n width: '80px',\n render: (role: any) => (\n <span className=\"rounded bg-bg-sunken px-2 py-0.5 text-xs font-medium\">\n {role.priority}\n </span>\n ),\n },\n {\n key: 'permissions',\n header: 'Default Permissions',\n render: (role: any) => (\n <div className=\"flex max-w-md flex-wrap gap-1 text-left\">\n {role.defaultPermissions && role.defaultPermissions.length > 0 ? (\n role.defaultPermissions.map((perm: any) => (\n <Badge\n key={perm.id}\n variant=\"outline\"\n className=\"bg-bg-surface/50 px-1 py-0 font-normal text-[10px]\"\n >\n <span className=\"mr-1 text-text-secondary\">{perm.resourceType}:</span>\n <span className=\"font-medium\">{perm.level}</span>\n </Badge>\n ))\n ) : (\n <span className=\"text-xs italic text-text-secondary\">No permissions defined</span>\n )}\n </div>\n ),\n },\n {\n key: 'actions',\n header: '',\n align: 'right' as const,\n width: '50px',\n render: (role: any) => (\n <RowActions\n actions={[\n {\n key: 'edit',\n label: 'Edit Role',\n icon: <Pencil className=\"h-4 w-4\" />,\n onClick: () => console.log('Edit', role.id),\n disabled: role.isSystem,\n },\n {\n key: 'delete',\n label: 'Delete Role',\n icon: <Trash2 className=\"h-4 w-4\" />,\n onClick: () => console.log('Delete', role.id),\n destructive: true,\n disabled: role.isSystem,\n separator: true,\n },\n ]}\n />\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"Roles & Permissions\"\n gradientWord=\"Permissions\"\n description=\"Manage platform roles and global permissions\"\n actions={\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n Create Role\n </Button>\n }\n >\n <div className=\"space-y-4\">\n <PagePurpose>\n Roles bundle together the permissions a person can hold across the platform. Use this page\n to review what each role can do, create new roles for different kinds of operators, and\n keep least-privilege access tidy as your team grows.\n </PagePurpose>\n\n {/* Emphasis: how many roles are defined platform-wide. */}\n <EmphasisPanel className=\"flex items-center gap-4 p-5\">\n <div className=\"flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-action-primary-bg/15 text-action-primary-bg\">\n <Shield className=\"h-6 w-6\" />\n </div>\n <div>\n <div className=\"text-3xl font-bold tabular-nums text-text-primary\">{roles.length}</div>\n <p className=\"text-sm text-text-secondary\">roles defined platform-wide</p>\n </div>\n </EmphasisPanel>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"relative flex-1 max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search roles...\"\n className=\"pl-9\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\" className=\"h-8\">\n {resourceTypesData?.resourceTypes?.length ?? 0} Resource Types\n </Badge>\n </div>\n </div>\n\n {rolesError ? (\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Shield className=\"h-8 w-8 text-status-error-text\" />}\n title=\"Error loading roles\"\n description={rolesError.message}\n />\n ) : (\n <DataTable\n columns={columns}\n data={filteredRoles}\n keyExtractor={(role) => role.id}\n loading={rolesLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-people\"\n icon={<Shield className=\"h-8 w-8\" />}\n title=\"No roles found\"\n description={\n searchQuery\n ? `No roles match \"${searchQuery}\"`\n : 'Roles and permissions will appear here when they are created'\n }\n action={\n searchQuery ? (\n <Button variant=\"outline\" size=\"sm\" onClick={() => setSearchQuery('')}>\n Clear Search\n </Button>\n ) : undefined\n }\n />\n }\n />\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -10,8 +10,9 @@ import "../components/index.js";
|
|
|
10
10
|
import { useState as g } from "react";
|
|
11
11
|
import { Activity as _, AlertTriangle as v, CheckCircle2 as y, Cpu as b, Database as x, HardDrive as S, RefreshCw as C, Server as w, TrendingUp as T, Wifi as E } from "lucide-react";
|
|
12
12
|
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
13
|
+
import { PagePurpose as k } from "@burdenoff/fe-libs/ui";
|
|
13
14
|
//#region src/admin/pages/SREPage.tsx
|
|
14
|
-
var
|
|
15
|
+
var A = [
|
|
15
16
|
{
|
|
16
17
|
id: "s1",
|
|
17
18
|
name: "wspace-public-gateway",
|
|
@@ -111,7 +112,7 @@ var k = [
|
|
|
111
112
|
lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
|
|
112
113
|
region: "ap-south-1"
|
|
113
114
|
}
|
|
114
|
-
],
|
|
115
|
+
], j = [{
|
|
115
116
|
id: "inc-1",
|
|
116
117
|
title: "Elevated latency on billing service",
|
|
117
118
|
severity: "major",
|
|
@@ -126,7 +127,7 @@ var k = [
|
|
|
126
127
|
affectedServices: ["postgresql-primary"],
|
|
127
128
|
startedAt: (/* @__PURE__ */ new Date(Date.now() - 14400 * 1e3)).toISOString(),
|
|
128
129
|
resolvedAt: (/* @__PURE__ */ new Date(Date.now() - 10800 * 1e3)).toISOString()
|
|
129
|
-
}],
|
|
130
|
+
}], M = [
|
|
130
131
|
{
|
|
131
132
|
id: "d1",
|
|
132
133
|
service: "wspace-tags-svc",
|
|
@@ -163,21 +164,21 @@ var k = [
|
|
|
163
164
|
deployedBy: "fluxcd",
|
|
164
165
|
duration: 110
|
|
165
166
|
}
|
|
166
|
-
],
|
|
167
|
+
], N = {
|
|
167
168
|
api: /* @__PURE__ */ D(w, { className: "h-4 w-4" }),
|
|
168
169
|
worker: /* @__PURE__ */ D(b, { className: "h-4 w-4" }),
|
|
169
170
|
database: /* @__PURE__ */ D(x, { className: "h-4 w-4" }),
|
|
170
171
|
cache: /* @__PURE__ */ D(S, { className: "h-4 w-4" }),
|
|
171
172
|
queue: /* @__PURE__ */ D(E, { className: "h-4 w-4" })
|
|
172
|
-
},
|
|
173
|
-
critical: "bg-status-error-bg
|
|
174
|
-
major: "bg-warning
|
|
175
|
-
minor: "bg-bg
|
|
173
|
+
}, P = {
|
|
174
|
+
critical: "bg-status-error-bg text-status-error-text",
|
|
175
|
+
major: "bg-status-warning-bg text-status-warning-text",
|
|
176
|
+
minor: "bg-status-neutral-bg text-status-neutral-text"
|
|
176
177
|
};
|
|
177
|
-
function
|
|
178
|
-
let { canViewSRE: b, isLoading: x } = e(), [S, E] = g(!1),
|
|
179
|
-
|
|
180
|
-
let
|
|
178
|
+
function F() {
|
|
179
|
+
let { canViewSRE: b, isLoading: x } = e(), [S, E] = g(!1), F = A.filter((e) => e.status === "healthy").length, I = A.filter((e) => e.status === "degraded").length;
|
|
180
|
+
A.filter((e) => e.status === "down").length;
|
|
181
|
+
let L = A.reduce((e, t) => e + t.uptime, 0) / A.length, R = A.reduce((e, t) => e + t.latency, 0) / A.length, z = j.filter((e) => e.status !== "resolved").length;
|
|
181
182
|
return /* @__PURE__ */ D(h, {
|
|
182
183
|
allowed: b,
|
|
183
184
|
isLoading: x,
|
|
@@ -198,44 +199,45 @@ function P() {
|
|
|
198
199
|
children: /* @__PURE__ */ O("div", {
|
|
199
200
|
className: "space-y-6",
|
|
200
201
|
children: [
|
|
202
|
+
/* @__PURE__ */ D(k, { children: "A live view of platform reliability. Watch the health, uptime and latency of every service, keep an eye on active incidents, and catch a degraded component before it turns into an outage your users notice." }),
|
|
201
203
|
/* @__PURE__ */ O(p, { children: [
|
|
202
204
|
/* @__PURE__ */ D(f, {
|
|
203
205
|
title: "Healthy Services",
|
|
204
206
|
hero: !0,
|
|
205
|
-
value:
|
|
206
|
-
icon: /* @__PURE__ */ D(y, { className: "h-5 w-5 text-success" }),
|
|
207
|
-
subtitle: `of ${
|
|
207
|
+
value: F,
|
|
208
|
+
icon: /* @__PURE__ */ D(y, { className: "h-5 w-5 text-status-success-text" }),
|
|
209
|
+
subtitle: `of ${A.length} total`
|
|
208
210
|
}),
|
|
209
211
|
/* @__PURE__ */ D(f, {
|
|
210
212
|
title: "Degraded",
|
|
211
|
-
value:
|
|
212
|
-
icon: /* @__PURE__ */ D(v, { className: "h-5 w-5 text-warning" }),
|
|
213
|
-
priority:
|
|
213
|
+
value: I,
|
|
214
|
+
icon: /* @__PURE__ */ D(v, { className: "h-5 w-5 text-status-warning-text" }),
|
|
215
|
+
priority: I > 0 ? "high" : "normal"
|
|
214
216
|
}),
|
|
215
217
|
/* @__PURE__ */ D(f, {
|
|
216
218
|
title: "Avg Uptime",
|
|
217
|
-
value: `${
|
|
219
|
+
value: `${L.toFixed(2)}%`,
|
|
218
220
|
icon: /* @__PURE__ */ D(T, { className: "h-5 w-5" })
|
|
219
221
|
}),
|
|
220
222
|
/* @__PURE__ */ D(f, {
|
|
221
223
|
title: "Avg Latency",
|
|
222
|
-
value: `${
|
|
224
|
+
value: `${R.toFixed(0)}ms`,
|
|
223
225
|
icon: /* @__PURE__ */ D(_, { className: "h-5 w-5" })
|
|
224
226
|
})
|
|
225
227
|
] }),
|
|
226
|
-
|
|
227
|
-
className: "border-warning
|
|
228
|
+
z > 0 && /* @__PURE__ */ O(r, {
|
|
229
|
+
className: "border-status-warning-border bg-status-warning-bg",
|
|
228
230
|
children: [/* @__PURE__ */ D(a, { children: /* @__PURE__ */ O(o, {
|
|
229
|
-
className: "text-lg flex items-center gap-2 text-warning",
|
|
231
|
+
className: "text-lg flex items-center gap-2 text-status-warning-text",
|
|
230
232
|
children: [
|
|
231
233
|
/* @__PURE__ */ D(v, { className: "h-5 w-5" }),
|
|
232
234
|
"Active Incidents (",
|
|
233
|
-
|
|
235
|
+
z,
|
|
234
236
|
")"
|
|
235
237
|
]
|
|
236
238
|
}) }), /* @__PURE__ */ D(i, { children: /* @__PURE__ */ D("div", {
|
|
237
239
|
className: "space-y-3",
|
|
238
|
-
children:
|
|
240
|
+
children: j.filter((e) => e.status !== "resolved").map((e) => /* @__PURE__ */ O("div", {
|
|
239
241
|
className: "flex items-start justify-between rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
240
242
|
children: [/* @__PURE__ */ O("div", {
|
|
241
243
|
className: "space-y-1",
|
|
@@ -243,7 +245,7 @@ function P() {
|
|
|
243
245
|
/* @__PURE__ */ O("div", {
|
|
244
246
|
className: "flex items-center gap-2",
|
|
245
247
|
children: [/* @__PURE__ */ D(t, {
|
|
246
|
-
className:
|
|
248
|
+
className: P[e.severity],
|
|
247
249
|
children: e.severity.toUpperCase()
|
|
248
250
|
}), /* @__PURE__ */ D("span", {
|
|
249
251
|
className: "font-medium",
|
|
@@ -285,7 +287,7 @@ function P() {
|
|
|
285
287
|
header: "Service",
|
|
286
288
|
render: (e) => /* @__PURE__ */ O("div", {
|
|
287
289
|
className: "flex items-center gap-2",
|
|
288
|
-
children: [
|
|
290
|
+
children: [N[e.type], /* @__PURE__ */ D("span", {
|
|
289
291
|
className: "font-medium",
|
|
290
292
|
children: e.name
|
|
291
293
|
})]
|
|
@@ -303,7 +305,7 @@ function P() {
|
|
|
303
305
|
width: "100px",
|
|
304
306
|
align: "right",
|
|
305
307
|
render: (e) => /* @__PURE__ */ O("span", {
|
|
306
|
-
className: e.uptime < 99 ? "text-warning" : "text-success",
|
|
308
|
+
className: e.uptime < 99 ? "text-status-warning-text" : "text-status-success-text",
|
|
307
309
|
children: [e.uptime.toFixed(2), "%"]
|
|
308
310
|
})
|
|
309
311
|
},
|
|
@@ -313,7 +315,7 @@ function P() {
|
|
|
313
315
|
width: "100px",
|
|
314
316
|
align: "right",
|
|
315
317
|
render: (e) => /* @__PURE__ */ O("span", {
|
|
316
|
-
className: e.latency > 100 ? "text-warning" : "",
|
|
318
|
+
className: e.latency > 100 ? "text-status-warning-text" : "",
|
|
317
319
|
children: [e.latency, "ms"]
|
|
318
320
|
})
|
|
319
321
|
},
|
|
@@ -337,7 +339,7 @@ function P() {
|
|
|
337
339
|
})
|
|
338
340
|
}
|
|
339
341
|
],
|
|
340
|
-
data:
|
|
342
|
+
data: A,
|
|
341
343
|
keyExtractor: (e) => e.id,
|
|
342
344
|
emptyState: /* @__PURE__ */ D(s, {
|
|
343
345
|
illustration: "empty-data",
|
|
@@ -390,7 +392,7 @@ function P() {
|
|
|
390
392
|
})
|
|
391
393
|
}
|
|
392
394
|
],
|
|
393
|
-
data:
|
|
395
|
+
data: M,
|
|
394
396
|
keyExtractor: (e) => e.id,
|
|
395
397
|
emptyState: /* @__PURE__ */ D(s, {
|
|
396
398
|
illustration: "empty-data",
|
|
@@ -404,6 +406,6 @@ function P() {
|
|
|
404
406
|
});
|
|
405
407
|
}
|
|
406
408
|
//#endregion
|
|
407
|
-
export {
|
|
409
|
+
export { F as SREPage };
|
|
408
410
|
|
|
409
411
|
//# sourceMappingURL=SREPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SREPage.js","names":[],"sources":["../../../src/admin/pages/SREPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Activity,\n Server,\n Database,\n Cpu,\n HardDrive,\n Wifi,\n AlertTriangle,\n CheckCircle2,\n RefreshCw,\n TrendingUp,\n} from 'lucide-react';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n MetricCard,\n MetricsGrid,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Button,\n EmptyState,\n DataTable,\n HealthStatusBadge,\n DeploymentStatusBadge,\n PermissionGuard,\n} from '../components';\nimport { formatRelativeTime } from '../utils/formatters';\n\n/**\n * Service health entity\n */\ninterface ServiceHealth {\n id: string;\n name: string;\n type: 'api' | 'worker' | 'database' | 'cache' | 'queue';\n status: 'healthy' | 'degraded' | 'down';\n uptime: number; // percentage\n latency: number; // ms\n errorRate: number; // percentage\n lastChecked: string;\n region: string;\n}\n\n/**\n * Incident entity\n */\ninterface Incident {\n id: string;\n title: string;\n severity: 'critical' | 'major' | 'minor';\n status: 'active' | 'investigating' | 'resolved';\n affectedServices: string[];\n startedAt: string;\n resolvedAt?: string;\n}\n\n/**\n * Deployment entity\n */\ninterface Deployment {\n id: string;\n service: string;\n version: string;\n status: 'success' | 'failed' | 'in_progress' | 'rolled_back';\n deployedAt: string;\n deployedBy: string;\n duration: number; // seconds\n}\n\n// Mock data\nconst mockServices: ServiceHealth[] = [\n {\n id: 's1',\n name: 'wspace-public-gateway',\n type: 'api',\n status: 'healthy',\n uptime: 99.99,\n latency: 45,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's2',\n name: 'global-auth-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.95,\n latency: 32,\n errorRate: 0.02,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's3',\n name: 'wspace-tags-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.98,\n latency: 28,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's4',\n name: 'global-billing-svc',\n type: 'api',\n status: 'degraded',\n uptime: 98.5,\n latency: 250,\n errorRate: 2.5,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's5',\n name: 'wspace-calendar-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.97,\n latency: 35,\n errorRate: 0.03,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's6',\n name: 'postgresql-primary',\n type: 'database',\n status: 'healthy',\n uptime: 99.999,\n latency: 5,\n errorRate: 0,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's7',\n name: 'valkey-cluster',\n type: 'cache',\n status: 'healthy',\n uptime: 99.99,\n latency: 2,\n errorRate: 0,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's8',\n name: 'nats-cluster',\n type: 'queue',\n status: 'healthy',\n uptime: 99.98,\n latency: 8,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's9',\n name: 'temporal-worker',\n type: 'worker',\n status: 'healthy',\n uptime: 99.95,\n latency: 15,\n errorRate: 0.05,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n];\n\nconst mockIncidents: Incident[] = [\n {\n id: 'inc-1',\n title: 'Elevated latency on billing service',\n severity: 'major',\n status: 'investigating',\n affectedServices: ['global-billing-svc'],\n startedAt: new Date(Date.now() - 30 * 60 * 1000).toISOString(),\n },\n {\n id: 'inc-2',\n title: 'Intermittent database connection errors',\n severity: 'minor',\n status: 'resolved',\n affectedServices: ['postgresql-primary'],\n startedAt: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(),\n resolvedAt: new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString(),\n },\n];\n\nconst mockDeployments: Deployment[] = [\n {\n id: 'd1',\n service: 'wspace-tags-svc',\n version: '2025.01.18.1',\n status: 'success',\n deployedAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 120,\n },\n {\n id: 'd2',\n service: 'global-auth-svc',\n version: '2025.01.18.0',\n status: 'success',\n deployedAt: new Date(Date.now() - 5 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 95,\n },\n {\n id: 'd3',\n service: 'wspace-calendar-svc',\n version: '2025.01.17.2',\n status: 'rolled_back',\n deployedAt: new Date(Date.now() - 12 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 180,\n },\n {\n id: 'd4',\n service: 'global-billing-svc',\n version: '2025.01.17.1',\n status: 'success',\n deployedAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 110,\n },\n];\n\nconst typeIcons: Record<string, React.ReactNode> = {\n api: <Server className=\"h-4 w-4\" />,\n worker: <Cpu className=\"h-4 w-4\" />,\n database: <Database className=\"h-4 w-4\" />,\n cache: <HardDrive className=\"h-4 w-4\" />,\n queue: <Wifi className=\"h-4 w-4\" />,\n};\n\nconst severityColors: Record<string, string> = {\n critical: 'bg-status-error-bg/10 text-status-error-text',\n major: 'bg-warning/10 text-warning',\n minor: 'bg-bg-sunken text-text-secondary',\n};\n\n/**\n * SRE Monitoring page\n */\nexport function SREPage() {\n const { canViewSRE, isLoading: permissionsLoading } = useAdminPermissions();\n\n const [refreshing, setRefreshing] = useState(false);\n\n // Calculate metrics\n const healthyServices = mockServices.filter((s) => s.status === 'healthy').length;\n const degradedServices = mockServices.filter((s) => s.status === 'degraded').length;\n // Note: downServices available for future use when we have down services\n const _downServices = mockServices.filter((s) => s.status === 'down').length;\n void _downServices;\n const avgUptime = mockServices.reduce((sum, s) => sum + s.uptime, 0) / mockServices.length;\n const avgLatency = mockServices.reduce((sum, s) => sum + s.latency, 0) / mockServices.length;\n const activeIncidents = mockIncidents.filter((i) => i.status !== 'resolved').length;\n\n const handleRefresh = () => {\n setRefreshing(true);\n setTimeout(() => setRefreshing(false), 1000);\n };\n\n const serviceColumns = [\n {\n key: 'name',\n header: 'Service',\n render: (service: ServiceHealth) => (\n <div className=\"flex items-center gap-2\">\n {typeIcons[service.type]}\n <span className=\"font-medium\">{service.name}</span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '100px',\n render: (service: ServiceHealth) => <HealthStatusBadge status={service.status} />,\n },\n {\n key: 'uptime',\n header: 'Uptime',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span className={service.uptime < 99 ? 'text-warning' : 'text-success'}>\n {service.uptime.toFixed(2)}%\n </span>\n ),\n },\n {\n key: 'latency',\n header: 'Latency',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span className={service.latency > 100 ? 'text-warning' : ''}>{service.latency}ms</span>\n ),\n },\n {\n key: 'errorRate',\n header: 'Error Rate',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span className={service.errorRate > 1 ? 'text-status-error-text' : ''}>\n {service.errorRate.toFixed(2)}%\n </span>\n ),\n },\n {\n key: 'region',\n header: 'Region',\n width: '120px',\n render: (service: ServiceHealth) => (\n <span className=\"text-text-secondary\">{service.region}</span>\n ),\n },\n ];\n\n const deploymentColumns = [\n {\n key: 'service',\n header: 'Service',\n render: (d: Deployment) => <span className=\"font-medium\">{d.service}</span>,\n },\n {\n key: 'version',\n header: 'Version',\n width: '140px',\n render: (d: Deployment) => (\n <code className=\"text-xs bg-bg-sunken px-1.5 py-0.5 rounded\">{d.version}</code>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '120px',\n render: (d: Deployment) => <DeploymentStatusBadge status={d.status} />,\n },\n {\n key: 'duration',\n header: 'Duration',\n width: '100px',\n align: 'right' as const,\n render: (d: Deployment) => `${d.duration}s`,\n },\n {\n key: 'deployedAt',\n header: 'Deployed',\n width: '140px',\n render: (d: Deployment) => (\n <span className=\"text-text-secondary\">{formatRelativeTime(d.deployedAt)}</span>\n ),\n },\n ];\n\n return (\n <PermissionGuard\n allowed={canViewSRE}\n isLoading={permissionsLoading}\n pageTitle=\"SRE Monitoring\"\n denyMessage=\"You don't have permission to view SRE monitoring.\"\n >\n <PageLayout\n title=\"SRE Monitoring\"\n gradientWord=\"Monitoring\"\n description=\"Service health, incidents, and deployment monitoring\"\n actions={\n <Button variant=\"outline\" onClick={handleRefresh} disabled={refreshing}>\n <RefreshCw className={`mr-2 h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />\n Refresh\n </Button>\n }\n >\n <div className=\"space-y-6\">\n {/* Metrics */}\n <MetricsGrid>\n <MetricCard\n title=\"Healthy Services\"\n hero\n value={healthyServices}\n icon={<CheckCircle2 className=\"h-5 w-5 text-success\" />}\n subtitle={`of ${mockServices.length} total`}\n />\n <MetricCard\n title=\"Degraded\"\n value={degradedServices}\n icon={<AlertTriangle className=\"h-5 w-5 text-warning\" />}\n priority={degradedServices > 0 ? 'high' : 'normal'}\n />\n <MetricCard\n title=\"Avg Uptime\"\n value={`${avgUptime.toFixed(2)}%`}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <MetricCard\n title=\"Avg Latency\"\n value={`${avgLatency.toFixed(0)}ms`}\n icon={<Activity className=\"h-5 w-5\" />}\n />\n </MetricsGrid>\n\n {/* Active Incidents */}\n {activeIncidents > 0 && (\n <Card className=\"border-warning/50 bg-warning/5\">\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2 text-warning\">\n <AlertTriangle className=\"h-5 w-5\" />\n Active Incidents ({activeIncidents})\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {mockIncidents\n .filter((i) => i.status !== 'resolved')\n .map((incident) => (\n <div\n key={incident.id}\n className=\"flex items-start justify-between rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge className={severityColors[incident.severity]}>\n {incident.severity.toUpperCase()}\n </Badge>\n <span className=\"font-medium\">{incident.title}</span>\n </div>\n <div className=\"flex items-center gap-4 text-sm text-text-secondary\">\n <span>Started {formatRelativeTime(incident.startedAt)}</span>\n <span>•</span>\n <span>Status: {incident.status}</span>\n </div>\n <div className=\"flex flex-wrap gap-1 mt-2\">\n {incident.affectedServices.map((svc) => (\n <Badge key={svc} variant=\"outline\" className=\"text-xs\">\n {svc}\n </Badge>\n ))}\n </div>\n </div>\n <Button size=\"sm\" variant=\"outline\">\n View\n </Button>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Service Health */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2\">\n <Server className=\"h-5 w-5\" />\n Service Health\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={serviceColumns}\n data={mockServices}\n keyExtractor={(s) => s.id}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<Server className=\"h-8 w-8\" />}\n title=\"No services found\"\n />\n }\n />\n </CardContent>\n </Card>\n\n {/* Recent Deployments */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2\">\n <RefreshCw className=\"h-5 w-5\" />\n Recent Deployments\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={deploymentColumns}\n data={mockDeployments}\n keyExtractor={(d) => d.id}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<RefreshCw className=\"h-8 w-8\" />}\n title=\"No recent deployments\"\n />\n }\n />\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SREPage.js","names":[],"sources":["../../../src/admin/pages/SREPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Activity,\n Server,\n Database,\n Cpu,\n HardDrive,\n Wifi,\n AlertTriangle,\n CheckCircle2,\n RefreshCw,\n TrendingUp,\n} from 'lucide-react';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n MetricCard,\n MetricsGrid,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Button,\n EmptyState,\n DataTable,\n HealthStatusBadge,\n DeploymentStatusBadge,\n PermissionGuard,\n} from '../components';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\n\n/**\n * Service health entity\n */\ninterface ServiceHealth {\n id: string;\n name: string;\n type: 'api' | 'worker' | 'database' | 'cache' | 'queue';\n status: 'healthy' | 'degraded' | 'down';\n uptime: number; // percentage\n latency: number; // ms\n errorRate: number; // percentage\n lastChecked: string;\n region: string;\n}\n\n/**\n * Incident entity\n */\ninterface Incident {\n id: string;\n title: string;\n severity: 'critical' | 'major' | 'minor';\n status: 'active' | 'investigating' | 'resolved';\n affectedServices: string[];\n startedAt: string;\n resolvedAt?: string;\n}\n\n/**\n * Deployment entity\n */\ninterface Deployment {\n id: string;\n service: string;\n version: string;\n status: 'success' | 'failed' | 'in_progress' | 'rolled_back';\n deployedAt: string;\n deployedBy: string;\n duration: number; // seconds\n}\n\n// Mock data\nconst mockServices: ServiceHealth[] = [\n {\n id: 's1',\n name: 'wspace-public-gateway',\n type: 'api',\n status: 'healthy',\n uptime: 99.99,\n latency: 45,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's2',\n name: 'global-auth-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.95,\n latency: 32,\n errorRate: 0.02,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's3',\n name: 'wspace-tags-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.98,\n latency: 28,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's4',\n name: 'global-billing-svc',\n type: 'api',\n status: 'degraded',\n uptime: 98.5,\n latency: 250,\n errorRate: 2.5,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's5',\n name: 'wspace-calendar-svc',\n type: 'api',\n status: 'healthy',\n uptime: 99.97,\n latency: 35,\n errorRate: 0.03,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's6',\n name: 'postgresql-primary',\n type: 'database',\n status: 'healthy',\n uptime: 99.999,\n latency: 5,\n errorRate: 0,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's7',\n name: 'valkey-cluster',\n type: 'cache',\n status: 'healthy',\n uptime: 99.99,\n latency: 2,\n errorRate: 0,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's8',\n name: 'nats-cluster',\n type: 'queue',\n status: 'healthy',\n uptime: 99.98,\n latency: 8,\n errorRate: 0.01,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n {\n id: 's9',\n name: 'temporal-worker',\n type: 'worker',\n status: 'healthy',\n uptime: 99.95,\n latency: 15,\n errorRate: 0.05,\n lastChecked: new Date().toISOString(),\n region: 'ap-south-1',\n },\n];\n\nconst mockIncidents: Incident[] = [\n {\n id: 'inc-1',\n title: 'Elevated latency on billing service',\n severity: 'major',\n status: 'investigating',\n affectedServices: ['global-billing-svc'],\n startedAt: new Date(Date.now() - 30 * 60 * 1000).toISOString(),\n },\n {\n id: 'inc-2',\n title: 'Intermittent database connection errors',\n severity: 'minor',\n status: 'resolved',\n affectedServices: ['postgresql-primary'],\n startedAt: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(),\n resolvedAt: new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString(),\n },\n];\n\nconst mockDeployments: Deployment[] = [\n {\n id: 'd1',\n service: 'wspace-tags-svc',\n version: '2025.01.18.1',\n status: 'success',\n deployedAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 120,\n },\n {\n id: 'd2',\n service: 'global-auth-svc',\n version: '2025.01.18.0',\n status: 'success',\n deployedAt: new Date(Date.now() - 5 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 95,\n },\n {\n id: 'd3',\n service: 'wspace-calendar-svc',\n version: '2025.01.17.2',\n status: 'rolled_back',\n deployedAt: new Date(Date.now() - 12 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 180,\n },\n {\n id: 'd4',\n service: 'global-billing-svc',\n version: '2025.01.17.1',\n status: 'success',\n deployedAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),\n deployedBy: 'fluxcd',\n duration: 110,\n },\n];\n\nconst typeIcons: Record<string, React.ReactNode> = {\n api: <Server className=\"h-4 w-4\" />,\n worker: <Cpu className=\"h-4 w-4\" />,\n database: <Database className=\"h-4 w-4\" />,\n cache: <HardDrive className=\"h-4 w-4\" />,\n queue: <Wifi className=\"h-4 w-4\" />,\n};\n\nconst severityColors: Record<string, string> = {\n critical: 'bg-status-error-bg text-status-error-text',\n major: 'bg-status-warning-bg text-status-warning-text',\n minor: 'bg-status-neutral-bg text-status-neutral-text',\n};\n\n/**\n * SRE Monitoring page\n */\nexport function SREPage() {\n const { canViewSRE, isLoading: permissionsLoading } = useAdminPermissions();\n\n const [refreshing, setRefreshing] = useState(false);\n\n // Calculate metrics\n const healthyServices = mockServices.filter((s) => s.status === 'healthy').length;\n const degradedServices = mockServices.filter((s) => s.status === 'degraded').length;\n // Note: downServices available for future use when we have down services\n const _downServices = mockServices.filter((s) => s.status === 'down').length;\n void _downServices;\n const avgUptime = mockServices.reduce((sum, s) => sum + s.uptime, 0) / mockServices.length;\n const avgLatency = mockServices.reduce((sum, s) => sum + s.latency, 0) / mockServices.length;\n const activeIncidents = mockIncidents.filter((i) => i.status !== 'resolved').length;\n\n const handleRefresh = () => {\n setRefreshing(true);\n setTimeout(() => setRefreshing(false), 1000);\n };\n\n const serviceColumns = [\n {\n key: 'name',\n header: 'Service',\n render: (service: ServiceHealth) => (\n <div className=\"flex items-center gap-2\">\n {typeIcons[service.type]}\n <span className=\"font-medium\">{service.name}</span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '100px',\n render: (service: ServiceHealth) => <HealthStatusBadge status={service.status} />,\n },\n {\n key: 'uptime',\n header: 'Uptime',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span\n className={service.uptime < 99 ? 'text-status-warning-text' : 'text-status-success-text'}\n >\n {service.uptime.toFixed(2)}%\n </span>\n ),\n },\n {\n key: 'latency',\n header: 'Latency',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span className={service.latency > 100 ? 'text-status-warning-text' : ''}>\n {service.latency}ms\n </span>\n ),\n },\n {\n key: 'errorRate',\n header: 'Error Rate',\n width: '100px',\n align: 'right' as const,\n render: (service: ServiceHealth) => (\n <span className={service.errorRate > 1 ? 'text-status-error-text' : ''}>\n {service.errorRate.toFixed(2)}%\n </span>\n ),\n },\n {\n key: 'region',\n header: 'Region',\n width: '120px',\n render: (service: ServiceHealth) => (\n <span className=\"text-text-secondary\">{service.region}</span>\n ),\n },\n ];\n\n const deploymentColumns = [\n {\n key: 'service',\n header: 'Service',\n render: (d: Deployment) => <span className=\"font-medium\">{d.service}</span>,\n },\n {\n key: 'version',\n header: 'Version',\n width: '140px',\n render: (d: Deployment) => (\n <code className=\"text-xs bg-bg-sunken px-1.5 py-0.5 rounded\">{d.version}</code>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n width: '120px',\n render: (d: Deployment) => <DeploymentStatusBadge status={d.status} />,\n },\n {\n key: 'duration',\n header: 'Duration',\n width: '100px',\n align: 'right' as const,\n render: (d: Deployment) => `${d.duration}s`,\n },\n {\n key: 'deployedAt',\n header: 'Deployed',\n width: '140px',\n render: (d: Deployment) => (\n <span className=\"text-text-secondary\">{formatRelativeTime(d.deployedAt)}</span>\n ),\n },\n ];\n\n return (\n <PermissionGuard\n allowed={canViewSRE}\n isLoading={permissionsLoading}\n pageTitle=\"SRE Monitoring\"\n denyMessage=\"You don't have permission to view SRE monitoring.\"\n >\n <PageLayout\n title=\"SRE Monitoring\"\n gradientWord=\"Monitoring\"\n description=\"Service health, incidents, and deployment monitoring\"\n actions={\n <Button variant=\"outline\" onClick={handleRefresh} disabled={refreshing}>\n <RefreshCw className={`mr-2 h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />\n Refresh\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose>\n A live view of platform reliability. Watch the health, uptime and latency of every\n service, keep an eye on active incidents, and catch a degraded component before it turns\n into an outage your users notice.\n </PagePurpose>\n\n {/* Metrics */}\n <MetricsGrid>\n <MetricCard\n title=\"Healthy Services\"\n hero\n value={healthyServices}\n icon={<CheckCircle2 className=\"h-5 w-5 text-status-success-text\" />}\n subtitle={`of ${mockServices.length} total`}\n />\n <MetricCard\n title=\"Degraded\"\n value={degradedServices}\n icon={<AlertTriangle className=\"h-5 w-5 text-status-warning-text\" />}\n priority={degradedServices > 0 ? 'high' : 'normal'}\n />\n <MetricCard\n title=\"Avg Uptime\"\n value={`${avgUptime.toFixed(2)}%`}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <MetricCard\n title=\"Avg Latency\"\n value={`${avgLatency.toFixed(0)}ms`}\n icon={<Activity className=\"h-5 w-5\" />}\n />\n </MetricsGrid>\n\n {/* Active Incidents */}\n {activeIncidents > 0 && (\n <Card className=\"border-status-warning-border bg-status-warning-bg\">\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2 text-status-warning-text\">\n <AlertTriangle className=\"h-5 w-5\" />\n Active Incidents ({activeIncidents})\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {mockIncidents\n .filter((i) => i.status !== 'resolved')\n .map((incident) => (\n <div\n key={incident.id}\n className=\"flex items-start justify-between rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge className={severityColors[incident.severity]}>\n {incident.severity.toUpperCase()}\n </Badge>\n <span className=\"font-medium\">{incident.title}</span>\n </div>\n <div className=\"flex items-center gap-4 text-sm text-text-secondary\">\n <span>Started {formatRelativeTime(incident.startedAt)}</span>\n <span>•</span>\n <span>Status: {incident.status}</span>\n </div>\n <div className=\"flex flex-wrap gap-1 mt-2\">\n {incident.affectedServices.map((svc) => (\n <Badge key={svc} variant=\"outline\" className=\"text-xs\">\n {svc}\n </Badge>\n ))}\n </div>\n </div>\n <Button size=\"sm\" variant=\"outline\">\n View\n </Button>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Service Health */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2\">\n <Server className=\"h-5 w-5\" />\n Service Health\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={serviceColumns}\n data={mockServices}\n keyExtractor={(s) => s.id}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<Server className=\"h-8 w-8\" />}\n title=\"No services found\"\n />\n }\n />\n </CardContent>\n </Card>\n\n {/* Recent Deployments */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg flex items-center gap-2\">\n <RefreshCw className=\"h-5 w-5\" />\n Recent Deployments\n </CardTitle>\n </CardHeader>\n <CardContent>\n <DataTable\n columns={deploymentColumns}\n data={mockDeployments}\n keyExtractor={(d) => d.id}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<RefreshCw className=\"h-8 w-8\" />}\n title=\"No recent deployments\"\n />\n }\n />\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|