@burdenoff/microfe-adaptercloud 2026.629.1 → 2026.706.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/adaptercloud/AdapterCloudRoot.js +39 -33
  2. package/dist/adaptercloud/AdapterCloudRoot.js.map +1 -1
  3. package/dist/adaptercloud/AdapterCloudRoutes.js +5 -1
  4. package/dist/adaptercloud/AdapterCloudRoutes.js.map +1 -1
  5. package/dist/adaptercloud/components/ConfirmDialog.js +27 -0
  6. package/dist/adaptercloud/components/ConfirmDialog.js.map +1 -0
  7. package/dist/adaptercloud/components/DataState.js +1 -1
  8. package/dist/adaptercloud/components/DataState.js.map +1 -1
  9. package/dist/adaptercloud/hooks/useAdapterCloudApi.js +246 -220
  10. package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
  11. package/dist/adaptercloud/lib/toast.js +36 -0
  12. package/dist/adaptercloud/lib/toast.js.map +1 -0
  13. package/dist/adaptercloud/pages/OverviewPage.js +159 -156
  14. package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
  15. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js +102 -89
  16. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js.map +1 -1
  17. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js +2 -0
  18. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js.map +1 -1
  19. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +2 -0
  20. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -1
  21. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +141 -124
  22. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
  23. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js +2 -0
  24. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js.map +1 -1
  25. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +1 -0
  26. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
  27. package/dist/adaptercloud/pages/costs/CostsPage.js +112 -87
  28. package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -1
  29. package/dist/adaptercloud/pages/drift/DriftListPage.js +81 -59
  30. package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -1
  31. package/dist/adaptercloud/pages/policies/PoliciesListPage.js +2 -0
  32. package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -1
  33. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +109 -91
  34. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -1
  35. package/dist/adaptercloud/pages/policies/PolicyFormPage.js +211 -184
  36. package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -1
  37. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +153 -111
  38. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -1
  39. package/dist/adaptercloud/pages/resources/ResourcesListPage.js +111 -83
  40. package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -1
  41. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +108 -86
  42. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -1
  43. package/dist/adaptercloud/pages/violations/ViolationsListPage.js +11 -3
  44. package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -1
  45. package/dist/adaptercloud/utils/domain.js +1 -0
  46. package/dist/adaptercloud/utils/domain.js.map +1 -1
  47. package/dist/adaptercloud/utils/formatters.js +3 -15
  48. package/dist/adaptercloud/utils/formatters.js.map +1 -1
  49. package/dist/index.js +4 -4
  50. package/package.json +2 -1
@@ -5,192 +5,214 @@ import { StatusBadge as i } from "../../components/StatusBadge.js";
5
5
  import { DataState as a } from "../../components/DataState.js";
6
6
  import { useCancelSyncRun as o, useSyncRuns as s } from "../../hooks/useAdapterCloudApi.js";
7
7
  import { formatDate as c, formatRelativeTime as l } from "../../utils/formatters.js";
8
- import { useCallback as u, useState as d } from "react";
9
- import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
- import { Activity as p, ChevronLeft as m, ChevronRight as h, GitCompareArrows as g, Loader2 as _, RotateCcw as v, Server as y, ShieldAlert as b, XCircle as x } from "lucide-react";
11
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
12
- import { GlassCard as w } from "@burdenoff/fe-libs/ui";
8
+ import { ConfirmDialog as u } from "../../components/ConfirmDialog.js";
9
+ import { useCallback as d, useState as f } from "react";
10
+ import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
11
+ import { Activity as m, ChevronLeft as h, ChevronRight as g, GitCompareArrows as _, Loader2 as v, RotateCcw as y, Server as b, ShieldAlert as x, XCircle as S } from "lucide-react";
12
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
13
+ import { GlassCard as T } from "@burdenoff/fe-libs/ui";
13
14
  //#region src/adaptercloud/pages/sync-runs/SyncRunsListPage.tsx
14
- var T = 20;
15
- function E() {
16
- let { navigateTo: E } = e(), { t: D } = f(), O = u((e, t) => {
17
- let n = D(e);
15
+ var E = 20;
16
+ function D() {
17
+ let { navigateTo: D } = e(), { t: O } = p(), k = d((e, t) => {
18
+ let n = O(e);
18
19
  return n === e ? t : n;
19
- }, [D]), [k, A] = d(""), [j, M] = d(0), [N, P] = d(null), F = s({
20
- status: k || void 0,
20
+ }, [O]), [A, j] = f(""), [M, N] = f(0), [P, F] = f(null), [I, L] = f(null), R = s({
21
+ status: A || void 0,
21
22
  pagination: {
22
- limit: T,
23
- offset: j
23
+ limit: E,
24
+ offset: M
24
25
  }
25
- }), I = o(), L = F.data?.items ?? [], R = F.data?.pageInfo.hasMore ?? !1, z = u((e) => {
26
- P(null), I.mutate(e, { onError: (e) => P(e instanceof Error ? e.message : "Failed to cancel run.") });
27
- }, [I]);
28
- return /* @__PURE__ */ C(t, {
29
- title: O("adaptercloud.syncRuns.title", "Sync Runs"),
30
- description: O("adaptercloud.syncRuns.subtitle", "Discovery, reconciliation and cost-ingest executions that keep the picture live."),
26
+ }), z = o(), B = R.data?.items ?? [], V = R.data?.pageInfo.hasMore ?? !1, H = z.isPending ? z.variables : void 0, U = d((e) => {
27
+ F(null), z.mutate(e, {
28
+ onSuccess: () => L(null),
29
+ onError: (e) => F(e instanceof Error ? e.message : "Failed to cancel run.")
30
+ });
31
+ }, [z]);
32
+ return /* @__PURE__ */ w(t, {
33
+ title: k("adaptercloud.syncRuns.title", "Sync Runs"),
34
+ description: k("adaptercloud.syncRuns.subtitle", "Discovery, reconciliation and cost-ingest executions that keep the picture live."),
31
35
  children: [
32
- /* @__PURE__ */ S("div", {
36
+ /* @__PURE__ */ C("div", {
33
37
  className: "mb-6 flex flex-wrap gap-3",
34
- children: /* @__PURE__ */ C("select", {
35
- value: k,
38
+ children: /* @__PURE__ */ w("select", {
39
+ value: A,
36
40
  onChange: (e) => {
37
- A(e.target.value), M(0);
41
+ j(e.target.value), N(0);
38
42
  },
43
+ "aria-label": k("adaptercloud.syncRuns.filterByStatus", "Filter by status"),
39
44
  className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
40
- children: [/* @__PURE__ */ S("option", {
45
+ children: [/* @__PURE__ */ C("option", {
41
46
  value: "",
42
- children: O("adaptercloud.syncRuns.allStatuses", "All statuses")
43
- }), Object.keys(r).map((e) => /* @__PURE__ */ S("option", {
47
+ children: k("adaptercloud.syncRuns.allStatuses", "All statuses")
48
+ }), Object.keys(r).map((e) => /* @__PURE__ */ C("option", {
44
49
  value: e,
45
50
  children: r[e]
46
51
  }, e))]
47
52
  })
48
53
  }),
49
- N && /* @__PURE__ */ S("p", {
54
+ P && /* @__PURE__ */ C("p", {
55
+ role: "alert",
56
+ "aria-live": "polite",
50
57
  className: "mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
51
- children: N
58
+ children: P
52
59
  }),
53
- /* @__PURE__ */ C(a, {
54
- isLoading: F.isLoading,
55
- isError: F.isError,
56
- isEmpty: L.length === 0,
57
- error: F.error,
58
- onRetry: () => void F.refetch(),
59
- emptyTitle: O("adaptercloud.syncRuns.emptyTitle", "No sync runs yet"),
60
- emptyDescription: O("adaptercloud.syncRuns.emptyDescription", "Start a sync run from a connection to keep the inventory current."),
61
- emptyIcon: /* @__PURE__ */ S(p, { className: "h-10 w-10" }),
62
- emptyAction: /* @__PURE__ */ S("button", {
60
+ /* @__PURE__ */ w(a, {
61
+ isLoading: R.isLoading,
62
+ isError: R.isError,
63
+ isEmpty: B.length === 0,
64
+ error: R.error,
65
+ onRetry: () => void R.refetch(),
66
+ emptyTitle: k("adaptercloud.syncRuns.emptyTitle", "No sync runs yet"),
67
+ emptyDescription: k("adaptercloud.syncRuns.emptyDescription", "Start a sync run from a connection to keep the inventory current."),
68
+ emptyIcon: /* @__PURE__ */ C(m, { className: "h-10 w-10" }),
69
+ emptyAction: /* @__PURE__ */ C("button", {
63
70
  type: "button",
64
- onClick: () => E("/connections"),
71
+ onClick: () => D("/connections"),
65
72
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90",
66
- children: O("adaptercloud.syncRuns.goToConnections", "Go to connections")
73
+ children: k("adaptercloud.syncRuns.goToConnections", "Go to connections")
67
74
  }),
68
- children: [/* @__PURE__ */ S("div", {
75
+ children: [/* @__PURE__ */ C("div", {
69
76
  className: "space-y-3",
70
- children: L.map((e) => {
77
+ children: B.map((e) => {
71
78
  let t = e.status === "QUEUED" || e.status === "RUNNING";
72
- return /* @__PURE__ */ S(w, {
79
+ return /* @__PURE__ */ C(T, {
73
80
  className: "p-5",
74
- children: /* @__PURE__ */ C("div", {
81
+ children: /* @__PURE__ */ w("div", {
75
82
  className: "flex flex-wrap items-start justify-between gap-3",
76
- children: [/* @__PURE__ */ C("div", {
83
+ children: [/* @__PURE__ */ w("div", {
77
84
  className: "min-w-0 flex-1",
78
85
  children: [
79
- /* @__PURE__ */ C("div", {
86
+ /* @__PURE__ */ w("div", {
80
87
  className: "mb-1.5 flex flex-wrap items-center gap-2",
81
- children: [/* @__PURE__ */ S("span", {
88
+ children: [/* @__PURE__ */ C("span", {
82
89
  className: "text-sm font-semibold text-text-primary",
83
90
  children: n[e.kind]
84
- }), /* @__PURE__ */ S(i, { status: e.status })]
91
+ }), /* @__PURE__ */ C(i, { status: e.status })]
85
92
  }),
86
- /* @__PURE__ */ C("div", {
93
+ /* @__PURE__ */ w("div", {
87
94
  className: "flex flex-wrap items-center gap-4 text-xs text-text-secondary",
88
95
  children: [
89
- /* @__PURE__ */ C("span", {
96
+ /* @__PURE__ */ w("span", {
90
97
  className: "flex items-center gap-1",
91
98
  children: [
92
- /* @__PURE__ */ S(y, { className: "h-3.5 w-3.5" }),
99
+ /* @__PURE__ */ C(b, { className: "h-3.5 w-3.5" }),
93
100
  " ",
94
101
  e.discoveredCount,
95
102
  " ",
96
- O("adaptercloud.syncRuns.discovered", "discovered")
103
+ k("adaptercloud.syncRuns.discovered", "discovered")
97
104
  ]
98
105
  }),
99
- /* @__PURE__ */ C("span", {
106
+ /* @__PURE__ */ w("span", {
100
107
  className: "flex items-center gap-1",
101
108
  children: [
102
- /* @__PURE__ */ S(v, { className: "h-3.5 w-3.5" }),
109
+ /* @__PURE__ */ C(y, { className: "h-3.5 w-3.5" }),
103
110
  " ",
104
111
  e.reconciledCount,
105
112
  " ",
106
- O("adaptercloud.syncRuns.reconciled", "reconciled")
113
+ k("adaptercloud.syncRuns.reconciled", "reconciled")
107
114
  ]
108
115
  }),
109
- /* @__PURE__ */ C("span", {
116
+ /* @__PURE__ */ w("span", {
110
117
  className: "flex items-center gap-1",
111
118
  children: [
112
- /* @__PURE__ */ S(g, { className: "h-3.5 w-3.5" }),
119
+ /* @__PURE__ */ C(_, { className: "h-3.5 w-3.5" }),
113
120
  " ",
114
121
  e.driftCount,
115
122
  " ",
116
- O("adaptercloud.syncRuns.drift", "drift")
123
+ k("adaptercloud.syncRuns.drift", "drift")
117
124
  ]
118
125
  }),
119
- /* @__PURE__ */ C("span", {
126
+ /* @__PURE__ */ w("span", {
120
127
  className: "flex items-center gap-1",
121
128
  children: [
122
- /* @__PURE__ */ S(b, { className: "h-3.5 w-3.5" }),
129
+ /* @__PURE__ */ C(x, { className: "h-3.5 w-3.5" }),
123
130
  " ",
124
131
  e.violationCount,
125
132
  " ",
126
- O("adaptercloud.syncRuns.violations", "violations")
133
+ k("adaptercloud.syncRuns.violations", "violations")
127
134
  ]
128
135
  })
129
136
  ]
130
137
  }),
131
- /* @__PURE__ */ C("p", {
138
+ /* @__PURE__ */ w("p", {
132
139
  className: "mt-2 text-xs text-text-secondary",
133
140
  children: [
134
- e.startedAt ? `${O("adaptercloud.syncRuns.started", "Started")} ${c(e.startedAt)}` : `${O("adaptercloud.syncRuns.created", "Created")} ${l(e.createdAt)}`,
135
- e.finishedAt && ` · ${O("adaptercloud.syncRuns.finished", "Finished")} ${c(e.finishedAt)}`,
141
+ e.startedAt ? `${k("adaptercloud.syncRuns.started", "Started")} ${c(e.startedAt)}` : `${k("adaptercloud.syncRuns.created", "Created")} ${l(e.createdAt)}`,
142
+ e.finishedAt && ` · ${k("adaptercloud.syncRuns.finished", "Finished")} ${c(e.finishedAt)}`,
136
143
  " · ",
137
- /* @__PURE__ */ S("button", {
144
+ /* @__PURE__ */ C("button", {
138
145
  type: "button",
139
- onClick: () => E(`/connections/${e.connectionId}`),
146
+ onClick: () => D(`/connections/${e.connectionId}`),
140
147
  className: "hover:underline",
141
- children: O("adaptercloud.syncRuns.viewConnection", "View connection")
148
+ children: k("adaptercloud.syncRuns.viewConnection", "View connection")
142
149
  })
143
150
  ]
144
151
  }),
145
- e.error && /* @__PURE__ */ S("p", {
152
+ e.error && /* @__PURE__ */ C("p", {
146
153
  className: "mt-2 rounded-lg bg-status-error-bg-subtle px-3 py-1.5 text-xs text-status-error-text",
147
154
  children: e.error
148
155
  })
149
156
  ]
150
- }), t && /* @__PURE__ */ C("button", {
157
+ }), t && /* @__PURE__ */ w("button", {
151
158
  type: "button",
152
- disabled: I.isPending,
153
- onClick: () => z(e.id),
159
+ disabled: H === e.id,
160
+ onClick: () => {
161
+ F(null), L(e);
162
+ },
154
163
  className: "inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50",
155
- children: [I.isPending ? /* @__PURE__ */ S(_, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ S(x, { className: "h-3.5 w-3.5" }), O("adaptercloud.syncRuns.cancel", "Cancel")]
164
+ children: [H === e.id ? /* @__PURE__ */ C(v, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ C(S, { className: "h-3.5 w-3.5" }), k("adaptercloud.syncRuns.cancel", "Cancel")]
156
165
  })]
157
166
  })
158
167
  }, e.id);
159
168
  })
160
- }), (j > 0 || R) && /* @__PURE__ */ C("div", {
169
+ }), (M > 0 || V) && /* @__PURE__ */ w("div", {
161
170
  className: "mt-6 flex items-center justify-between",
162
171
  children: [
163
- /* @__PURE__ */ C("button", {
172
+ /* @__PURE__ */ w("button", {
164
173
  type: "button",
165
- disabled: j === 0,
166
- onClick: () => M((e) => Math.max(0, e - T)),
174
+ disabled: M === 0,
175
+ onClick: () => N((e) => Math.max(0, e - E)),
167
176
  className: "inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50",
168
- children: [/* @__PURE__ */ S(m, { className: "h-4 w-4" }), O("adaptercloud.common.prev", "Previous")]
177
+ children: [/* @__PURE__ */ C(h, { className: "h-4 w-4" }), k("adaptercloud.common.prev", "Previous")]
169
178
  }),
170
- /* @__PURE__ */ C("span", {
179
+ /* @__PURE__ */ w("span", {
171
180
  className: "text-sm text-text-secondary",
172
181
  children: [
173
- O("adaptercloud.common.showing", "Showing"),
182
+ k("adaptercloud.common.showing", "Showing"),
174
183
  " ",
175
- j + 1,
184
+ M + 1,
176
185
  "–",
177
- j + L.length
186
+ M + B.length
178
187
  ]
179
188
  }),
180
- /* @__PURE__ */ C("button", {
189
+ /* @__PURE__ */ w("button", {
181
190
  type: "button",
182
- disabled: !R,
183
- onClick: () => M((e) => e + T),
191
+ disabled: !V,
192
+ onClick: () => N((e) => e + E),
184
193
  className: "inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50",
185
- children: [O("adaptercloud.common.next", "Next"), /* @__PURE__ */ S(h, { className: "h-4 w-4" })]
194
+ children: [k("adaptercloud.common.next", "Next"), /* @__PURE__ */ C(g, { className: "h-4 w-4" })]
186
195
  })
187
196
  ]
188
197
  })]
198
+ }),
199
+ /* @__PURE__ */ C(u, {
200
+ open: !!I,
201
+ onOpenChange: (e) => {
202
+ e || L(null);
203
+ },
204
+ title: k("adaptercloud.syncRuns.cancelTitle", "Cancel this sync run?"),
205
+ description: k("adaptercloud.syncRuns.cancelPrompt", "The run will stop and transition to Cancelled. Any work already done is kept, but it will not finish."),
206
+ confirmLabel: k("adaptercloud.syncRuns.confirmCancel", "Cancel run"),
207
+ cancelLabel: k("adaptercloud.syncRuns.keepRunning", "Keep running"),
208
+ onConfirm: () => I && U(I.id),
209
+ isPending: !!I && H === I?.id,
210
+ tone: "danger"
189
211
  })
190
212
  ]
191
213
  });
192
214
  }
193
215
  //#endregion
194
- export { E as SyncRunsListPage };
216
+ export { D as SyncRunsListPage };
195
217
 
196
218
  //# sourceMappingURL=SyncRunsListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SyncRunsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/sync-runs/SyncRunsListPage.tsx"],"sourcesContent":["/**\n * Sync Runs History Page\n * @module adaptercloud/pages/sync-runs\n *\n * The operations log (`adaListSyncRuns`) — every discovery / reconcile /\n * cost-ingest / full execution with its lifecycle and counters. Filters by\n * status; queued/running runs can be cancelled via `adaCancelSyncRun`.\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Activity,\n ChevronLeft,\n ChevronRight,\n XCircle,\n Loader2,\n Server,\n GitCompareArrows,\n ShieldAlert,\n RotateCcw,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useSyncRuns, useCancelSyncRun } from '../../hooks/useAdapterCloudApi';\nimport { syncKindLabels, syncStatusLabels } from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\nimport type { AdaSyncStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function SyncRunsListPage() {\n const { navigateTo } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaSyncStatus | ''>('');\n const [offset, setOffset] = useState(0);\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useSyncRuns({\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const cancel = useCancelSyncRun();\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const handleCancel = useCallback(\n (id: string) => {\n setActionError(null);\n cancel.mutate(id, {\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Failed to cancel run.'),\n });\n },\n [cancel]\n );\n\n return (\n <PageLayout\n title={t('adaptercloud.syncRuns.title', 'Sync Runs')}\n description={t(\n 'adaptercloud.syncRuns.subtitle',\n 'Discovery, reconciliation and cost-ingest executions that keep the picture live.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaSyncStatus | '');\n setOffset(0);\n }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.syncRuns.allStatuses', 'All statuses')}</option>\n {(Object.keys(syncStatusLabels) as AdaSyncStatus[]).map((s) => (\n <option key={s} value={s}>\n {syncStatusLabels[s]}\n </option>\n ))}\n </select>\n </div>\n\n {actionError && (\n <p className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.syncRuns.emptyTitle', 'No sync runs yet')}\n emptyDescription={t(\n 'adaptercloud.syncRuns.emptyDescription',\n 'Start a sync run from a connection to keep the inventory current.'\n )}\n emptyIcon={<Activity className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.syncRuns.goToConnections', 'Go to connections')}\n </button>\n }\n >\n <div className=\"space-y-3\">\n {items.map((run) => {\n const cancellable = run.status === 'QUEUED' || run.status === 'RUNNING';\n return (\n <GlassCard key={run.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {syncKindLabels[run.kind]}\n </span>\n <StatusBadge status={run.status} />\n </div>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Server className=\"h-3.5 w-3.5\" /> {run.discoveredCount}{' '}\n {t('adaptercloud.syncRuns.discovered', 'discovered')}\n </span>\n <span className=\"flex items-center gap-1\">\n <RotateCcw className=\"h-3.5 w-3.5\" /> {run.reconciledCount}{' '}\n {t('adaptercloud.syncRuns.reconciled', 'reconciled')}\n </span>\n <span className=\"flex items-center gap-1\">\n <GitCompareArrows className=\"h-3.5 w-3.5\" /> {run.driftCount}{' '}\n {t('adaptercloud.syncRuns.drift', 'drift')}\n </span>\n <span className=\"flex items-center gap-1\">\n <ShieldAlert className=\"h-3.5 w-3.5\" /> {run.violationCount}{' '}\n {t('adaptercloud.syncRuns.violations', 'violations')}\n </span>\n </div>\n <p className=\"mt-2 text-xs text-text-secondary\">\n {run.startedAt\n ? `${t('adaptercloud.syncRuns.started', 'Started')} ${formatDate(run.startedAt)}`\n : `${t('adaptercloud.syncRuns.created', 'Created')} ${formatRelativeTime(run.createdAt)}`}\n {run.finishedAt &&\n ` · ${t('adaptercloud.syncRuns.finished', 'Finished')} ${formatDate(run.finishedAt)}`}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${run.connectionId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.syncRuns.viewConnection', 'View connection')}\n </button>\n </p>\n {run.error && (\n <p className=\"mt-2 rounded-lg bg-status-error-bg-subtle px-3 py-1.5 text-xs text-status-error-text\">\n {run.error}\n </p>\n )}\n </div>\n\n {cancellable && (\n <button\n type=\"button\"\n disabled={cancel.isPending}\n onClick={() => handleCancel(run.id)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n {cancel.isPending ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <XCircle className=\"h-3.5 w-3.5\" />\n )}\n {t('adaptercloud.syncRuns.cancel', 'Cancel')}\n </button>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SyncRunsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/sync-runs/SyncRunsListPage.tsx"],"sourcesContent":["/**\n * Sync Runs History Page\n * @module adaptercloud/pages/sync-runs\n *\n * The operations log (`adaListSyncRuns`) — every discovery / reconcile /\n * cost-ingest / full execution with its lifecycle and counters. Filters by\n * status; queued/running runs can be cancelled via `adaCancelSyncRun`.\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Activity,\n ChevronLeft,\n ChevronRight,\n XCircle,\n Loader2,\n Server,\n GitCompareArrows,\n ShieldAlert,\n RotateCcw,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { ConfirmDialog } from '../../components/ConfirmDialog';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useSyncRuns, useCancelSyncRun } from '../../hooks/useAdapterCloudApi';\nimport { syncKindLabels, syncStatusLabels } from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\nimport type { AdaSyncRun, AdaSyncStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function SyncRunsListPage() {\n const { navigateTo } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaSyncStatus | ''>('');\n const [offset, setOffset] = useState(0);\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmTarget, setConfirmTarget] = useState<AdaSyncRun | null>(null);\n\n const query = useSyncRuns({\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const cancel = useCancelSyncRun();\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n // Per-id pending so cancelling one run only disables/spins that row's button.\n const pendingId = cancel.isPending ? cancel.variables : undefined;\n\n const handleCancel = useCallback(\n (id: string) => {\n setActionError(null);\n cancel.mutate(id, {\n onSuccess: () => setConfirmTarget(null),\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Failed to cancel run.'),\n });\n },\n [cancel]\n );\n\n return (\n <PageLayout\n title={t('adaptercloud.syncRuns.title', 'Sync Runs')}\n description={t(\n 'adaptercloud.syncRuns.subtitle',\n 'Discovery, reconciliation and cost-ingest executions that keep the picture live.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaSyncStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.syncRuns.filterByStatus', 'Filter by status')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.syncRuns.allStatuses', 'All statuses')}</option>\n {(Object.keys(syncStatusLabels) as AdaSyncStatus[]).map((s) => (\n <option key={s} value={s}>\n {syncStatusLabels[s]}\n </option>\n ))}\n </select>\n </div>\n\n {actionError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n {actionError}\n </p>\n )}\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.syncRuns.emptyTitle', 'No sync runs yet')}\n emptyDescription={t(\n 'adaptercloud.syncRuns.emptyDescription',\n 'Start a sync run from a connection to keep the inventory current.'\n )}\n emptyIcon={<Activity className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.syncRuns.goToConnections', 'Go to connections')}\n </button>\n }\n >\n <div className=\"space-y-3\">\n {items.map((run) => {\n const cancellable = run.status === 'QUEUED' || run.status === 'RUNNING';\n return (\n <GlassCard key={run.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {syncKindLabels[run.kind]}\n </span>\n <StatusBadge status={run.status} />\n </div>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Server className=\"h-3.5 w-3.5\" /> {run.discoveredCount}{' '}\n {t('adaptercloud.syncRuns.discovered', 'discovered')}\n </span>\n <span className=\"flex items-center gap-1\">\n <RotateCcw className=\"h-3.5 w-3.5\" /> {run.reconciledCount}{' '}\n {t('adaptercloud.syncRuns.reconciled', 'reconciled')}\n </span>\n <span className=\"flex items-center gap-1\">\n <GitCompareArrows className=\"h-3.5 w-3.5\" /> {run.driftCount}{' '}\n {t('adaptercloud.syncRuns.drift', 'drift')}\n </span>\n <span className=\"flex items-center gap-1\">\n <ShieldAlert className=\"h-3.5 w-3.5\" /> {run.violationCount}{' '}\n {t('adaptercloud.syncRuns.violations', 'violations')}\n </span>\n </div>\n <p className=\"mt-2 text-xs text-text-secondary\">\n {run.startedAt\n ? `${t('adaptercloud.syncRuns.started', 'Started')} ${formatDate(run.startedAt)}`\n : `${t('adaptercloud.syncRuns.created', 'Created')} ${formatRelativeTime(run.createdAt)}`}\n {run.finishedAt &&\n ` · ${t('adaptercloud.syncRuns.finished', 'Finished')} ${formatDate(run.finishedAt)}`}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${run.connectionId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.syncRuns.viewConnection', 'View connection')}\n </button>\n </p>\n {run.error && (\n <p className=\"mt-2 rounded-lg bg-status-error-bg-subtle px-3 py-1.5 text-xs text-status-error-text\">\n {run.error}\n </p>\n )}\n </div>\n\n {cancellable && (\n <button\n type=\"button\"\n disabled={pendingId === run.id}\n onClick={() => {\n setActionError(null);\n setConfirmTarget(run);\n }}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n {pendingId === run.id ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <XCircle className=\"h-3.5 w-3.5\" />\n )}\n {t('adaptercloud.syncRuns.cancel', 'Cancel')}\n </button>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={Boolean(confirmTarget)}\n onOpenChange={(open) => {\n if (!open) setConfirmTarget(null);\n }}\n title={t('adaptercloud.syncRuns.cancelTitle', 'Cancel this sync run?')}\n description={t(\n 'adaptercloud.syncRuns.cancelPrompt',\n 'The run will stop and transition to Cancelled. Any work already done is kept, but it will not finish.'\n )}\n confirmLabel={t('adaptercloud.syncRuns.confirmCancel', 'Cancel run')}\n cancelLabel={t('adaptercloud.syncRuns.keepRunning', 'Keep running')}\n onConfirm={() => confirmTarget && handleCancel(confirmTarget.id)}\n isPending={Boolean(confirmTarget) && pendingId === confirmTarget?.id}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAiCA,IAAM,IAAY;AAElB,SAAgB,IAAmB;CACjC,IAAM,EAAE,kBAAe,GAAiB,EAClC,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ,EAEK,CAAC,GAAQ,KAAa,EAA6B,GAAG,EACtD,CAAC,GAAQ,KAAa,EAAS,EAAE,EACjC,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAe,KAAoB,EAA4B,KAAK,EAErE,IAAQ,EAAY;EACxB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW;GAAQ;EACzC,CAAC,EACI,IAAS,GAAkB,EAE3B,IAAQ,EAAM,MAAM,SAAS,EAAE,EAC/B,IAAU,EAAM,MAAM,SAAS,WAAW,IAG1C,IAAY,EAAO,YAAY,EAAO,YAAY,KAAA,GAElD,IAAe,GAClB,MAAe;AAEd,EADA,EAAe,KAAK,EACpB,EAAO,OAAO,GAAI;GAChB,iBAAiB,EAAiB,KAAK;GACvC,UAAU,MACR,EAAe,aAAe,QAAQ,EAAI,UAAU,wBAAwB;GAC/E,CAAC;IAEJ,CAAC,EAAO,CACT;AAED,QACE,kBAAC,GAAD;EACE,OAAO,EAAE,+BAA+B,YAAY;EACpD,aAAa,EACX,kCACA,mFACD;YALH;GAOE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM;AAEf,MADA,EAAU,EAAE,OAAO,MAA4B,EAC/C,EAAU,EAAE;;KAEd,cAAY,EAAE,wCAAwC,mBAAmB;KACzE,WAAU;eAPZ,CASE,kBAAC,UAAD;MAAQ,OAAM;gBAAI,EAAE,qCAAqC,eAAe;MAAU,CAAA,EAChF,OAAO,KAAK,EAAiB,CAAqB,KAAK,MACvD,kBAAC,UAAD;MAAgB,OAAO;gBACpB,EAAiB;MACX,EAFI,EAEJ,CACT,CACK;;IACL,CAAA;GAEL,KACC,kBAAC,KAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;cAET;IACC,CAAA;GAGN,kBAAC,GAAD;IACE,WAAW,EAAM;IACjB,SAAS,EAAM;IACf,SAAS,EAAM,WAAW;IAC1B,OAAO,EAAM;IACb,eAAe,KAAK,EAAM,SAAS;IACnC,YAAY,EAAE,oCAAoC,mBAAmB;IACrE,kBAAkB,EAChB,0CACA,oEACD;IACD,WAAW,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;IAC7C,aACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAW,eAAe;KACzC,WAAU;eAET,EAAE,yCAAyC,oBAAoB;KACzD,CAAA;cAnBb,CAsBE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,MAAQ;MAClB,IAAM,IAAc,EAAI,WAAW,YAAY,EAAI,WAAW;AAC9D,aACE,kBAAC,GAAD;OAAwB,WAAU;iBAChC,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBACb,EAAe,EAAI;YACf,CAAA,EACP,kBAAC,GAAD,EAAa,QAAQ,EAAI,QAAU,CAAA,CAC/B;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA;;cAAE,EAAI;cAAiB;cACxD,EAAE,oCAAoC,aAAa;cAC/C;;YACP,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cACE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA;;cAAE,EAAI;cAAiB;cAC3D,EAAE,oCAAoC,aAAa;cAC/C;;YACP,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cACE,kBAAC,GAAD,EAAkB,WAAU,eAAgB,CAAA;;cAAE,EAAI;cAAY;cAC7D,EAAE,+BAA+B,QAAQ;cACrC;;YACP,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cACE,kBAAC,GAAD,EAAa,WAAU,eAAgB,CAAA;;cAAE,EAAI;cAAgB;cAC5D,EAAE,oCAAoC,aAAa;cAC/C;;YACH;;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAb;YACG,EAAI,YACD,GAAG,EAAE,iCAAiC,UAAU,CAAC,GAAG,EAAW,EAAI,UAAU,KAC7E,GAAG,EAAE,iCAAiC,UAAU,CAAC,GAAG,EAAmB,EAAI,UAAU;YACxF,EAAI,cACH,MAAM,EAAE,kCAAkC,WAAW,CAAC,GAAG,EAAW,EAAI,WAAW;YACpF;YACD,kBAAC,UAAD;aACE,MAAK;aACL,eAAe,EAAW,gBAAgB,EAAI,eAAe;aAC7D,WAAU;uBAET,EAAE,wCAAwC,kBAAkB;aACtD,CAAA;YACP;;UACH,EAAI,SACH,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAI;WACH,CAAA;UAEF;YAEL,KACC,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAc,EAAI;SAC5B,eAAe;AAEb,UADA,EAAe,KAAK,EACpB,EAAiB,EAAI;;SAEvB,WAAU;mBAPZ,CASG,MAAc,EAAI,KACjB,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA,GAEhD,kBAAC,GAAD,EAAS,WAAU,eAAgB,CAAA,EAEpC,EAAE,gCAAgC,SAAS,CACrC;WAEP;;OACI,EApEI,EAAI,GAoER;OAEd;KACE,CAAA,GAEJ,IAAS,KAAK,MACd,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAW;OACrB,eAAe,GAAW,MAAM,KAAK,IAAI,GAAG,IAAI,EAAU,CAAC;OAC3D,WAAU;iBAJZ,CAME,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAClC,EAAE,4BAA4B,WAAW,CACnC;;MACT,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACG,EAAE,+BAA+B,UAAU;QAAC;QAAE,IAAS;QAAE;QAAE,IAAS,EAAM;QACtE;;MACP,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,CAAC;OACX,eAAe,GAAW,MAAM,IAAI,EAAU;OAC9C,WAAU;iBAJZ,CAMG,EAAE,4BAA4B,OAAO,EACtC,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,CAC7B;;MACL;OAEE;;GAEZ,kBAAC,GAAD;IACE,MAAM,EAAQ;IACd,eAAe,MAAS;AACtB,KAAK,KAAM,EAAiB,KAAK;;IAEnC,OAAO,EAAE,qCAAqC,wBAAwB;IACtE,aAAa,EACX,sCACA,wGACD;IACD,cAAc,EAAE,uCAAuC,aAAa;IACpE,aAAa,EAAE,qCAAqC,eAAe;IACnE,iBAAiB,KAAiB,EAAa,EAAc,GAAG;IAChE,WAAW,EAAQ,KAAkB,MAAc,GAAe;IAClE,MAAK;IACL,CAAA;GACS"}
@@ -66,6 +66,7 @@ function A() {
66
66
  onChange: (e) => {
67
67
  L(e.target.value), z(0);
68
68
  },
69
+ "aria-label": F("adaptercloud.violations.filterByStatus", "Filter by status"),
69
70
  className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
70
71
  children: [/* @__PURE__ */ x("option", {
71
72
  value: "",
@@ -82,6 +83,8 @@ function A() {
82
83
  })]
83
84
  }),
84
85
  W && /* @__PURE__ */ x("p", {
86
+ role: "alert",
87
+ "aria-live": "polite",
85
88
  className: "mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
86
89
  children: W
87
90
  }),
@@ -113,7 +116,7 @@ function A() {
113
116
  e.policy && /* @__PURE__ */ x("button", {
114
117
  type: "button",
115
118
  onClick: () => A(`/policies/${e.policyId}`),
116
- className: "text-xs font-medium text-primary hover:underline",
119
+ className: "text-xs font-medium text-accent-blue hover:underline",
117
120
  children: e.policy.name
118
121
  })
119
122
  ]
@@ -217,19 +220,24 @@ function A() {
217
220
  /* @__PURE__ */ S("div", {
218
221
  className: "px-1 py-2",
219
222
  children: [
220
- /* @__PURE__ */ x("p", {
221
- className: "mb-3 text-sm text-text-secondary",
223
+ /* @__PURE__ */ x("label", {
224
+ htmlFor: "ada-waiver-reason",
225
+ className: "mb-1.5 block text-sm text-text-secondary",
222
226
  children: F("adaptercloud.violations.waivePrompt", "A waiver requires a documented reason and is recorded on the violation.")
223
227
  }),
224
228
  /* @__PURE__ */ x("textarea", {
229
+ id: "ada-waiver-reason",
225
230
  value: H,
226
231
  onChange: (e) => U(e.target.value),
227
232
  rows: 4,
228
233
  autoFocus: !0,
234
+ "aria-label": F("adaptercloud.violations.waiverReason", "Waiver reason"),
229
235
  placeholder: F("adaptercloud.violations.waiveReasonPlaceholder", "Why is this acceptable?"),
230
236
  className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
231
237
  }),
232
238
  W && /* @__PURE__ */ x("p", {
239
+ role: "alert",
240
+ "aria-live": "polite",
233
241
  className: "mt-2 text-sm text-status-error-text",
234
242
  children: W
235
243
  })
@@ -1 +1 @@
1
- {"version":3,"file":"ViolationsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/violations/ViolationsListPage.tsx"],"sourcesContent":["/**\n * Violations Queue Page\n * @module adaptercloud/pages/violations\n *\n * The governance work queue (`adaListViolations`). Filters by status (and by\n * policy/resource via URL params). Each open/acknowledged violation can be\n * transitioned via `adaResolveViolation` — acknowledge, resolve, or waive (a\n * waiver requires a reason, enforced both client-side and at the service).\n */\n\nimport { useState, useCallback } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ShieldAlert,\n ChevronLeft,\n ChevronRight,\n Check,\n CheckCheck,\n FileText,\n Loader2,\n} from 'lucide-react';\nimport {\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { SeverityBadge } from '../../components/SeverityBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useViolations, useResolveViolation } from '../../hooks/useAdapterCloudApi';\nimport { violationStatusLabels, severityRank } from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport type { AdaPolicyViolation, AdaViolationStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function ViolationsListPage() {\n const { navigateTo } = useAdapterCloud();\n const [searchParams] = useSearchParams();\n const policyId = searchParams.get('policyId') ?? undefined;\n const resourceId = searchParams.get('resourceId') ?? undefined;\n\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaViolationStatus | ''>('OPEN');\n const [offset, setOffset] = useState(0);\n const [waiveTarget, setWaiveTarget] = useState<AdaPolicyViolation | null>(null);\n const [waiverReason, setWaiverReason] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useViolations({\n policyId,\n resourceId,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const resolve = useResolveViolation();\n\n const items = [...(query.data?.items ?? [])].sort(\n (a, b) => severityRank[b.severity] - severityRank[a.severity]\n );\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const onError = useCallback(\n (err: unknown) =>\n setActionError(err instanceof Error ? err.message : 'Action failed. Please try again.'),\n []\n );\n\n const transition = useCallback(\n (id: string, newStatus: AdaViolationStatus) => {\n setActionError(null);\n resolve.mutate({ id, status: newStatus }, { onError });\n },\n [resolve, onError]\n );\n\n const confirmWaive = useCallback(() => {\n if (!waiveTarget) return;\n if (!waiverReason.trim()) {\n setActionError(t('adaptercloud.violations.reasonRequired', 'A waiver requires a reason.'));\n return;\n }\n setActionError(null);\n resolve.mutate(\n { id: waiveTarget.id, status: 'WAIVED', waiverReason: waiverReason.trim() },\n {\n onSuccess: () => {\n setWaiveTarget(null);\n setWaiverReason('');\n },\n onError,\n }\n );\n }, [waiveTarget, waiverReason, resolve, onError, t]);\n\n return (\n <PageLayout\n title={t('adaptercloud.violations.title', 'Violations')}\n description={t(\n 'adaptercloud.violations.subtitle',\n 'Work the governance queue — acknowledge, resolve, or waive policy breaches.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaViolationStatus | '');\n setOffset(0);\n }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.violations.allStatuses', 'All statuses')}</option>\n {(Object.keys(violationStatusLabels) as AdaViolationStatus[]).map((s) => (\n <option key={s} value={s}>\n {violationStatusLabels[s]}\n </option>\n ))}\n </select>\n {(policyId || resourceId) && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"inline-flex items-center gap-1.5 rounded-full bg-accent-blue-subtle px-2.5 py-1 text-xs text-accent-blue hover:underline\"\n >\n {t('adaptercloud.violations.clearScope', 'Clear scope ×')}\n </button>\n )}\n </div>\n\n {actionError && (\n <p className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.violations.emptyTitle', 'No violations')}\n emptyDescription={t(\n 'adaptercloud.violations.emptyDescription',\n 'Nothing matches this filter — your estate is clean here.'\n )}\n emptyIcon={<ShieldAlert className=\"h-10 w-10\" />}\n >\n <div className=\"space-y-3\">\n {items.map((v) => {\n const isOpen = v.status === 'OPEN' || v.status === 'ACKNOWLEDGED';\n return (\n <GlassCard key={v.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <SeverityBadge severity={v.severity} />\n <StatusBadge status={v.status} />\n {v.policy && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/policies/${v.policyId}`)}\n className=\"text-xs font-medium text-primary hover:underline\"\n >\n {v.policy.name}\n </button>\n )}\n </div>\n <p className=\"text-sm font-medium text-text-primary\">{v.message}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {t('adaptercloud.violations.detected', 'Detected')} {formatDate(v.detectedAt)}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${v.resourceId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.violations.viewResource', 'View resource')}\n </button>\n </p>\n {v.waiverReason && (\n <p className=\"mt-2 rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary\">\n {t('adaptercloud.violations.waiver', 'Waiver')}: {v.waiverReason}\n </p>\n )}\n </div>\n\n {isOpen && (\n <div className=\"flex shrink-0 flex-wrap gap-2\">\n {v.status === 'OPEN' && (\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'ACKNOWLEDGED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <Check className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.acknowledge', 'Acknowledge')}\n </button>\n )}\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'RESOLVED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50\"\n >\n <CheckCheck className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.resolve', 'Resolve')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => {\n setActionError(null);\n setWaiverReason('');\n setWaiveTarget(v);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <FileText className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.waive', 'Waive')}\n </button>\n </div>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n\n {/* Waive dialog */}\n <ResponsiveDialog\n open={Boolean(waiveTarget)}\n onOpenChange={(open) => {\n if (!open) setWaiveTarget(null);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {t('adaptercloud.violations.waiveTitle', 'Waive violation')}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <div className=\"px-1 py-2\">\n <p className=\"mb-3 text-sm text-text-secondary\">\n {t(\n 'adaptercloud.violations.waivePrompt',\n 'A waiver requires a documented reason and is recorded on the violation.'\n )}\n </p>\n <textarea\n value={waiverReason}\n onChange={(e) => setWaiverReason(e.target.value)}\n rows={4}\n autoFocus\n placeholder={t(\n 'adaptercloud.violations.waiveReasonPlaceholder',\n 'Why is this acceptable?'\n )}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n {actionError && <p className=\"mt-2 text-sm text-status-error-text\">{actionError}</p>}\n </div>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={() => setWaiveTarget(null)}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n {t('adaptercloud.common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={confirmWaive}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90 disabled:opacity-50\"\n >\n {resolve.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {t('adaptercloud.violations.confirmWaive', 'Waive')}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ViolationsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/violations/ViolationsListPage.tsx"],"sourcesContent":["/**\n * Violations Queue Page\n * @module adaptercloud/pages/violations\n *\n * The governance work queue (`adaListViolations`). Filters by status (and by\n * policy/resource via URL params). Each open/acknowledged violation can be\n * transitioned via `adaResolveViolation` — acknowledge, resolve, or waive (a\n * waiver requires a reason, enforced both client-side and at the service).\n */\n\nimport { useState, useCallback } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ShieldAlert,\n ChevronLeft,\n ChevronRight,\n Check,\n CheckCheck,\n FileText,\n Loader2,\n} from 'lucide-react';\nimport {\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { SeverityBadge } from '../../components/SeverityBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useViolations, useResolveViolation } from '../../hooks/useAdapterCloudApi';\nimport { violationStatusLabels, severityRank } from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport type { AdaPolicyViolation, AdaViolationStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function ViolationsListPage() {\n const { navigateTo } = useAdapterCloud();\n const [searchParams] = useSearchParams();\n const policyId = searchParams.get('policyId') ?? undefined;\n const resourceId = searchParams.get('resourceId') ?? undefined;\n\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaViolationStatus | ''>('OPEN');\n const [offset, setOffset] = useState(0);\n const [waiveTarget, setWaiveTarget] = useState<AdaPolicyViolation | null>(null);\n const [waiverReason, setWaiverReason] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useViolations({\n policyId,\n resourceId,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const resolve = useResolveViolation();\n\n // Severity ordering is applied ONLY within the current server page. The queue\n // pages by offset, so this does not globally reorder across pages — a page-2\n // CRITICAL still sorts below a page-1 LOW. Kept as a within-page readability\n // aid (the service has no severity sort arg to make it global).\n const items = [...(query.data?.items ?? [])].sort(\n (a, b) => severityRank[b.severity] - severityRank[a.severity]\n );\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const onError = useCallback(\n (err: unknown) =>\n setActionError(err instanceof Error ? err.message : 'Action failed. Please try again.'),\n []\n );\n\n const transition = useCallback(\n (id: string, newStatus: AdaViolationStatus) => {\n setActionError(null);\n resolve.mutate({ id, status: newStatus }, { onError });\n },\n [resolve, onError]\n );\n\n const confirmWaive = useCallback(() => {\n if (!waiveTarget) return;\n if (!waiverReason.trim()) {\n setActionError(t('adaptercloud.violations.reasonRequired', 'A waiver requires a reason.'));\n return;\n }\n setActionError(null);\n resolve.mutate(\n { id: waiveTarget.id, status: 'WAIVED', waiverReason: waiverReason.trim() },\n {\n onSuccess: () => {\n setWaiveTarget(null);\n setWaiverReason('');\n },\n onError,\n }\n );\n }, [waiveTarget, waiverReason, resolve, onError, t]);\n\n return (\n <PageLayout\n title={t('adaptercloud.violations.title', 'Violations')}\n description={t(\n 'adaptercloud.violations.subtitle',\n 'Work the governance queue — acknowledge, resolve, or waive policy breaches.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaViolationStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.violations.filterByStatus', 'Filter by status')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.violations.allStatuses', 'All statuses')}</option>\n {(Object.keys(violationStatusLabels) as AdaViolationStatus[]).map((s) => (\n <option key={s} value={s}>\n {violationStatusLabels[s]}\n </option>\n ))}\n </select>\n {(policyId || resourceId) && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"inline-flex items-center gap-1.5 rounded-full bg-accent-blue-subtle px-2.5 py-1 text-xs text-accent-blue hover:underline\"\n >\n {t('adaptercloud.violations.clearScope', 'Clear scope ×')}\n </button>\n )}\n </div>\n\n {actionError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n {actionError}\n </p>\n )}\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.violations.emptyTitle', 'No violations')}\n emptyDescription={t(\n 'adaptercloud.violations.emptyDescription',\n 'Nothing matches this filter — your estate is clean here.'\n )}\n emptyIcon={<ShieldAlert className=\"h-10 w-10\" />}\n >\n <div className=\"space-y-3\">\n {items.map((v) => {\n const isOpen = v.status === 'OPEN' || v.status === 'ACKNOWLEDGED';\n return (\n <GlassCard key={v.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <SeverityBadge severity={v.severity} />\n <StatusBadge status={v.status} />\n {v.policy && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/policies/${v.policyId}`)}\n className=\"text-xs font-medium text-accent-blue hover:underline\"\n >\n {v.policy.name}\n </button>\n )}\n </div>\n <p className=\"text-sm font-medium text-text-primary\">{v.message}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {t('adaptercloud.violations.detected', 'Detected')} {formatDate(v.detectedAt)}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${v.resourceId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.violations.viewResource', 'View resource')}\n </button>\n </p>\n {v.waiverReason && (\n <p className=\"mt-2 rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary\">\n {t('adaptercloud.violations.waiver', 'Waiver')}: {v.waiverReason}\n </p>\n )}\n </div>\n\n {isOpen && (\n <div className=\"flex shrink-0 flex-wrap gap-2\">\n {v.status === 'OPEN' && (\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'ACKNOWLEDGED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <Check className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.acknowledge', 'Acknowledge')}\n </button>\n )}\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'RESOLVED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50\"\n >\n <CheckCheck className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.resolve', 'Resolve')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => {\n setActionError(null);\n setWaiverReason('');\n setWaiveTarget(v);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <FileText className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.waive', 'Waive')}\n </button>\n </div>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n\n {/* Waive dialog */}\n <ResponsiveDialog\n open={Boolean(waiveTarget)}\n onOpenChange={(open) => {\n if (!open) setWaiveTarget(null);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {t('adaptercloud.violations.waiveTitle', 'Waive violation')}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <div className=\"px-1 py-2\">\n <label htmlFor=\"ada-waiver-reason\" className=\"mb-1.5 block text-sm text-text-secondary\">\n {t(\n 'adaptercloud.violations.waivePrompt',\n 'A waiver requires a documented reason and is recorded on the violation.'\n )}\n </label>\n <textarea\n id=\"ada-waiver-reason\"\n value={waiverReason}\n onChange={(e) => setWaiverReason(e.target.value)}\n rows={4}\n autoFocus\n aria-label={t('adaptercloud.violations.waiverReason', 'Waiver reason')}\n placeholder={t(\n 'adaptercloud.violations.waiveReasonPlaceholder',\n 'Why is this acceptable?'\n )}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n {actionError && (\n <p role=\"alert\" aria-live=\"polite\" className=\"mt-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\n </div>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={() => setWaiveTarget(null)}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n {t('adaptercloud.common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={confirmWaive}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90 disabled:opacity-50\"\n >\n {resolve.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {t('adaptercloud.violations.confirmWaive', 'Waive')}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,IAAM,IAAY;AAElB,SAAgB,IAAqB;CACnC,IAAM,EAAE,kBAAe,GAAiB,EAClC,CAAC,KAAgB,GAAiB,EAClC,IAAW,EAAa,IAAI,WAAW,IAAI,KAAA,GAC3C,IAAa,EAAa,IAAI,aAAa,IAAI,KAAA,GAE/C,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ,EAEK,CAAC,GAAQ,KAAa,EAAkC,OAAO,EAC/D,CAAC,GAAQ,KAAa,EAAS,EAAE,EACjC,CAAC,GAAa,KAAkB,EAAoC,KAAK,EACzE,CAAC,GAAc,KAAmB,EAAS,GAAG,EAC9C,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAQ,EAAc;EAC1B;EACA;EACA,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW;GAAQ;EACzC,CAAC,EACI,IAAU,GAAqB,EAM/B,IAAQ,CAAC,GAAI,EAAM,MAAM,SAAS,EAAE,CAAE,CAAC,MAC1C,GAAG,MAAM,EAAa,EAAE,YAAY,EAAa,EAAE,UACrD,EACK,IAAU,EAAM,MAAM,SAAS,WAAW,IAE1C,IAAU,GACb,MACC,EAAe,aAAe,QAAQ,EAAI,UAAU,mCAAmC,EACzF,EAAE,CACH,EAEK,IAAa,GAChB,GAAY,MAAkC;AAE7C,EADA,EAAe,KAAK,EACpB,EAAQ,OAAO;GAAE;GAAI,QAAQ;GAAW,EAAE,EAAE,YAAS,CAAC;IAExD,CAAC,GAAS,EAAQ,CACnB,EAEK,IAAe,QAAkB;AAChC,SACL;OAAI,CAAC,EAAa,MAAM,EAAE;AACxB,MAAe,EAAE,0CAA0C,8BAA8B,CAAC;AAC1F;;AAGF,GADA,EAAe,KAAK,EACpB,EAAQ,OACN;IAAE,IAAI,EAAY;IAAI,QAAQ;IAAU,cAAc,EAAa,MAAM;IAAE,EAC3E;IACE,iBAAiB;AAEf,KADA,EAAe,KAAK,EACpB,EAAgB,GAAG;;IAErB;IACD,CACF;;IACA;EAAC;EAAa;EAAc;EAAS;EAAS;EAAE,CAAC;AAEpD,QACE,kBAAC,GAAD;EACE,OAAO,EAAE,iCAAiC,aAAa;EACvD,aAAa,EACX,oCACA,8EACD;YALH;GAOE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM;AAEf,MADA,EAAU,EAAE,OAAO,MAAiC,EACpD,EAAU,EAAE;;KAEd,cAAY,EAAE,0CAA0C,mBAAmB;KAC3E,WAAU;eAPZ,CASE,kBAAC,UAAD;MAAQ,OAAM;gBAAI,EAAE,uCAAuC,eAAe;MAAU,CAAA,EAClF,OAAO,KAAK,EAAsB,CAA0B,KAAK,MACjE,kBAAC,UAAD;MAAgB,OAAO;gBACpB,EAAsB;MAChB,EAFI,EAEJ,CACT,CACK;SACP,KAAY,MACZ,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAW,cAAc;KACxC,WAAU;eAET,EAAE,sCAAsC,gBAAgB;KAClD,CAAA,CAEP;;GAEL,KACC,kBAAC,KAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;cAET;IACC,CAAA;GAGN,kBAAC,GAAD;IACE,WAAW,EAAM;IACjB,SAAS,EAAM;IACf,SAAS,EAAM,WAAW;IAC1B,OAAO,EAAM;IACb,eAAe,KAAK,EAAM,SAAS;IACnC,YAAY,EAAE,sCAAsC,gBAAgB;IACpE,kBAAkB,EAChB,4CACA,2DACD;IACD,WAAW,kBAAC,GAAD,EAAa,WAAU,aAAc,CAAA;cAXlD,CAaE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,MAAM;MAChB,IAAM,IAAS,EAAE,WAAW,UAAU,EAAE,WAAW;AACnD,aACE,kBAAC,GAAD;OAAsB,WAAU;iBAC9B,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,GAAD,EAAe,UAAU,EAAE,UAAY,CAAA;YACvC,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA;YAChC,EAAE,UACD,kBAAC,UAAD;aACE,MAAK;aACL,eAAe,EAAW,aAAa,EAAE,WAAW;aACpD,WAAU;uBAET,EAAE,OAAO;aACH,CAAA;YAEP;;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAyC,EAAE;WAAY,CAAA;UACpE,kBAAC,KAAD;WAAG,WAAU;qBAAb;YACG,EAAE,oCAAoC,WAAW;YAAC;YAAE,EAAW,EAAE,WAAW;YAC5E;YACD,kBAAC,UAAD;aACE,MAAK;aACL,eAAe,EAAW,cAAc,EAAE,aAAa;aACvD,WAAU;uBAET,EAAE,wCAAwC,gBAAgB;aACpD,CAAA;YACP;;UACH,EAAE,gBACD,kBAAC,KAAD;WAAG,WAAU;qBAAb;YACG,EAAE,kCAAkC,SAAS;YAAC;YAAG,EAAE;YAClD;;UAEF;YAEL,KACC,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACG,EAAE,WAAW,UACZ,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,EAAQ;WAClB,eAAe,EAAW,EAAE,IAAI,eAAe;WAC/C,WAAU;qBAJZ,CAME,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA,EAChC,EAAE,uCAAuC,cAAc,CACjD;;UAEX,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,EAAQ;WAClB,eAAe,EAAW,EAAE,IAAI,WAAW;WAC3C,WAAU;qBAJZ,CAME,kBAAC,GAAD,EAAY,WAAU,eAAgB,CAAA,EACrC,EAAE,mCAAmC,UAAU,CACzC;;UACT,kBAAC,UAAD;WACE,MAAK;WACL,UAAU,EAAQ;WAClB,eAAe;AAGb,YAFA,EAAe,KAAK,EACpB,EAAgB,GAAG,EACnB,EAAe,EAAE;;WAEnB,WAAU;qBARZ,CAUE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACnC,EAAE,iCAAiC,QAAQ,CACrC;;UACL;WAEJ;;OACI,EAzEI,EAAE,GAyEN;OAEd;KACE,CAAA,GAEJ,IAAS,KAAK,MACd,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAW;OACrB,eAAe,GAAW,MAAM,KAAK,IAAI,GAAG,IAAI,EAAU,CAAC;OAC3D,WAAU;iBAJZ,CAME,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAClC,EAAE,4BAA4B,WAAW,CACnC;;MACT,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACG,EAAE,+BAA+B,UAAU;QAAC;QAAE,IAAS;QAAE;QAAE,IAAS,EAAM;QACtE;;MACP,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,CAAC;OACX,eAAe,GAAW,MAAM,IAAI,EAAU;OAC9C,WAAU;iBAJZ,CAMG,EAAE,4BAA4B,OAAO,EACtC,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,CAC7B;;MACL;OAEE;;GAGZ,kBAAC,GAAD;IACE,MAAM,EAAQ;IACd,eAAe,MAAS;AACtB,KAAK,KAAM,EAAe,KAAK;;cAGjC,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACG,EAAE,sCAAsC,kBAAkB,EACrC,CAAA,EACD,CAAA;KACzB,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,SAAD;QAAO,SAAQ;QAAoB,WAAU;kBAC1C,EACC,uCACA,0EACD;QACK,CAAA;OACR,kBAAC,YAAD;QACE,IAAG;QACH,OAAO;QACP,WAAW,MAAM,EAAgB,EAAE,OAAO,MAAM;QAChD,MAAM;QACN,WAAA;QACA,cAAY,EAAE,wCAAwC,gBAAgB;QACtE,aAAa,EACX,kDACA,0BACD;QACD,WAAU;QACV,CAAA;OACD,KACC,kBAAC,KAAD;QAAG,MAAK;QAAQ,aAAU;QAAS,WAAU;kBAC1C;QACC,CAAA;OAEF;;KACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAe,KAAK;MACnC,WAAU;gBAET,EAAE,8BAA8B,SAAS;MACnC,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,UAAU,EAAQ;MAClB,SAAS;MACT,WAAU;gBAJZ,CAMG,EAAQ,aAAa,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EACjE,EAAE,wCAAwC,QAAQ,CAC5C;QACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GACR"}
@@ -6,6 +6,7 @@ var t = {
6
6
  CUSTOM: "Custom",
7
7
  DATA_SYSTEM: "Data System",
8
8
  EDGE: "Edge",
9
+ IOT: "IoT",
9
10
  KUBERNETES: "Kubernetes",
10
11
  NETWORK: "Network",
11
12
  ON_PREM: "On-Prem",
@@ -1 +1 @@
1
- {"version":3,"file":"domain.js","names":[],"sources":["../../../src/adaptercloud/utils/domain.ts"],"sourcesContent":["/**\n * AdapterCloud domain helpers\n * @module adaptercloud/utils\n *\n * Human-readable labels and severity/status ordering for the AdapterCloud\n * domain enums, plus a USD-default money formatter (cost records carry their\n * own currency). Keeps page components free of inline enum-to-label maps.\n */\n\nimport type {\n AdaAdapterKind,\n AdaAdapterStatus,\n AdaAuthMethod,\n AdaConnectionStatus,\n AdaDriftStatus,\n AdaPolicyEnforcement,\n AdaPolicyKind,\n AdaResourceState,\n AdaSeverity,\n AdaSyncKind,\n AdaSyncStatus,\n AdaViolationStatus,\n} from '../types';\n\n/** Title-case an UPPER_SNAKE enum value into a readable label. */\nexport function humanizeEnum(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\nexport const adapterKindLabels: Record<AdaAdapterKind, string> = {\n CUSTOM: 'Custom',\n DATA_SYSTEM: 'Data System',\n EDGE: 'Edge',\n KUBERNETES: 'Kubernetes',\n NETWORK: 'Network',\n ON_PREM: 'On-Prem',\n PRIVATE_CLOUD: 'Private Cloud',\n PUBLIC_CLOUD: 'Public Cloud',\n SAAS: 'SaaS',\n};\n\nexport const adapterStatusLabels: Record<AdaAdapterStatus, string> = {\n ARCHIVED: 'Archived',\n DEPRECATED: 'Deprecated',\n DRAFT: 'Draft',\n PUBLISHED: 'Published',\n};\n\nexport const authMethodLabels: Record<AdaAuthMethod, string> = {\n API_KEY: 'API Key',\n CERTIFICATE: 'Certificate',\n IAM_ROLE: 'IAM Role',\n NONE: 'None',\n OAUTH2: 'OAuth2',\n SERVICE_ACCOUNT: 'Service Account',\n};\n\nexport const connectionStatusLabels: Record<AdaConnectionStatus, string> = {\n CONNECTED: 'Connected',\n DEGRADED: 'Degraded',\n DISABLED: 'Disabled',\n ERROR: 'Error',\n PENDING: 'Pending',\n};\n\nexport const resourceStateLabels: Record<AdaResourceState, string> = {\n DELETED: 'Deleted',\n DISCOVERED: 'Discovered',\n DRIFTED: 'Drifted',\n ORPHANED: 'Orphaned',\n RECONCILED: 'Reconciled',\n};\n\nexport const policyKindLabels: Record<AdaPolicyKind, string> = {\n COMPLIANCE: 'Compliance',\n COST: 'Cost',\n GUARDRAIL: 'Guardrail',\n NAMING: 'Naming',\n SECURITY: 'Security',\n TAGGING: 'Tagging',\n};\n\nexport const policyEnforcementLabels: Record<AdaPolicyEnforcement, string> = {\n ADVISORY: 'Advisory',\n BLOCK: 'Block',\n WARN: 'Warn',\n};\n\nexport const severityLabels: Record<AdaSeverity, string> = {\n CRITICAL: 'Critical',\n HIGH: 'High',\n INFO: 'Info',\n LOW: 'Low',\n MEDIUM: 'Medium',\n};\n\nexport const violationStatusLabels: Record<AdaViolationStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n OPEN: 'Open',\n RESOLVED: 'Resolved',\n WAIVED: 'Waived',\n};\n\nexport const driftStatusLabels: Record<AdaDriftStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n DETECTED: 'Detected',\n IGNORED: 'Ignored',\n REMEDIATED: 'Remediated',\n};\n\nexport const syncKindLabels: Record<AdaSyncKind, string> = {\n COST_INGEST: 'Cost Ingest',\n DISCOVERY: 'Discovery',\n FULL: 'Full',\n RECONCILE: 'Reconcile',\n};\n\nexport const syncStatusLabels: Record<AdaSyncStatus, string> = {\n CANCELLED: 'Cancelled',\n FAILED: 'Failed',\n QUEUED: 'Queued',\n RUNNING: 'Running',\n SUCCEEDED: 'Succeeded',\n};\n\n/** Highest = most urgent. Used to sort violations/drift queues. */\nexport const severityRank: Record<AdaSeverity, number> = {\n CRITICAL: 5,\n HIGH: 4,\n MEDIUM: 3,\n LOW: 2,\n INFO: 1,\n};\n\n/** Tailwind classes (semantic tokens only) for a severity pill. */\nexport const severityPillClass: Record<AdaSeverity, string> = {\n CRITICAL: 'bg-status-error-bg-subtle text-status-error-text',\n HIGH: 'bg-status-error-bg-subtle text-status-error-text',\n MEDIUM: 'bg-status-warning-bg-subtle text-status-warning-text',\n LOW: 'bg-accent-blue-subtle text-accent-blue',\n INFO: 'bg-bg-sunken text-text-secondary',\n};\n\n/**\n * Format a money amount with its currency. AdapterCloud cost is multi-cloud and\n * typically USD; cost records carry an explicit currency code.\n */\nexport function formatMoney(amount: number, currency = 'USD'): string {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(amount);\n } catch {\n return `${currency} ${amount.toFixed(2)}`;\n }\n}\n"],"mappings":";AAyBA,SAAgB,EAAa,GAAuB;AAClD,QAAO,EACJ,aAAa,CACb,MAAM,IAAI,CACV,KAAK,MAAS,EAAK,OAAO,EAAE,CAAC,aAAa,GAAG,EAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,IAAI;;AAGd,IAAa,IAAoD;CAC/D,QAAQ;CACR,aAAa;CACb,MAAM;CACN,YAAY;CACZ,SAAS;CACT,SAAS;CACT,eAAe;CACf,cAAc;CACd,MAAM;CACP,EAEY,IAAwD;CACnE,UAAU;CACV,YAAY;CACZ,OAAO;CACP,WAAW;CACZ,EAEY,IAAkD;CAC7D,SAAS;CACT,aAAa;CACb,UAAU;CACV,MAAM;CACN,QAAQ;CACR,iBAAiB;CAClB,EAEY,IAA8D;CACzE,WAAW;CACX,UAAU;CACV,UAAU;CACV,OAAO;CACP,SAAS;CACV,EAEY,IAAwD;CACnE,SAAS;CACT,YAAY;CACZ,SAAS;CACT,UAAU;CACV,YAAY;CACb,EAEY,IAAkD;CAC7D,YAAY;CACZ,MAAM;CACN,WAAW;CACX,QAAQ;CACR,UAAU;CACV,SAAS;CACV,EAEY,IAAgE;CAC3E,UAAU;CACV,OAAO;CACP,MAAM;CACP,EAEY,IAA8C;CACzD,UAAU;CACV,MAAM;CACN,MAAM;CACN,KAAK;CACL,QAAQ;CACT,EAEY,IAA4D;CACvE,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACT,EAEY,IAAoD;CAC/D,cAAc;CACd,UAAU;CACV,SAAS;CACT,YAAY;CACb,EAEY,IAA8C;CACzD,aAAa;CACb,WAAW;CACX,MAAM;CACN,WAAW;CACZ,EAEY,IAAkD;CAC7D,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,WAAW;CACZ,EAGY,IAA4C;CACvD,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP,EAGY,IAAiD;CAC5D,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP;AAMD,SAAgB,EAAY,GAAgB,IAAW,OAAe;AACpE,KAAI;AACF,SAAO,IAAI,KAAK,aAAa,SAAS;GACpC,OAAO;GACP;GACA,uBAAuB;GACvB,uBAAuB;GACxB,CAAC,CAAC,OAAO,EAAO;SACX;AACN,SAAO,GAAG,EAAS,GAAG,EAAO,QAAQ,EAAE"}
1
+ {"version":3,"file":"domain.js","names":[],"sources":["../../../src/adaptercloud/utils/domain.ts"],"sourcesContent":["/**\n * AdapterCloud domain helpers\n * @module adaptercloud/utils\n *\n * Human-readable labels and severity/status ordering for the AdapterCloud\n * domain enums, plus a USD-default money formatter (cost records carry their\n * own currency). Keeps page components free of inline enum-to-label maps.\n */\n\nimport type {\n AdaAdapterKind,\n AdaAdapterStatus,\n AdaAuthMethod,\n AdaConnectionStatus,\n AdaDriftStatus,\n AdaPolicyEnforcement,\n AdaPolicyKind,\n AdaResourceState,\n AdaSeverity,\n AdaSyncKind,\n AdaSyncStatus,\n AdaViolationStatus,\n} from '../types';\n\n/** Title-case an UPPER_SNAKE enum value into a readable label. */\nexport function humanizeEnum(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\nexport const adapterKindLabels: Record<AdaAdapterKind, string> = {\n CUSTOM: 'Custom',\n DATA_SYSTEM: 'Data System',\n EDGE: 'Edge',\n IOT: 'IoT',\n KUBERNETES: 'Kubernetes',\n NETWORK: 'Network',\n ON_PREM: 'On-Prem',\n PRIVATE_CLOUD: 'Private Cloud',\n PUBLIC_CLOUD: 'Public Cloud',\n SAAS: 'SaaS',\n};\n\nexport const adapterStatusLabels: Record<AdaAdapterStatus, string> = {\n ARCHIVED: 'Archived',\n DEPRECATED: 'Deprecated',\n DRAFT: 'Draft',\n PUBLISHED: 'Published',\n};\n\nexport const authMethodLabels: Record<AdaAuthMethod, string> = {\n API_KEY: 'API Key',\n CERTIFICATE: 'Certificate',\n IAM_ROLE: 'IAM Role',\n NONE: 'None',\n OAUTH2: 'OAuth2',\n SERVICE_ACCOUNT: 'Service Account',\n};\n\nexport const connectionStatusLabels: Record<AdaConnectionStatus, string> = {\n CONNECTED: 'Connected',\n DEGRADED: 'Degraded',\n DISABLED: 'Disabled',\n ERROR: 'Error',\n PENDING: 'Pending',\n};\n\nexport const resourceStateLabels: Record<AdaResourceState, string> = {\n DELETED: 'Deleted',\n DISCOVERED: 'Discovered',\n DRIFTED: 'Drifted',\n ORPHANED: 'Orphaned',\n RECONCILED: 'Reconciled',\n};\n\nexport const policyKindLabels: Record<AdaPolicyKind, string> = {\n COMPLIANCE: 'Compliance',\n COST: 'Cost',\n GUARDRAIL: 'Guardrail',\n NAMING: 'Naming',\n SECURITY: 'Security',\n TAGGING: 'Tagging',\n};\n\nexport const policyEnforcementLabels: Record<AdaPolicyEnforcement, string> = {\n ADVISORY: 'Advisory',\n BLOCK: 'Block',\n WARN: 'Warn',\n};\n\nexport const severityLabels: Record<AdaSeverity, string> = {\n CRITICAL: 'Critical',\n HIGH: 'High',\n INFO: 'Info',\n LOW: 'Low',\n MEDIUM: 'Medium',\n};\n\nexport const violationStatusLabels: Record<AdaViolationStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n OPEN: 'Open',\n RESOLVED: 'Resolved',\n WAIVED: 'Waived',\n};\n\nexport const driftStatusLabels: Record<AdaDriftStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n DETECTED: 'Detected',\n IGNORED: 'Ignored',\n REMEDIATED: 'Remediated',\n};\n\nexport const syncKindLabels: Record<AdaSyncKind, string> = {\n COST_INGEST: 'Cost Ingest',\n DISCOVERY: 'Discovery',\n FULL: 'Full',\n RECONCILE: 'Reconcile',\n};\n\nexport const syncStatusLabels: Record<AdaSyncStatus, string> = {\n CANCELLED: 'Cancelled',\n FAILED: 'Failed',\n QUEUED: 'Queued',\n RUNNING: 'Running',\n SUCCEEDED: 'Succeeded',\n};\n\n/** Highest = most urgent. Used to sort violations/drift queues. */\nexport const severityRank: Record<AdaSeverity, number> = {\n CRITICAL: 5,\n HIGH: 4,\n MEDIUM: 3,\n LOW: 2,\n INFO: 1,\n};\n\n/** Tailwind classes (semantic tokens only) for a severity pill. */\nexport const severityPillClass: Record<AdaSeverity, string> = {\n CRITICAL: 'bg-status-error-bg-subtle text-status-error-text',\n HIGH: 'bg-status-error-bg-subtle text-status-error-text',\n MEDIUM: 'bg-status-warning-bg-subtle text-status-warning-text',\n LOW: 'bg-accent-blue-subtle text-accent-blue',\n INFO: 'bg-bg-sunken text-text-secondary',\n};\n\n/**\n * Format a money amount with its currency. AdapterCloud cost is multi-cloud and\n * typically USD; cost records carry an explicit currency code.\n */\nexport function formatMoney(amount: number, currency = 'USD'): string {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(amount);\n } catch {\n return `${currency} ${amount.toFixed(2)}`;\n }\n}\n"],"mappings":";AAyBA,SAAgB,EAAa,GAAuB;AAClD,QAAO,EACJ,aAAa,CACb,MAAM,IAAI,CACV,KAAK,MAAS,EAAK,OAAO,EAAE,CAAC,aAAa,GAAG,EAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,IAAI;;AAGd,IAAa,IAAoD;CAC/D,QAAQ;CACR,aAAa;CACb,MAAM;CACN,KAAK;CACL,YAAY;CACZ,SAAS;CACT,SAAS;CACT,eAAe;CACf,cAAc;CACd,MAAM;CACP,EAEY,IAAwD;CACnE,UAAU;CACV,YAAY;CACZ,OAAO;CACP,WAAW;CACZ,EAEY,IAAkD;CAC7D,SAAS;CACT,aAAa;CACb,UAAU;CACV,MAAM;CACN,QAAQ;CACR,iBAAiB;CAClB,EAEY,IAA8D;CACzE,WAAW;CACX,UAAU;CACV,UAAU;CACV,OAAO;CACP,SAAS;CACV,EAEY,IAAwD;CACnE,SAAS;CACT,YAAY;CACZ,SAAS;CACT,UAAU;CACV,YAAY;CACb,EAEY,IAAkD;CAC7D,YAAY;CACZ,MAAM;CACN,WAAW;CACX,QAAQ;CACR,UAAU;CACV,SAAS;CACV,EAEY,IAAgE;CAC3E,UAAU;CACV,OAAO;CACP,MAAM;CACP,EAEY,IAA8C;CACzD,UAAU;CACV,MAAM;CACN,MAAM;CACN,KAAK;CACL,QAAQ;CACT,EAEY,IAA4D;CACvE,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACT,EAEY,IAAoD;CAC/D,cAAc;CACd,UAAU;CACV,SAAS;CACT,YAAY;CACb,EAEY,IAA8C;CACzD,aAAa;CACb,WAAW;CACX,MAAM;CACN,WAAW;CACZ,EAEY,IAAkD;CAC7D,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,WAAW;CACZ,EAGY,IAA4C;CACvD,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP,EAGY,IAAiD;CAC5D,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP;AAMD,SAAgB,EAAY,GAAgB,IAAW,OAAe;AACpE,KAAI;AACF,SAAO,IAAI,KAAK,aAAa,SAAS;GACpC,OAAO;GACP;GACA,uBAAuB;GACvB,uBAAuB;GACxB,CAAC,CAAC,OAAO,EAAO;SACX;AACN,SAAO,GAAG,EAAS,GAAG,EAAO,QAAQ,EAAE"}
@@ -1,16 +1,7 @@
1
1
  //#region src/adaptercloud/utils/formatters.ts
2
2
  function e(e, t) {
3
- return new Intl.NumberFormat("en-IN", {
4
- style: "currency",
5
- currency: "INR",
6
- minimumFractionDigits: 2,
7
- maximumFractionDigits: 2,
8
- ...t
9
- }).format(e);
10
- }
11
- function t(e, t) {
12
3
  let n = typeof e == "string" ? new Date(e) : e;
13
- return new Intl.DateTimeFormat("en-IN", {
4
+ return new Intl.DateTimeFormat("en-GB", {
14
5
  day: "numeric",
15
6
  month: "short",
16
7
  year: "numeric",
@@ -20,7 +11,7 @@ function t(e, t) {
20
11
  ...t
21
12
  }).format(n);
22
13
  }
23
- function n(e) {
14
+ function t(e) {
24
15
  let t = typeof e == "string" ? new Date(e) : e, n = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), r = Math.floor(n / 1e3), i = Math.floor(r / 60), a = Math.floor(i / 60), o = Math.floor(a / 24), s = Math.floor(o / 7), c = Math.floor(o / 30);
25
16
  if (r < 60) return "just now";
26
17
  if (i < 60) return `${i} min${i === 1 ? "" : "s"} ago`;
@@ -31,10 +22,7 @@ function n(e) {
31
22
  let l = Math.floor(o / 365);
32
23
  return `${l} year${l === 1 ? "" : "s"} ago`;
33
24
  }
34
- function r(e, t) {
35
- return new Intl.NumberFormat("en-IN", t).format(e);
36
- }
37
25
  //#endregion
38
- export { e as formatCurrency, t as formatDate, r as formatNumber, n as formatRelativeTime };
26
+ export { e as formatDate, t as formatRelativeTime };
39
27
 
40
28
  //# sourceMappingURL=formatters.js.map