@burdenoff/microfe-adaptercloud 2026.825.4 → 2026.827.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adaptercloud/components/ActiveSwitch.d.ts +17 -0
- package/dist/adaptercloud/components/ActiveSwitch.d.ts.map +1 -0
- package/dist/adaptercloud/components/ActiveSwitch.js +28 -0
- package/dist/adaptercloud/components/ActiveSwitch.js.map +1 -0
- package/dist/adaptercloud/components/index.d.ts +1 -0
- package/dist/adaptercloud/components/index.d.ts.map +1 -1
- package/dist/adaptercloud/hooks/useAdapterCloudApi.d.ts +28 -2
- package/dist/adaptercloud/hooks/useAdapterCloudApi.d.ts.map +1 -1
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js +43 -18
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
- package/dist/adaptercloud/pages/OverviewPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/OverviewPage.js +4 -4
- package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +6 -5
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +217 -104
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +6 -5
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
- package/dist/adaptercloud/pages/costs/CostsPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/costs/CostsPage.js +183 -156
- package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -1
- package/dist/adaptercloud/pages/drift/DriftListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/drift/DriftListPage.js +108 -107
- package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -1
- package/dist/adaptercloud/pages/policies/PoliciesListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js +141 -131
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -1
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +171 -117
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourcesListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js +85 -66
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -1
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +148 -121
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -1
- package/dist/adaptercloud/pages/violations/ViolationsListPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js +145 -144
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -1
- package/dist/utils/pageContext.d.ts +0 -2
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +1 -3
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,134 +1,160 @@
|
|
|
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 { useCallback as
|
|
12
|
-
import { useI18n as
|
|
13
|
-
import { AlertCircle as
|
|
14
|
-
import { useParams as
|
|
15
|
-
import { Fragment as
|
|
16
|
-
import { GlassCard as
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { policyEnforcementLabels as n, policyKindLabels as r } from "../../utils/domain.js";
|
|
4
|
+
import { StatusBadge as i } from "../../components/StatusBadge.js";
|
|
5
|
+
import { SeverityBadge as a } from "../../components/SeverityBadge.js";
|
|
6
|
+
import { DataState as o } from "../../components/DataState.js";
|
|
7
|
+
import { useArchivePolicy as s, usePolicy as c, useUpdatePolicy as l, useViolations as u } from "../../hooks/useAdapterCloudApi.js";
|
|
8
|
+
import { formatDate as d, formatRelativeTime as f } from "../../utils/formatters.js";
|
|
9
|
+
import { ConfirmDialog as p } from "../../components/ConfirmDialog.js";
|
|
10
|
+
import { ActiveSwitch as m } from "../../components/ActiveSwitch.js";
|
|
11
|
+
import { useCallback as h, useState as g } from "react";
|
|
12
|
+
import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
|
+
import { AlertCircle as v, Archive as y, ArrowLeft as b, Pencil as x } from "lucide-react";
|
|
14
|
+
import { useParams as S } from "react-router";
|
|
15
|
+
import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
16
|
+
import { GlassCard as E } from "@burdenoff/fe-libs/ui";
|
|
17
17
|
//#region src/adaptercloud/pages/policies/PolicyDetailPage.tsx
|
|
18
|
-
function
|
|
19
|
-
let { id:
|
|
20
|
-
let n =
|
|
18
|
+
function D() {
|
|
19
|
+
let { id: D } = S(), { navigateTo: O } = e(), { t: k } = _(), A = h((e, t) => {
|
|
20
|
+
let n = k(e);
|
|
21
21
|
return n === e ? t : n;
|
|
22
|
-
}, [
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
}, [k]), j = c(D), M = s(), N = l(), P = j.data, [F, I] = g(!1), [L, R] = g(null), z = L ?? P?.isActive ?? !1, B = h(() => {
|
|
23
|
+
if (!P) return;
|
|
24
|
+
let e = !z;
|
|
25
|
+
R(e), N.mutate({
|
|
26
|
+
id: P.id,
|
|
27
|
+
input: { isActive: e }
|
|
28
|
+
}, { onSettled: () => R(null) });
|
|
29
|
+
}, [
|
|
30
|
+
P,
|
|
31
|
+
z,
|
|
32
|
+
N
|
|
33
|
+
]), V = {
|
|
34
|
+
policyId: D,
|
|
35
|
+
pagination: {
|
|
36
|
+
limit: 1,
|
|
37
|
+
offset: 0
|
|
38
|
+
}
|
|
39
|
+
}, H = { enabled: !!D }, U = u({
|
|
40
|
+
...V,
|
|
41
|
+
status: "OPEN"
|
|
42
|
+
}, H), W = u({
|
|
43
|
+
...V,
|
|
44
|
+
status: "ACKNOWLEDGED"
|
|
45
|
+
}, H), G = U.data?.pageInfo.totalCount, K = W.data?.pageInfo.totalCount, q = h(() => {
|
|
46
|
+
D && M.mutate(D, { onSuccess: () => {
|
|
47
|
+
I(!1), O("/policies");
|
|
25
48
|
} });
|
|
26
49
|
}, [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
M,
|
|
51
|
+
D,
|
|
52
|
+
O
|
|
30
53
|
]);
|
|
31
|
-
return /* @__PURE__ */
|
|
32
|
-
title:
|
|
33
|
-
description:
|
|
34
|
-
actions: /* @__PURE__ */
|
|
54
|
+
return /* @__PURE__ */ T(t, {
|
|
55
|
+
title: P?.name ?? A("adaptercloud.policies.detailTitle", "Policy"),
|
|
56
|
+
description: P ? r[P.kind] : void 0,
|
|
57
|
+
actions: /* @__PURE__ */ T("div", {
|
|
35
58
|
className: "flex items-center gap-2",
|
|
36
|
-
children: [/* @__PURE__ */
|
|
59
|
+
children: [/* @__PURE__ */ T("button", {
|
|
37
60
|
type: "button",
|
|
38
|
-
onClick: () =>
|
|
61
|
+
onClick: () => O("/policies"),
|
|
39
62
|
className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent",
|
|
40
|
-
children: [/* @__PURE__ */
|
|
41
|
-
}),
|
|
63
|
+
children: [/* @__PURE__ */ w(b, { className: "h-4 w-4" }), A("adaptercloud.common.back", "Back")]
|
|
64
|
+
}), P && /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ T("button", {
|
|
42
65
|
type: "button",
|
|
43
|
-
onClick: () =>
|
|
66
|
+
onClick: () => O(`/policies/${P.id}/edit`),
|
|
44
67
|
className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent",
|
|
45
|
-
children: [/* @__PURE__ */
|
|
46
|
-
}), /* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ w(x, { className: "h-4 w-4" }), A("adaptercloud.common.edit", "Edit")]
|
|
69
|
+
}), /* @__PURE__ */ T("button", {
|
|
47
70
|
type: "button",
|
|
48
|
-
onClick: () =>
|
|
49
|
-
disabled:
|
|
71
|
+
onClick: () => I(!0),
|
|
72
|
+
disabled: M.isPending,
|
|
50
73
|
className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ w(y, { className: "h-4 w-4" }), A("adaptercloud.common.archive", "Archive")]
|
|
52
75
|
})] })]
|
|
53
76
|
}),
|
|
54
|
-
children: [/* @__PURE__ */
|
|
55
|
-
isLoading:
|
|
56
|
-
isError:
|
|
57
|
-
isEmpty: !
|
|
58
|
-
error:
|
|
59
|
-
onRetry: () => void
|
|
60
|
-
emptyTitle:
|
|
61
|
-
children:
|
|
77
|
+
children: [/* @__PURE__ */ w(o, {
|
|
78
|
+
isLoading: j.isLoading,
|
|
79
|
+
isError: j.isError,
|
|
80
|
+
isEmpty: !j.isLoading && !P,
|
|
81
|
+
error: j.error,
|
|
82
|
+
onRetry: () => void j.refetch(),
|
|
83
|
+
emptyTitle: A("adaptercloud.policies.notFound", "Policy not found"),
|
|
84
|
+
children: P && /* @__PURE__ */ T("div", {
|
|
62
85
|
className: "space-y-6",
|
|
63
86
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
87
|
+
/* @__PURE__ */ T(E, {
|
|
65
88
|
className: "p-6",
|
|
66
89
|
children: [
|
|
67
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ T("div", {
|
|
68
91
|
className: "mb-4 flex flex-wrap items-center gap-3",
|
|
69
92
|
children: [
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ w(a, { severity: P.severity }),
|
|
94
|
+
/* @__PURE__ */ w("span", {
|
|
72
95
|
className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
|
|
73
|
-
children:
|
|
96
|
+
children: n[P.enforcement]
|
|
74
97
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
|
|
77
|
-
|
|
98
|
+
/* @__PURE__ */ w(m, {
|
|
99
|
+
checked: z,
|
|
100
|
+
disabled: N.isPending,
|
|
101
|
+
onToggle: B,
|
|
102
|
+
label: z ? A("adaptercloud.policies.deactivate", "Deactivate policy") : A("adaptercloud.policies.activate", "Activate policy"),
|
|
103
|
+
children: z ? A("adaptercloud.policies.active", "Active") : A("adaptercloud.policies.inactive", "Inactive")
|
|
78
104
|
})
|
|
79
105
|
]
|
|
80
106
|
}),
|
|
81
|
-
|
|
107
|
+
P.description && /* @__PURE__ */ w("p", {
|
|
82
108
|
className: "mb-4 text-sm text-text-secondary",
|
|
83
|
-
children:
|
|
109
|
+
children: P.description
|
|
84
110
|
}),
|
|
85
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ T("dl", {
|
|
86
112
|
className: "grid grid-cols-2 gap-4 text-sm sm:grid-cols-3",
|
|
87
113
|
children: [
|
|
88
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
|
|
89
115
|
className: "text-text-secondary",
|
|
90
|
-
children:
|
|
91
|
-
}), /* @__PURE__ */
|
|
116
|
+
children: A("adaptercloud.policies.kind", "Kind")
|
|
117
|
+
}), /* @__PURE__ */ w("dd", {
|
|
92
118
|
className: "mt-0.5 font-medium text-text-primary",
|
|
93
|
-
children:
|
|
119
|
+
children: r[P.kind]
|
|
94
120
|
})] }),
|
|
95
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
|
|
96
122
|
className: "text-text-secondary",
|
|
97
|
-
children:
|
|
98
|
-
}), /* @__PURE__ */
|
|
123
|
+
children: A("adaptercloud.common.created", "Created")
|
|
124
|
+
}), /* @__PURE__ */ w("dd", {
|
|
99
125
|
className: "mt-0.5 font-medium text-text-primary",
|
|
100
|
-
children:
|
|
126
|
+
children: d(P.createdAt)
|
|
101
127
|
})] }),
|
|
102
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
|
|
103
129
|
className: "text-text-secondary",
|
|
104
|
-
children:
|
|
105
|
-
}), /* @__PURE__ */
|
|
130
|
+
children: A("adaptercloud.common.updated", "Updated")
|
|
131
|
+
}), /* @__PURE__ */ w("dd", {
|
|
106
132
|
className: "mt-0.5 font-medium text-text-primary",
|
|
107
|
-
children:
|
|
133
|
+
children: d(P.updatedAt)
|
|
108
134
|
})] })
|
|
109
135
|
]
|
|
110
136
|
}),
|
|
111
|
-
|
|
137
|
+
P.appliesTo.length > 0 && /* @__PURE__ */ T("div", {
|
|
112
138
|
className: "mt-5",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
114
140
|
className: "mb-2 text-sm font-semibold text-text-primary",
|
|
115
|
-
children:
|
|
116
|
-
}), /* @__PURE__ */
|
|
141
|
+
children: A("adaptercloud.policies.appliesTo", "Applies To")
|
|
142
|
+
}), /* @__PURE__ */ w("div", {
|
|
117
143
|
className: "flex flex-wrap gap-1.5",
|
|
118
|
-
children:
|
|
144
|
+
children: P.appliesTo.map((e) => /* @__PURE__ */ w("span", {
|
|
119
145
|
className: "inline-flex items-center rounded-full bg-accent-blue-subtle px-2.5 py-0.5 font-mono text-xs text-accent-blue",
|
|
120
146
|
children: e
|
|
121
147
|
}, e))
|
|
122
148
|
})]
|
|
123
149
|
}),
|
|
124
|
-
|
|
150
|
+
P.tags.length > 0 && /* @__PURE__ */ T("div", {
|
|
125
151
|
className: "mt-4",
|
|
126
|
-
children: [/* @__PURE__ */
|
|
152
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
127
153
|
className: "mb-2 text-sm font-semibold text-text-primary",
|
|
128
|
-
children:
|
|
129
|
-
}), /* @__PURE__ */
|
|
154
|
+
children: A("adaptercloud.common.tags", "Tags")
|
|
155
|
+
}), /* @__PURE__ */ w("div", {
|
|
130
156
|
className: "flex flex-wrap gap-1.5",
|
|
131
|
-
children:
|
|
157
|
+
children: P.tags.map((e) => /* @__PURE__ */ w("span", {
|
|
132
158
|
className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary",
|
|
133
159
|
children: e
|
|
134
160
|
}, e))
|
|
@@ -136,81 +162,109 @@ function T() {
|
|
|
136
162
|
})
|
|
137
163
|
]
|
|
138
164
|
}),
|
|
139
|
-
/* @__PURE__ */
|
|
165
|
+
/* @__PURE__ */ T(E, {
|
|
140
166
|
className: "p-6",
|
|
141
|
-
children: [/* @__PURE__ */
|
|
167
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
142
168
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
143
|
-
children:
|
|
144
|
-
}), /* @__PURE__ */
|
|
169
|
+
children: A("adaptercloud.policies.expression", "Expression")
|
|
170
|
+
}), /* @__PURE__ */ w("pre", {
|
|
145
171
|
className: "overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary",
|
|
146
|
-
children: JSON.stringify(
|
|
172
|
+
children: JSON.stringify(P.expression, null, 2)
|
|
147
173
|
})]
|
|
148
174
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
150
|
-
className: "mb-3 flex items-center justify-between",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
152
|
-
className: "
|
|
153
|
-
children:
|
|
154
|
-
|
|
175
|
+
/* @__PURE__ */ T("section", { children: [/* @__PURE__ */ T("div", {
|
|
176
|
+
className: "mb-3 flex flex-wrap items-center justify-between gap-3",
|
|
177
|
+
children: [/* @__PURE__ */ T("div", {
|
|
178
|
+
className: "flex flex-wrap items-baseline gap-3",
|
|
179
|
+
children: [/* @__PURE__ */ w("h3", {
|
|
180
|
+
className: "text-base font-semibold text-text-primary",
|
|
181
|
+
children: A("adaptercloud.policies.violations", "Violations")
|
|
182
|
+
}), (G != null || K != null) && /* @__PURE__ */ T("p", {
|
|
183
|
+
className: "flex items-center gap-2 text-xs",
|
|
184
|
+
children: [
|
|
185
|
+
G != null && /* @__PURE__ */ T("span", {
|
|
186
|
+
className: "font-medium text-status-error-text",
|
|
187
|
+
children: [
|
|
188
|
+
G,
|
|
189
|
+
" ",
|
|
190
|
+
A("adaptercloud.policies.openCount", "open")
|
|
191
|
+
]
|
|
192
|
+
}),
|
|
193
|
+
G != null && K != null && /* @__PURE__ */ w("span", {
|
|
194
|
+
"aria-hidden": "true",
|
|
195
|
+
className: "text-text-tertiary",
|
|
196
|
+
children: "·"
|
|
197
|
+
}),
|
|
198
|
+
K != null && /* @__PURE__ */ T("span", {
|
|
199
|
+
className: "font-medium text-status-warning-text",
|
|
200
|
+
children: [
|
|
201
|
+
K,
|
|
202
|
+
" ",
|
|
203
|
+
A("adaptercloud.policies.acknowledgedCount", "acknowledged")
|
|
204
|
+
]
|
|
205
|
+
})
|
|
206
|
+
]
|
|
207
|
+
})]
|
|
208
|
+
}), /* @__PURE__ */ w("button", {
|
|
155
209
|
type: "button",
|
|
156
|
-
onClick: () =>
|
|
210
|
+
onClick: () => O(`/violations?policyId=${P.id}`),
|
|
157
211
|
className: "text-sm font-medium text-accent-blue hover:underline",
|
|
158
|
-
children:
|
|
212
|
+
children: A("adaptercloud.common.viewAll", "View all")
|
|
159
213
|
})]
|
|
160
|
-
}),
|
|
214
|
+
}), P.violations && P.violations.length > 0 ? /* @__PURE__ */ w("div", {
|
|
161
215
|
className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
|
|
162
|
-
children:
|
|
216
|
+
children: P.violations.slice(0, 10).map((e) => /* @__PURE__ */ T("div", {
|
|
163
217
|
className: "flex w-full items-start gap-3 px-4 py-3 transition-colors hover:bg-accent/50",
|
|
164
218
|
children: [
|
|
165
|
-
/* @__PURE__ */
|
|
166
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ w(v, { className: "mt-0.5 h-4 w-4 shrink-0 text-status-error-text" }),
|
|
220
|
+
/* @__PURE__ */ T("div", {
|
|
167
221
|
className: "min-w-0 flex-1",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: [/* @__PURE__ */ w("p", {
|
|
169
223
|
className: "truncate text-sm font-medium text-text-primary",
|
|
170
224
|
children: e.message
|
|
171
|
-
}), /* @__PURE__ */
|
|
225
|
+
}), /* @__PURE__ */ T("p", {
|
|
172
226
|
className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-text-secondary",
|
|
173
227
|
children: [
|
|
174
|
-
/* @__PURE__ */
|
|
175
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ w("span", { children: f(e.detectedAt) }),
|
|
229
|
+
/* @__PURE__ */ w("span", {
|
|
176
230
|
"aria-hidden": "true",
|
|
177
231
|
children: "·"
|
|
178
232
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ w("button", {
|
|
180
234
|
type: "button",
|
|
181
|
-
onClick: () =>
|
|
235
|
+
onClick: () => O(`/resources/${e.resourceId}`),
|
|
182
236
|
className: "font-medium text-accent-blue hover:underline",
|
|
183
|
-
children:
|
|
237
|
+
children: A("adaptercloud.violations.viewResource", "View resource")
|
|
184
238
|
})
|
|
185
239
|
]
|
|
186
240
|
})]
|
|
187
241
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ T("div", {
|
|
189
243
|
className: "flex shrink-0 items-center gap-2",
|
|
190
|
-
children: [/* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ w(a, { severity: e.severity }), /* @__PURE__ */ w(i, { status: e.status })]
|
|
191
245
|
})
|
|
192
246
|
]
|
|
193
247
|
}, e.id))
|
|
194
|
-
}) : /* @__PURE__ */
|
|
248
|
+
}) : /* @__PURE__ */ w("p", {
|
|
195
249
|
className: "rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary",
|
|
196
|
-
children:
|
|
250
|
+
children: A("adaptercloud.policies.noViolations", "No violations recorded for this policy.")
|
|
197
251
|
})] })
|
|
198
252
|
]
|
|
199
253
|
})
|
|
200
|
-
}), /* @__PURE__ */
|
|
201
|
-
open:
|
|
202
|
-
onOpenChange:
|
|
203
|
-
title:
|
|
204
|
-
description:
|
|
205
|
-
confirmLabel:
|
|
206
|
-
cancelLabel:
|
|
207
|
-
onConfirm:
|
|
208
|
-
isPending:
|
|
254
|
+
}), /* @__PURE__ */ w(p, {
|
|
255
|
+
open: F,
|
|
256
|
+
onOpenChange: I,
|
|
257
|
+
title: A("adaptercloud.policies.archiveTitle", "Archive this policy?"),
|
|
258
|
+
description: A("adaptercloud.policies.archivePrompt", "The policy will be archived and removed from every governance view. This cannot be undone from the UI."),
|
|
259
|
+
confirmLabel: A("adaptercloud.common.archive", "Archive"),
|
|
260
|
+
cancelLabel: A("adaptercloud.common.cancel", "Cancel"),
|
|
261
|
+
onConfirm: q,
|
|
262
|
+
isPending: M.isPending,
|
|
209
263
|
tone: "danger"
|
|
210
264
|
})]
|
|
211
265
|
});
|
|
212
266
|
}
|
|
213
267
|
//#endregion
|
|
214
|
-
export {
|
|
268
|
+
export { D as PolicyDetailPage };
|
|
215
269
|
|
|
216
270
|
//# sourceMappingURL=PolicyDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PolicyDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/policies/PolicyDetailPage.tsx"],"sourcesContent":["/**\n * Policy Detail Page\n * @module adaptercloud/pages/policies\n *\n * One governance policy (`adaPolicy`) — its kind, enforcement, severity, JSON\n * expression, applies-to selector, and the violations it has produced. Supports\n * archiving via `adaArchivePolicy`.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Archive, AlertCircle, Pencil } 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 { usePolicy, useArchivePolicy } from '../../hooks/useAdapterCloudApi';\nimport { policyKindLabels, policyEnforcementLabels } from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\n\nexport function PolicyDetailPage() {\n const { id } = useParams<{ id: string }>();\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 query = usePolicy(id);\n const archive = useArchivePolicy();\n const policy = query.data;\n\n const [confirmArchiveOpen, setConfirmArchiveOpen] = useState(false);\n\n const handleArchive = useCallback(() => {\n if (!id) return;\n archive.mutate(id, {\n onSuccess: () => {\n setConfirmArchiveOpen(false);\n navigateTo('/policies');\n },\n });\n }, [archive, id, navigateTo]);\n\n return (\n <PageLayout\n title={policy?.name ?? t('adaptercloud.policies.detailTitle', 'Policy')}\n description={policy ? policyKindLabels[policy.kind] : undefined}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/policies')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.back', 'Back')}\n </button>\n {policy && (\n <>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/policies/${policy.id}/edit`)}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <Pencil className=\"h-4 w-4\" />\n {t('adaptercloud.common.edit', 'Edit')}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmArchiveOpen(true)}\n disabled={archive.isPending}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n <Archive className=\"h-4 w-4\" />\n {t('adaptercloud.common.archive', 'Archive')}\n </button>\n </>\n )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !policy}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.policies.notFound', 'Policy not found')}\n >\n {policy && (\n <div className=\"space-y-6\">\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <SeverityBadge severity={policy.severity} />\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {policyEnforcementLabels[policy.enforcement]}\n </span>\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-xs font-medium',\n policy.isActive\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n )}\n >\n {policy.isActive\n ? t('adaptercloud.policies.active', 'Active')\n : t('adaptercloud.policies.inactive', 'Inactive')}\n </span>\n </div>\n\n {policy.description && (\n <p className=\"mb-4 text-sm text-text-secondary\">{policy.description}</p>\n )}\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-3\">\n <div>\n <dt className=\"text-text-secondary\">{t('adaptercloud.policies.kind', 'Kind')}</dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {policyKindLabels[policy.kind]}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.common.created', 'Created')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {formatDate(policy.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.common.updated', 'Updated')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {formatDate(policy.updatedAt)}\n </dd>\n </div>\n </dl>\n\n {policy.appliesTo.length > 0 && (\n <div className=\"mt-5\">\n <h3 className=\"mb-2 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.policies.appliesTo', 'Applies To')}\n </h3>\n <div className=\"flex flex-wrap gap-1.5\">\n {policy.appliesTo.map((sel) => (\n <span\n key={sel}\n className=\"inline-flex items-center rounded-full bg-accent-blue-subtle px-2.5 py-0.5 font-mono text-xs text-accent-blue\"\n >\n {sel}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {policy.tags.length > 0 && (\n <div className=\"mt-4\">\n <h3 className=\"mb-2 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.common.tags', 'Tags')}\n </h3>\n <div className=\"flex flex-wrap gap-1.5\">\n {policy.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n </GlassCard>\n\n {/* Expression */}\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.policies.expression', 'Expression')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(policy.expression, null, 2)}\n </pre>\n </GlassCard>\n\n {/* Violations */}\n <section>\n <div className=\"mb-3 flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {t('adaptercloud.policies.violations', 'Violations')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/violations?policyId=${policy.id}`)}\n className=\"text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}\n </button>\n </div>\n {policy.violations && policy.violations.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {policy.violations.slice(0, 10).map((v) => (\n <div\n key={v.id}\n className=\"flex w-full items-start gap-3 px-4 py-3 transition-colors hover:bg-accent/50\"\n >\n <AlertCircle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-error-text\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {v.message}\n </p>\n <p className=\"mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-text-secondary\">\n <span>{formatRelativeTime(v.detectedAt)}</span>\n <span aria-hidden=\"true\">·</span>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${v.resourceId}`)}\n className=\"font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.violations.viewResource', 'View resource')}\n </button>\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <SeverityBadge severity={v.severity} />\n <StatusBadge status={v.status} />\n </div>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.policies.noViolations',\n 'No violations recorded for this policy.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={confirmArchiveOpen}\n onOpenChange={setConfirmArchiveOpen}\n title={t('adaptercloud.policies.archiveTitle', 'Archive this policy?')}\n description={t(\n 'adaptercloud.policies.archivePrompt',\n 'The policy will be archived and removed from every governance view. This cannot be undone from the UI.'\n )}\n confirmLabel={t('adaptercloud.common.archive', 'Archive')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={handleArchive}\n isPending={archive.isPending}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PolicyDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/policies/PolicyDetailPage.tsx"],"sourcesContent":["/**\n * Policy Detail Page\n * @module adaptercloud/pages/policies\n *\n * One governance policy (`adaPolicy`) — its kind, enforcement, severity, JSON\n * expression, applies-to selector, and the violations it has produced. Supports\n * archiving via `adaArchivePolicy`.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Archive, AlertCircle, Pencil } 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 { ActiveSwitch } from '../../components/ActiveSwitch';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport {\n usePolicy,\n useArchivePolicy,\n useUpdatePolicy,\n useViolations,\n} from '../../hooks/useAdapterCloudApi';\nimport { policyKindLabels, policyEnforcementLabels } from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\n\nexport function PolicyDetailPage() {\n const { id } = useParams<{ id: string }>();\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 query = usePolicy(id);\n const archive = useArchivePolicy();\n const update = useUpdatePolicy();\n const policy = query.data;\n\n const [confirmArchiveOpen, setConfirmArchiveOpen] = useState(false);\n // Optimistic override of `isActive` while the mutation is in flight, so the\n // switch flips immediately instead of waiting for the refetch.\n const [pendingActive, setPendingActive] = useState<boolean | null>(null);\n\n const isActiveNow = pendingActive ?? policy?.isActive ?? false;\n\n const toggleActive = useCallback(() => {\n if (!policy) return;\n const next = !isActiveNow;\n setPendingActive(next);\n update.mutate(\n { id: policy.id, input: { isActive: next } },\n { onSettled: () => setPendingActive(null) }\n );\n }, [policy, isActiveNow, update]);\n\n // Exact per-status counts for this policy's violations. Each is a `limit: 1`\n // read of `pageInfo.totalCount` — the estate-wide total for that filter, not\n // a count of the (relation-capped) `policy.violations` array.\n const countBase = { policyId: id, pagination: { limit: 1, offset: 0 } };\n const countsEnabled = { enabled: Boolean(id) };\n const openCount = useViolations({ ...countBase, status: 'OPEN' }, countsEnabled);\n const ackCount = useViolations({ ...countBase, status: 'ACKNOWLEDGED' }, countsEnabled);\n const openTotal = openCount.data?.pageInfo.totalCount;\n const ackTotal = ackCount.data?.pageInfo.totalCount;\n\n const handleArchive = useCallback(() => {\n if (!id) return;\n archive.mutate(id, {\n onSuccess: () => {\n setConfirmArchiveOpen(false);\n navigateTo('/policies');\n },\n });\n }, [archive, id, navigateTo]);\n\n return (\n <PageLayout\n title={policy?.name ?? t('adaptercloud.policies.detailTitle', 'Policy')}\n description={policy ? policyKindLabels[policy.kind] : undefined}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/policies')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.back', 'Back')}\n </button>\n {policy && (\n <>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/policies/${policy.id}/edit`)}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <Pencil className=\"h-4 w-4\" />\n {t('adaptercloud.common.edit', 'Edit')}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmArchiveOpen(true)}\n disabled={archive.isPending}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n <Archive className=\"h-4 w-4\" />\n {t('adaptercloud.common.archive', 'Archive')}\n </button>\n </>\n )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !policy}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.policies.notFound', 'Policy not found')}\n >\n {policy && (\n <div className=\"space-y-6\">\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <SeverityBadge severity={policy.severity} />\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {policyEnforcementLabels[policy.enforcement]}\n </span>\n <ActiveSwitch\n checked={isActiveNow}\n disabled={update.isPending}\n onToggle={toggleActive}\n label={\n isActiveNow\n ? t('adaptercloud.policies.deactivate', 'Deactivate policy')\n : t('adaptercloud.policies.activate', 'Activate policy')\n }\n >\n {isActiveNow\n ? t('adaptercloud.policies.active', 'Active')\n : t('adaptercloud.policies.inactive', 'Inactive')}\n </ActiveSwitch>\n </div>\n\n {policy.description && (\n <p className=\"mb-4 text-sm text-text-secondary\">{policy.description}</p>\n )}\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-3\">\n <div>\n <dt className=\"text-text-secondary\">{t('adaptercloud.policies.kind', 'Kind')}</dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {policyKindLabels[policy.kind]}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.common.created', 'Created')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {formatDate(policy.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.common.updated', 'Updated')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {formatDate(policy.updatedAt)}\n </dd>\n </div>\n </dl>\n\n {policy.appliesTo.length > 0 && (\n <div className=\"mt-5\">\n <h3 className=\"mb-2 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.policies.appliesTo', 'Applies To')}\n </h3>\n <div className=\"flex flex-wrap gap-1.5\">\n {policy.appliesTo.map((sel) => (\n <span\n key={sel}\n className=\"inline-flex items-center rounded-full bg-accent-blue-subtle px-2.5 py-0.5 font-mono text-xs text-accent-blue\"\n >\n {sel}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {policy.tags.length > 0 && (\n <div className=\"mt-4\">\n <h3 className=\"mb-2 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.common.tags', 'Tags')}\n </h3>\n <div className=\"flex flex-wrap gap-1.5\">\n {policy.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n )}\n </GlassCard>\n\n {/* Expression */}\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.policies.expression', 'Expression')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(policy.expression, null, 2)}\n </pre>\n </GlassCard>\n\n {/* Violations */}\n <section>\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex flex-wrap items-baseline gap-3\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {t('adaptercloud.policies.violations', 'Violations')}\n </h3>\n {(openTotal != null || ackTotal != null) && (\n <p className=\"flex items-center gap-2 text-xs\">\n {openTotal != null && (\n <span className=\"font-medium text-status-error-text\">\n {openTotal} {t('adaptercloud.policies.openCount', 'open')}\n </span>\n )}\n {openTotal != null && ackTotal != null && (\n <span aria-hidden=\"true\" className=\"text-text-tertiary\">\n ·\n </span>\n )}\n {ackTotal != null && (\n <span className=\"font-medium text-status-warning-text\">\n {ackTotal} {t('adaptercloud.policies.acknowledgedCount', 'acknowledged')}\n </span>\n )}\n </p>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/violations?policyId=${policy.id}`)}\n className=\"text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}\n </button>\n </div>\n {policy.violations && policy.violations.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {policy.violations.slice(0, 10).map((v) => (\n <div\n key={v.id}\n className=\"flex w-full items-start gap-3 px-4 py-3 transition-colors hover:bg-accent/50\"\n >\n <AlertCircle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-error-text\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {v.message}\n </p>\n <p className=\"mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-text-secondary\">\n <span>{formatRelativeTime(v.detectedAt)}</span>\n <span aria-hidden=\"true\">·</span>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${v.resourceId}`)}\n className=\"font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.violations.viewResource', 'View resource')}\n </button>\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <SeverityBadge severity={v.severity} />\n <StatusBadge status={v.status} />\n </div>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.policies.noViolations',\n 'No violations recorded for this policy.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={confirmArchiveOpen}\n onOpenChange={setConfirmArchiveOpen}\n title={t('adaptercloud.policies.archiveTitle', 'Archive this policy?')}\n description={t(\n 'adaptercloud.policies.archivePrompt',\n 'The policy will be archived and removed from every governance view. This cannot be undone from the UI.'\n )}\n confirmLabel={t('adaptercloud.common.archive', 'Archive')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={handleArchive}\n isPending={archive.isPending}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourcesListPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/resources/ResourcesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"ResourcesListPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/resources/ResourcesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqBH,wBAAgB,iBAAiB,gCA8QhC"}
|