@burdenoff/microfe-adaptercloud 2026.706.1 → 2026.706.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adaptercloud/AdapterCloudRoot.js +52 -44
- package/dist/adaptercloud/AdapterCloudRoot.js.map +1 -1
- package/dist/adaptercloud/AdapterCloudRoutes.js +22 -14
- package/dist/adaptercloud/AdapterCloudRoutes.js.map +1 -1
- package/dist/adaptercloud/components/ConfirmDialog.js +27 -0
- package/dist/adaptercloud/components/ConfirmDialog.js.map +1 -0
- package/dist/adaptercloud/components/DataState.js +1 -1
- package/dist/adaptercloud/components/DataState.js.map +1 -1
- package/dist/adaptercloud/components/viz/BarChart.js +32 -0
- package/dist/adaptercloud/components/viz/BarChart.js.map +1 -0
- package/dist/adaptercloud/components/viz/Sparkline.js +50 -0
- package/dist/adaptercloud/components/viz/Sparkline.js.map +1 -0
- package/dist/adaptercloud/components/viz/StackedBar.js +1 -0
- package/dist/adaptercloud/components/viz/TopologyGraph.js +96 -0
- package/dist/adaptercloud/components/viz/TopologyGraph.js.map +1 -0
- package/dist/adaptercloud/components/viz/index.js +4 -0
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js +71 -34
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
- package/dist/adaptercloud/pages/OverviewPage.js +159 -156
- package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
- package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js +179 -113
- package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/adapters/AdapterFormPage.js +263 -179
- package/dist/adaptercloud/pages/adapters/AdapterFormPage.js.map +1 -1
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +2 -0
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +141 -124
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionFormPage.js +2 -0
- package/dist/adaptercloud/pages/connections/ConnectionFormPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +158 -93
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
- package/dist/adaptercloud/pages/costs/CostsPage.js +183 -109
- package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -1
- package/dist/adaptercloud/pages/drift/DriftListPage.js +172 -71
- package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -1
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js +179 -96
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -1
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +109 -91
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js +211 -184
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +183 -127
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js +121 -84
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -1
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +236 -153
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -1
- package/dist/adaptercloud/pages/topology/TopologyPage.js +397 -0
- package/dist/adaptercloud/pages/topology/TopologyPage.js.map +1 -0
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js +192 -131
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,132 +1,233 @@
|
|
|
1
1
|
import { useAdapterCloud as e } from "../../context/AdapterCloudContext.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
2
|
+
import { cn as t } from "../../utils/cn.js";
|
|
3
|
+
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
|
+
import { driftStatusLabels as r, severityRank as i } from "../../utils/domain.js";
|
|
5
|
+
import { StatusBadge as a } from "../../components/StatusBadge.js";
|
|
6
|
+
import { SeverityBadge as o } from "../../components/SeverityBadge.js";
|
|
7
|
+
import { DataState as s } from "../../components/DataState.js";
|
|
8
|
+
import { useDriftRecords as c, useRemediateDrift as l } from "../../hooks/useAdapterCloudApi.js";
|
|
9
|
+
import { formatDate as u } from "../../utils/formatters.js";
|
|
10
|
+
import { ConfirmDialog as d } from "../../components/ConfirmDialog.js";
|
|
11
|
+
import { useCallback as f, useMemo as p, useState as m } from "react";
|
|
12
|
+
import { useI18n as h } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
|
+
import { ArrowRight as g, GitCompareArrows as _, Loader2 as v, Wrench as y } from "lucide-react";
|
|
14
|
+
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
15
|
+
import { GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
14
16
|
//#region src/adaptercloud/pages/drift/DriftListPage.tsx
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
var C = [
|
|
18
|
+
{
|
|
19
|
+
status: "DETECTED",
|
|
20
|
+
className: "bg-status-warning-bg-subtle text-status-warning-text"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
status: "ACKNOWLEDGED",
|
|
24
|
+
className: "bg-accent-blue-subtle text-accent-blue"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
status: "REMEDIATED",
|
|
28
|
+
className: "bg-status-success-bg-subtle text-status-success-text"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
status: "IGNORED",
|
|
32
|
+
className: "bg-bg-sunken text-text-secondary"
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
function w(e) {
|
|
36
|
+
return e === null || [
|
|
37
|
+
"string",
|
|
38
|
+
"number",
|
|
39
|
+
"boolean"
|
|
40
|
+
].includes(typeof e);
|
|
41
|
+
}
|
|
42
|
+
function T(e) {
|
|
43
|
+
return e == null ? "—" : typeof e == "string" ? e : JSON.stringify(e);
|
|
44
|
+
}
|
|
45
|
+
function E() {
|
|
46
|
+
let { navigateTo: E } = e(), { t: D } = h(), O = f((e, t) => {
|
|
47
|
+
let n = D(e);
|
|
18
48
|
return n === e ? t : n;
|
|
19
|
-
}, [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
49
|
+
}, [D]), [k, A] = m("DETECTED"), [j, M] = m(null), [N, P] = m(null), F = c({ status: k || void 0 }), I = l(), L = c({}), R = p(() => {
|
|
50
|
+
let e = {
|
|
51
|
+
DETECTED: 0,
|
|
52
|
+
ACKNOWLEDGED: 0,
|
|
53
|
+
REMEDIATED: 0,
|
|
54
|
+
IGNORED: 0
|
|
55
|
+
};
|
|
56
|
+
for (let t of L.data ?? []) e[t.status] += 1;
|
|
57
|
+
return e;
|
|
58
|
+
}, [L.data]), z = (L.data?.length ?? 0) > 0, B = [...F.data ?? []].sort((e, t) => i[t.severity] - i[e.severity]), V = I.isPending ? I.variables : void 0, H = f((e) => {
|
|
59
|
+
M(null), I.mutate(e, {
|
|
60
|
+
onSuccess: () => P(null),
|
|
61
|
+
onError: (e) => M(e instanceof Error ? e.message : "Failed to remediate drift.")
|
|
62
|
+
});
|
|
63
|
+
}, [I]);
|
|
64
|
+
return /* @__PURE__ */ x(n, {
|
|
65
|
+
title: O("adaptercloud.drift.title", "Drift"),
|
|
66
|
+
description: O("adaptercloud.drift.subtitle", "Divergences between observed and desired state, surfaced during reconciliation."),
|
|
25
67
|
children: [
|
|
26
|
-
/* @__PURE__ */
|
|
68
|
+
z && /* @__PURE__ */ b("div", {
|
|
69
|
+
className: "mb-4 flex flex-wrap gap-2",
|
|
70
|
+
children: C.map((e) => {
|
|
71
|
+
let n = k === e.status;
|
|
72
|
+
return /* @__PURE__ */ x("button", {
|
|
73
|
+
type: "button",
|
|
74
|
+
onClick: () => A(n ? "" : e.status),
|
|
75
|
+
"aria-pressed": n,
|
|
76
|
+
className: t("inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-sm font-medium transition-shadow", e.className, n && "ring-2 ring-inset ring-[var(--color-focus-ring)]"),
|
|
77
|
+
children: [/* @__PURE__ */ b("span", {
|
|
78
|
+
className: "text-base font-semibold tabular-nums",
|
|
79
|
+
children: R[e.status]
|
|
80
|
+
}), /* @__PURE__ */ b("span", { children: r[e.status].toLowerCase() })]
|
|
81
|
+
}, e.status);
|
|
82
|
+
})
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ b("div", {
|
|
27
85
|
className: "mb-6 flex flex-wrap gap-3",
|
|
28
|
-
children: /* @__PURE__ */
|
|
29
|
-
value:
|
|
30
|
-
onChange: (e) =>
|
|
86
|
+
children: /* @__PURE__ */ x("select", {
|
|
87
|
+
value: k,
|
|
88
|
+
onChange: (e) => A(e.target.value),
|
|
89
|
+
"aria-label": O("adaptercloud.drift.filterByStatus", "Filter by status"),
|
|
31
90
|
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)]",
|
|
32
|
-
children: [/* @__PURE__ */
|
|
91
|
+
children: [/* @__PURE__ */ b("option", {
|
|
33
92
|
value: "",
|
|
34
|
-
children:
|
|
35
|
-
}), Object.keys(
|
|
93
|
+
children: O("adaptercloud.drift.allStatuses", "All statuses")
|
|
94
|
+
}), Object.keys(r).map((e) => /* @__PURE__ */ b("option", {
|
|
36
95
|
value: e,
|
|
37
|
-
children:
|
|
96
|
+
children: r[e]
|
|
38
97
|
}, e))]
|
|
39
98
|
})
|
|
40
99
|
}),
|
|
41
|
-
|
|
100
|
+
j && /* @__PURE__ */ b("p", {
|
|
101
|
+
role: "alert",
|
|
102
|
+
"aria-live": "polite",
|
|
42
103
|
className: "mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
43
|
-
children:
|
|
104
|
+
children: j
|
|
44
105
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
46
|
-
isLoading:
|
|
47
|
-
isError:
|
|
48
|
-
isEmpty:
|
|
49
|
-
error:
|
|
50
|
-
onRetry: () => void
|
|
51
|
-
emptyTitle:
|
|
52
|
-
emptyDescription:
|
|
53
|
-
emptyIcon: /* @__PURE__ */
|
|
54
|
-
children: /* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ b(s, {
|
|
107
|
+
isLoading: F.isLoading,
|
|
108
|
+
isError: F.isError,
|
|
109
|
+
isEmpty: B.length === 0,
|
|
110
|
+
error: F.error,
|
|
111
|
+
onRetry: () => void F.refetch(),
|
|
112
|
+
emptyTitle: O("adaptercloud.drift.emptyTitle", "No drift"),
|
|
113
|
+
emptyDescription: O("adaptercloud.drift.emptyDescription", "Nothing matches this filter — observed state matches desired state."),
|
|
114
|
+
emptyIcon: /* @__PURE__ */ b(_, { className: "h-10 w-10" }),
|
|
115
|
+
children: /* @__PURE__ */ b("div", {
|
|
55
116
|
className: "space-y-3",
|
|
56
|
-
children:
|
|
117
|
+
children: B.map((e) => {
|
|
57
118
|
let t = e.status === "DETECTED" || e.status === "ACKNOWLEDGED";
|
|
58
|
-
return /* @__PURE__ */
|
|
119
|
+
return /* @__PURE__ */ b(S, {
|
|
59
120
|
className: "p-5",
|
|
60
|
-
children: /* @__PURE__ */
|
|
121
|
+
children: /* @__PURE__ */ x("div", {
|
|
61
122
|
className: "flex flex-wrap items-start justify-between gap-3",
|
|
62
|
-
children: [/* @__PURE__ */
|
|
123
|
+
children: [/* @__PURE__ */ x("div", {
|
|
63
124
|
className: "min-w-0 flex-1",
|
|
64
125
|
children: [
|
|
65
|
-
/* @__PURE__ */
|
|
126
|
+
/* @__PURE__ */ x("div", {
|
|
66
127
|
className: "mb-1.5 flex flex-wrap items-center gap-2",
|
|
67
|
-
children: [/* @__PURE__ */
|
|
128
|
+
children: [/* @__PURE__ */ b(o, { severity: e.severity }), /* @__PURE__ */ b(a, {
|
|
68
129
|
status: e.status,
|
|
69
|
-
label:
|
|
130
|
+
label: r[e.status]
|
|
70
131
|
})]
|
|
71
132
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ b("p", {
|
|
73
134
|
className: "break-all font-mono text-sm font-medium text-text-primary",
|
|
74
135
|
children: e.attributePath
|
|
75
136
|
}),
|
|
76
|
-
/* @__PURE__ */
|
|
137
|
+
w(e.expectedValue) && w(e.observedValue) ? /* @__PURE__ */ x("div", {
|
|
138
|
+
className: "mt-3 flex flex-wrap items-end gap-2",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ x("div", {
|
|
141
|
+
className: "min-w-0",
|
|
142
|
+
children: [/* @__PURE__ */ b("p", {
|
|
143
|
+
className: "mb-1 text-xs font-semibold uppercase tracking-wide text-text-muted",
|
|
144
|
+
children: O("adaptercloud.drift.expected", "Expected")
|
|
145
|
+
}), /* @__PURE__ */ b("span", {
|
|
146
|
+
className: "inline-block max-w-full break-all rounded-md bg-status-error-bg-subtle px-2.5 py-1 font-mono text-xs text-status-error-text",
|
|
147
|
+
children: T(e.expectedValue)
|
|
148
|
+
})]
|
|
149
|
+
}),
|
|
150
|
+
/* @__PURE__ */ b(g, { className: "mb-1.5 h-4 w-4 shrink-0 text-text-tertiary" }),
|
|
151
|
+
/* @__PURE__ */ x("div", {
|
|
152
|
+
className: "min-w-0",
|
|
153
|
+
children: [/* @__PURE__ */ b("p", {
|
|
154
|
+
className: "mb-1 text-xs font-semibold uppercase tracking-wide text-text-muted",
|
|
155
|
+
children: O("adaptercloud.drift.observed", "Observed")
|
|
156
|
+
}), /* @__PURE__ */ b("span", {
|
|
157
|
+
className: "inline-block max-w-full break-all rounded-md bg-status-success-bg-subtle px-2.5 py-1 font-mono text-xs text-status-success-text",
|
|
158
|
+
children: T(e.observedValue)
|
|
159
|
+
})]
|
|
160
|
+
})
|
|
161
|
+
]
|
|
162
|
+
}) : /* @__PURE__ */ x("div", {
|
|
77
163
|
className: "mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2",
|
|
78
|
-
children: [/* @__PURE__ */
|
|
164
|
+
children: [/* @__PURE__ */ x("div", {
|
|
79
165
|
className: "rounded-lg bg-bg-sunken p-3",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
166
|
+
children: [/* @__PURE__ */ b("p", {
|
|
81
167
|
className: "mb-1 text-xs font-semibold text-text-secondary",
|
|
82
|
-
children:
|
|
83
|
-
}), /* @__PURE__ */
|
|
84
|
-
className: "overflow-auto text-xs text-text
|
|
168
|
+
children: O("adaptercloud.drift.expected", "Expected")
|
|
169
|
+
}), /* @__PURE__ */ b("pre", {
|
|
170
|
+
className: "overflow-auto text-xs text-status-error-text",
|
|
85
171
|
children: JSON.stringify(e.expectedValue, null, 2)
|
|
86
172
|
})]
|
|
87
|
-
}), /* @__PURE__ */
|
|
173
|
+
}), /* @__PURE__ */ x("div", {
|
|
88
174
|
className: "rounded-lg bg-bg-sunken p-3",
|
|
89
|
-
children: [/* @__PURE__ */
|
|
175
|
+
children: [/* @__PURE__ */ b("p", {
|
|
90
176
|
className: "mb-1 text-xs font-semibold text-text-secondary",
|
|
91
|
-
children:
|
|
92
|
-
}), /* @__PURE__ */
|
|
93
|
-
className: "overflow-auto text-xs text-text
|
|
177
|
+
children: O("adaptercloud.drift.observed", "Observed")
|
|
178
|
+
}), /* @__PURE__ */ b("pre", {
|
|
179
|
+
className: "overflow-auto text-xs text-status-success-text",
|
|
94
180
|
children: JSON.stringify(e.observedValue, null, 2)
|
|
95
181
|
})]
|
|
96
182
|
})]
|
|
97
183
|
}),
|
|
98
|
-
/* @__PURE__ */
|
|
184
|
+
/* @__PURE__ */ x("p", {
|
|
99
185
|
className: "mt-2 text-xs text-text-secondary",
|
|
100
186
|
children: [
|
|
101
|
-
|
|
187
|
+
O("adaptercloud.drift.detected", "Detected"),
|
|
102
188
|
" ",
|
|
103
|
-
|
|
189
|
+
u(e.detectedAt),
|
|
104
190
|
" · ",
|
|
105
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ b("button", {
|
|
106
192
|
type: "button",
|
|
107
|
-
onClick: () =>
|
|
193
|
+
onClick: () => E(`/resources/${e.resourceId}`),
|
|
108
194
|
className: "hover:underline",
|
|
109
|
-
children:
|
|
195
|
+
children: O("adaptercloud.drift.viewResource", "View resource")
|
|
110
196
|
})
|
|
111
197
|
]
|
|
112
198
|
})
|
|
113
199
|
]
|
|
114
|
-
}), t && /* @__PURE__ */
|
|
200
|
+
}), t && /* @__PURE__ */ x("button", {
|
|
115
201
|
type: "button",
|
|
116
|
-
disabled:
|
|
117
|
-
onClick: () =>
|
|
202
|
+
disabled: V === e.id,
|
|
203
|
+
onClick: () => {
|
|
204
|
+
M(null), P(e);
|
|
205
|
+
},
|
|
118
206
|
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-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50",
|
|
119
|
-
children: [
|
|
207
|
+
children: [V === e.id ? /* @__PURE__ */ b(v, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ b(y, { className: "h-3.5 w-3.5" }), O("adaptercloud.drift.remediate", "Remediate")]
|
|
120
208
|
})]
|
|
121
209
|
})
|
|
122
210
|
}, e.id);
|
|
123
211
|
})
|
|
124
212
|
})
|
|
213
|
+
}),
|
|
214
|
+
/* @__PURE__ */ b(d, {
|
|
215
|
+
open: !!N,
|
|
216
|
+
onOpenChange: (e) => {
|
|
217
|
+
e || P(null);
|
|
218
|
+
},
|
|
219
|
+
title: O("adaptercloud.drift.remediateTitle", "Mark this drift remediated?"),
|
|
220
|
+
description: O("adaptercloud.drift.remediatePrompt", "This records the divergence as remediated. Confirm only if the observed state now matches the desired state."),
|
|
221
|
+
confirmLabel: O("adaptercloud.drift.remediate", "Remediate"),
|
|
222
|
+
cancelLabel: O("adaptercloud.common.cancel", "Cancel"),
|
|
223
|
+
onConfirm: () => N && H(N.id),
|
|
224
|
+
isPending: !!N && V === N?.id,
|
|
225
|
+
tone: "primary"
|
|
125
226
|
})
|
|
126
227
|
]
|
|
127
228
|
});
|
|
128
229
|
}
|
|
129
230
|
//#endregion
|
|
130
|
-
export {
|
|
231
|
+
export { E as DriftListPage };
|
|
131
232
|
|
|
132
233
|
//# sourceMappingURL=DriftListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DriftListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/drift/DriftListPage.tsx"],"sourcesContent":["/**\n * Drift Board Page\n * @module adaptercloud/pages/drift\n *\n * Divergences between observed and desired state (`adaListDriftRecords`).\n * Filters by status; each detected/acknowledged record can be remediated via\n * `adaRemediateDrift`.\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { GitCompareArrows, Wrench, Loader2 } from 'lucide-react';\nimport { GlassCard } 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 { useDriftRecords, useRemediateDrift } from '../../hooks/useAdapterCloudApi';\nimport { driftStatusLabels, severityRank } from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport type { AdaDriftStatus } from '../../types';\n\nexport function DriftListPage() {\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<AdaDriftStatus | ''>('DETECTED');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useDriftRecords({ status: status || undefined });\n const remediate = useRemediateDrift();\n\n const items = [...(query.data ?? [])].sort(\n (a, b) => severityRank[b.severity] - severityRank[a.severity]\n );\n\n const handleRemediate = useCallback(\n (id: string) => {\n setActionError(null);\n remediate.mutate(id, {\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Failed to remediate drift.'),\n });\n },\n [remediate]\n );\n\n return (\n <PageLayout\n title={t('adaptercloud.drift.title', 'Drift')}\n description={t(\n 'adaptercloud.drift.subtitle',\n 'Divergences between observed and desired state, surfaced during reconciliation.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as AdaDriftStatus | '')}\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.drift.allStatuses', 'All statuses')}</option>\n {(Object.keys(driftStatusLabels) as AdaDriftStatus[]).map((s) => (\n <option key={s} value={s}>\n {driftStatusLabels[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.drift.emptyTitle', 'No drift')}\n emptyDescription={t(\n 'adaptercloud.drift.emptyDescription',\n 'Nothing matches this filter — observed state matches desired state.'\n )}\n emptyIcon={<GitCompareArrows className=\"h-10 w-10\" />}\n >\n <div className=\"space-y-3\">\n {items.map((d) => {\n const canRemediate = d.status === 'DETECTED' || d.status === 'ACKNOWLEDGED';\n return (\n <GlassCard key={d.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={d.severity} />\n <StatusBadge status={d.status} label={driftStatusLabels[d.status]} />\n </div>\n <p className=\"break-all font-mono text-sm font-medium text-text-primary\">\n {d.attributePath}\n </p>\n <div className=\"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div className=\"rounded-lg bg-bg-sunken p-3\">\n <p className=\"mb-1 text-xs font-semibold text-text-secondary\">\n {t('adaptercloud.drift.expected', 'Expected')}\n </p>\n <pre className=\"overflow-auto text-xs text-text-primary\">\n {JSON.stringify(d.expectedValue, null, 2)}\n </pre>\n </div>\n <div className=\"rounded-lg bg-bg-sunken p-3\">\n <p className=\"mb-1 text-xs font-semibold text-text-secondary\">\n {t('adaptercloud.drift.observed', 'Observed')}\n </p>\n <pre className=\"overflow-auto text-xs text-text-primary\">\n {JSON.stringify(d.observedValue, null, 2)}\n </pre>\n </div>\n </div>\n <p className=\"mt-2 text-xs text-text-secondary\">\n {t('adaptercloud.drift.detected', 'Detected')} {formatDate(d.detectedAt)}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${d.resourceId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.drift.viewResource', 'View resource')}\n </button>\n </p>\n </div>\n\n {canRemediate && (\n <button\n type=\"button\"\n disabled={remediate.isPending}\n onClick={() => handleRemediate(d.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-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50\"\n >\n {remediate.isPending ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <Wrench className=\"h-3.5 w-3.5\" />\n )}\n {t('adaptercloud.drift.remediate', 'Remediate')}\n </button>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DriftListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/drift/DriftListPage.tsx"],"sourcesContent":["/**\n * Drift Board Page\n * @module adaptercloud/pages/drift\n *\n * Divergences between observed and desired state (`adaListDriftRecords`).\n * Filters by status; each detected/acknowledged record can be remediated via\n * `adaRemediateDrift`.\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { GitCompareArrows, Wrench, Loader2, ArrowRight } from 'lucide-react';\nimport { GlassCard } 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 { ConfirmDialog } from '../../components/ConfirmDialog';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useDriftRecords, useRemediateDrift } from '../../hooks/useAdapterCloudApi';\nimport { driftStatusLabels, severityRank } from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { AdaDriftRecord, AdaDriftStatus, Json } from '../../types';\n\n/** Summary-chip config — order + tokenized colors for each drift status. */\nconst SUMMARY_CHIPS: { status: AdaDriftStatus; className: string }[] = [\n { status: 'DETECTED', className: 'bg-status-warning-bg-subtle text-status-warning-text' },\n { status: 'ACKNOWLEDGED', className: 'bg-accent-blue-subtle text-accent-blue' },\n { status: 'REMEDIATED', className: 'bg-status-success-bg-subtle text-status-success-text' },\n { status: 'IGNORED', className: 'bg-bg-sunken text-text-secondary' },\n];\n\n/** A drift value is renderable as a compact diff pill only when it is scalar. */\nfunction isScalar(value: Json): boolean {\n return value === null || ['string', 'number', 'boolean'].includes(typeof value);\n}\n\n/** Human-readable one-line rendering of a scalar drift value. */\nfunction scalarText(value: Json): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\nexport function DriftListPage() {\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<AdaDriftStatus | ''>('DETECTED');\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmTarget, setConfirmTarget] = useState<AdaDriftRecord | null>(null);\n\n const query = useDriftRecords({ status: status || undefined });\n const remediate = useRemediateDrift();\n\n // Estate-wide, all-status fetch feeding the summary strip. When the status\n // filter is \"All\" this shares a query key with the main list (React Query\n // dedupes to a single request); otherwise it is one extra cheap fetch.\n const allDrift = useDriftRecords({});\n const summaryCounts = useMemo(() => {\n const counts: Record<AdaDriftStatus, number> = {\n DETECTED: 0,\n ACKNOWLEDGED: 0,\n REMEDIATED: 0,\n IGNORED: 0,\n };\n for (const record of allDrift.data ?? []) counts[record.status] += 1;\n return counts;\n }, [allDrift.data]);\n const hasSummary = (allDrift.data?.length ?? 0) > 0;\n\n // Note: this severity sort only reorders the current server result set.\n // adaListDriftRecords returns a single capped array (no pagination), so the\n // ordering is global across what is loaded, not a partial-page reshuffle.\n const items = [...(query.data ?? [])].sort(\n (a, b) => severityRank[b.severity] - severityRank[a.severity]\n );\n\n // Per-id pending: React Query exposes the in-flight mutation argument via\n // `variables`, so only the acted row spins/disables — not the whole list.\n const pendingId = remediate.isPending ? remediate.variables : undefined;\n\n const handleRemediate = useCallback(\n (id: string) => {\n setActionError(null);\n remediate.mutate(id, {\n onSuccess: () => setConfirmTarget(null),\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Failed to remediate drift.'),\n });\n },\n [remediate]\n );\n\n return (\n <PageLayout\n title={t('adaptercloud.drift.title', 'Drift')}\n description={t(\n 'adaptercloud.drift.subtitle',\n 'Divergences between observed and desired state, surfaced during reconciliation.'\n )}\n >\n {hasSummary && (\n <div className=\"mb-4 flex flex-wrap gap-2\">\n {SUMMARY_CHIPS.map((chip) => {\n const active = status === chip.status;\n return (\n <button\n key={chip.status}\n type=\"button\"\n onClick={() => setStatus(active ? '' : chip.status)}\n aria-pressed={active}\n className={cn(\n 'inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-sm font-medium transition-shadow',\n chip.className,\n active && 'ring-2 ring-inset ring-[var(--color-focus-ring)]'\n )}\n >\n <span className=\"text-base font-semibold tabular-nums\">\n {summaryCounts[chip.status]}\n </span>\n <span>{driftStatusLabels[chip.status].toLowerCase()}</span>\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as AdaDriftStatus | '')}\n aria-label={t('adaptercloud.drift.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.drift.allStatuses', 'All statuses')}</option>\n {(Object.keys(driftStatusLabels) as AdaDriftStatus[]).map((s) => (\n <option key={s} value={s}>\n {driftStatusLabels[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.drift.emptyTitle', 'No drift')}\n emptyDescription={t(\n 'adaptercloud.drift.emptyDescription',\n 'Nothing matches this filter — observed state matches desired state.'\n )}\n emptyIcon={<GitCompareArrows className=\"h-10 w-10\" />}\n >\n <div className=\"space-y-3\">\n {items.map((d) => {\n const canRemediate = d.status === 'DETECTED' || d.status === 'ACKNOWLEDGED';\n return (\n <GlassCard key={d.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={d.severity} />\n <StatusBadge status={d.status} label={driftStatusLabels[d.status]} />\n </div>\n <p className=\"break-all font-mono text-sm font-medium text-text-primary\">\n {d.attributePath}\n </p>\n {isScalar(d.expectedValue) && isScalar(d.observedValue) ? (\n // Compact before → after diff for scalar drifts (the common\n // case, e.g. t3.medium → t3.large): expected in red, observed\n // in green, mirroring the mock's inline diff pills.\n <div className=\"mt-3 flex flex-wrap items-end gap-2\">\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-xs font-semibold uppercase tracking-wide text-text-muted\">\n {t('adaptercloud.drift.expected', 'Expected')}\n </p>\n <span className=\"inline-block max-w-full break-all rounded-md bg-status-error-bg-subtle px-2.5 py-1 font-mono text-xs text-status-error-text\">\n {scalarText(d.expectedValue)}\n </span>\n </div>\n <ArrowRight className=\"mb-1.5 h-4 w-4 shrink-0 text-text-tertiary\" />\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-xs font-semibold uppercase tracking-wide text-text-muted\">\n {t('adaptercloud.drift.observed', 'Observed')}\n </p>\n <span className=\"inline-block max-w-full break-all rounded-md bg-status-success-bg-subtle px-2.5 py-1 font-mono text-xs text-status-success-text\">\n {scalarText(d.observedValue)}\n </span>\n </div>\n </div>\n ) : (\n // Structured (object/array) drift — keep the full JSON blocks.\n <div className=\"mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div className=\"rounded-lg bg-bg-sunken p-3\">\n <p className=\"mb-1 text-xs font-semibold text-text-secondary\">\n {t('adaptercloud.drift.expected', 'Expected')}\n </p>\n <pre className=\"overflow-auto text-xs text-status-error-text\">\n {JSON.stringify(d.expectedValue, null, 2)}\n </pre>\n </div>\n <div className=\"rounded-lg bg-bg-sunken p-3\">\n <p className=\"mb-1 text-xs font-semibold text-text-secondary\">\n {t('adaptercloud.drift.observed', 'Observed')}\n </p>\n <pre className=\"overflow-auto text-xs text-status-success-text\">\n {JSON.stringify(d.observedValue, null, 2)}\n </pre>\n </div>\n </div>\n )}\n <p className=\"mt-2 text-xs text-text-secondary\">\n {t('adaptercloud.drift.detected', 'Detected')} {formatDate(d.detectedAt)}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${d.resourceId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.drift.viewResource', 'View resource')}\n </button>\n </p>\n </div>\n\n {canRemediate && (\n <button\n type=\"button\"\n disabled={pendingId === d.id}\n onClick={() => {\n setActionError(null);\n setConfirmTarget(d);\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-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50\"\n >\n {pendingId === d.id ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <Wrench className=\"h-3.5 w-3.5\" />\n )}\n {t('adaptercloud.drift.remediate', 'Remediate')}\n </button>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n </DataState>\n\n <ConfirmDialog\n open={Boolean(confirmTarget)}\n onOpenChange={(open) => {\n if (!open) setConfirmTarget(null);\n }}\n title={t('adaptercloud.drift.remediateTitle', 'Mark this drift remediated?')}\n description={t(\n 'adaptercloud.drift.remediatePrompt',\n 'This records the divergence as remediated. Confirm only if the observed state now matches the desired state.'\n )}\n confirmLabel={t('adaptercloud.drift.remediate', 'Remediate')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={() => confirmTarget && handleRemediate(confirmTarget.id)}\n isPending={Boolean(confirmTarget) && pendingId === confirmTarget?.id}\n tone=\"primary\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|