@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.
Files changed (77) hide show
  1. package/dist/admin/AdminRoot.js +2 -2
  2. package/dist/admin/AdminRoot.js.map +1 -1
  3. package/dist/admin/AdminRoutes.js +130 -78
  4. package/dist/admin/AdminRoutes.js.map +1 -1
  5. package/dist/admin/components/AccessDenied.js +2 -2
  6. package/dist/admin/components/AccessDenied.js.map +1 -1
  7. package/dist/admin/components/ActivityFeed.js +4 -4
  8. package/dist/admin/components/ActivityFeed.js.map +1 -1
  9. package/dist/admin/components/Charts.js.map +1 -1
  10. package/dist/admin/components/ConfirmDialog.js +1 -1
  11. package/dist/admin/components/ConfirmDialog.js.map +1 -1
  12. package/dist/admin/components/DataTable.js.map +1 -1
  13. package/dist/admin/components/FormSheet.js +1 -1
  14. package/dist/admin/components/FormSheet.js.map +1 -1
  15. package/dist/admin/components/TenantSsoPanel.js +1 -1
  16. package/dist/admin/components/TenantSsoPanel.js.map +1 -1
  17. package/dist/admin/components/Toast.js +11 -11
  18. package/dist/admin/components/Toast.js.map +1 -1
  19. package/dist/admin/components/forms/SubscriptionForm.js +2 -2
  20. package/dist/admin/components/forms/SubscriptionForm.js.map +1 -1
  21. package/dist/admin/components/forms/TenantForm.js +1 -1
  22. package/dist/admin/components/forms/UserForm.js +1 -1
  23. package/dist/admin/components/ui.js +3 -3
  24. package/dist/admin/components/ui.js.map +1 -1
  25. package/dist/admin/constants/featureFlags.js +12 -0
  26. package/dist/admin/constants/featureFlags.js.map +1 -0
  27. package/dist/admin/constants/index.js +33 -24
  28. package/dist/admin/constants/index.js.map +1 -1
  29. package/dist/admin/pages/AuditLogsPage.js +92 -77
  30. package/dist/admin/pages/AuditLogsPage.js.map +1 -1
  31. package/dist/admin/pages/BillingPage.js +95 -51
  32. package/dist/admin/pages/BillingPage.js.map +1 -1
  33. package/dist/admin/pages/CommunicationsPage.js +97 -92
  34. package/dist/admin/pages/CommunicationsPage.js.map +1 -1
  35. package/dist/admin/pages/ContentPagesPage.js +274 -259
  36. package/dist/admin/pages/ContentPagesPage.js.map +1 -1
  37. package/dist/admin/pages/DashboardPage.js +113 -84
  38. package/dist/admin/pages/DashboardPage.js.map +1 -1
  39. package/dist/admin/pages/FeatureFlagsPage.js +93 -75
  40. package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
  41. package/dist/admin/pages/OrganizationsListPage.js +105 -87
  42. package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
  43. package/dist/admin/pages/ProductsPage.js +138 -130
  44. package/dist/admin/pages/ProductsPage.js.map +1 -1
  45. package/dist/admin/pages/ReferralsPage.js +70 -52
  46. package/dist/admin/pages/ReferralsPage.js.map +1 -1
  47. package/dist/admin/pages/RolesPermissionsPage.js +136 -118
  48. package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
  49. package/dist/admin/pages/SREPage.js +34 -32
  50. package/dist/admin/pages/SREPage.js.map +1 -1
  51. package/dist/admin/pages/SandboxSettingsPage.js +360 -322
  52. package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
  53. package/dist/admin/pages/SettingsPage.js +64 -61
  54. package/dist/admin/pages/SettingsPage.js.map +1 -1
  55. package/dist/admin/pages/SyncFailuresPage.js +120 -118
  56. package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
  57. package/dist/admin/pages/TenantDetailPage.js +286 -231
  58. package/dist/admin/pages/TenantDetailPage.js.map +1 -1
  59. package/dist/admin/pages/TenantFormRoutePage.js +78 -73
  60. package/dist/admin/pages/TenantFormRoutePage.js.map +1 -1
  61. package/dist/admin/pages/TenantsListPage.js +182 -155
  62. package/dist/admin/pages/TenantsListPage.js.map +1 -1
  63. package/dist/admin/pages/UsersListPage.js +128 -113
  64. package/dist/admin/pages/UsersListPage.js.map +1 -1
  65. package/dist/admin/pages/WaitlistPage.js +78 -63
  66. package/dist/admin/pages/WaitlistPage.js.map +1 -1
  67. package/dist/admin/pages/WorkflowsPage.js +107 -102
  68. package/dist/admin/pages/WorkflowsPage.js.map +1 -1
  69. package/dist/admin/pages/WorkspacesListPage.js +61 -49
  70. package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
  71. package/dist/node_modules/@hookform/resolvers/dist/resolvers.js +2 -2
  72. package/dist/node_modules/@hookform/resolvers/dist/resolvers.js.map +1 -1
  73. package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js +35 -26
  74. package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js.map +1 -1
  75. package/dist/node_modules/react-hook-form/dist/index.esm.js +609 -516
  76. package/dist/node_modules/react-hook-form/dist/index.esm.js.map +1 -1
  77. 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\">{role.priority}</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 <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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"}
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 k = [
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
- ], A = [{
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
- }], j = [
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
- ], M = {
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
- }, N = {
173
- critical: "bg-status-error-bg/10 text-status-error-text",
174
- major: "bg-warning/10 text-warning",
175
- minor: "bg-bg-sunken text-text-secondary"
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 P() {
178
- let { canViewSRE: b, isLoading: x } = e(), [S, E] = g(!1), P = k.filter((e) => e.status === "healthy").length, F = k.filter((e) => e.status === "degraded").length;
179
- k.filter((e) => e.status === "down").length;
180
- let I = k.reduce((e, t) => e + t.uptime, 0) / k.length, L = k.reduce((e, t) => e + t.latency, 0) / k.length, R = A.filter((e) => e.status !== "resolved").length;
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: P,
206
- icon: /* @__PURE__ */ D(y, { className: "h-5 w-5 text-success" }),
207
- subtitle: `of ${k.length} total`
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: F,
212
- icon: /* @__PURE__ */ D(v, { className: "h-5 w-5 text-warning" }),
213
- priority: F > 0 ? "high" : "normal"
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: `${I.toFixed(2)}%`,
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: `${L.toFixed(0)}ms`,
224
+ value: `${R.toFixed(0)}ms`,
223
225
  icon: /* @__PURE__ */ D(_, { className: "h-5 w-5" })
224
226
  })
225
227
  ] }),
226
- R > 0 && /* @__PURE__ */ O(r, {
227
- className: "border-warning/50 bg-warning/5",
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
- R,
235
+ z,
234
236
  ")"
235
237
  ]
236
238
  }) }), /* @__PURE__ */ D(i, { children: /* @__PURE__ */ D("div", {
237
239
  className: "space-y-3",
238
- children: A.filter((e) => e.status !== "resolved").map((e) => /* @__PURE__ */ O("div", {
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: N[e.severity],
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: [M[e.type], /* @__PURE__ */ D("span", {
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: k,
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: j,
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 { P as SREPage };
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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"}