@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,14 +1,14 @@
|
|
|
1
1
|
import { useAdapterCloud as e } from "../../context/AdapterCloudContext.js";
|
|
2
2
|
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
-
import { authMethodLabels as n, connectionStatusLabels as r, formatMoney as i, resourceStateLabels as a, syncKindLabels as o } from "../../utils/domain.js";
|
|
4
|
-
import { StatusBadge as
|
|
5
|
-
import { DataState as
|
|
6
|
-
import { useConnection as
|
|
7
|
-
import { formatDate as p } from "../../utils/formatters.js";
|
|
8
|
-
import { ConfirmDialog as
|
|
9
|
-
import { canStartConnectionSync as
|
|
10
|
-
import { useCallback as
|
|
11
|
-
import { useI18n as
|
|
3
|
+
import { authMethodLabels as n, connectionStatusLabels as r, formatMoney as i, resourceStateLabels as a, syncKindLabels as o, syncStatusLabels as s } from "../../utils/domain.js";
|
|
4
|
+
import { StatusBadge as c } from "../../components/StatusBadge.js";
|
|
5
|
+
import { DataState as l } from "../../components/DataState.js";
|
|
6
|
+
import { useConnection as u, useDisableConnection as ee, useSetConnectionStatus as d, useStartSyncRun as f, useSyncRuns as te } from "../../hooks/useAdapterCloudApi.js";
|
|
7
|
+
import { formatDate as p, formatRelativeTime as m } from "../../utils/formatters.js";
|
|
8
|
+
import { ConfirmDialog as h } from "../../components/ConfirmDialog.js";
|
|
9
|
+
import { canStartConnectionSync as g, canStartConnectionSyncKind as _, isConnectionSyncKindExecutable as v } from "./connectionSync.js";
|
|
10
|
+
import { useCallback as y, useState as b } from "react";
|
|
11
|
+
import { useI18n as ne } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
12
12
|
import { ArrowLeft as x, Ban as S, Loader2 as C, Pencil as w, Play as T, RefreshCw as E, Server as D } from "lucide-react";
|
|
13
13
|
import { useParams as O } from "react-router";
|
|
14
14
|
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
@@ -24,89 +24,98 @@ var M = [
|
|
|
24
24
|
"RECONCILE",
|
|
25
25
|
"COST_INGEST",
|
|
26
26
|
"FULL"
|
|
27
|
-
];
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
], P = 5;
|
|
28
|
+
function F(e) {
|
|
29
|
+
return e === "QUEUED" || e === "RUNNING";
|
|
30
|
+
}
|
|
31
|
+
function I() {
|
|
32
|
+
let { id: I } = O(), { navigateTo: L } = e(), { t: R } = ne(), z = y((e, t) => {
|
|
33
|
+
let n = R(e);
|
|
31
34
|
return n === e ? t : n;
|
|
32
|
-
}, [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
}, [R]), B = u(I), V = d(), H = ee(), U = f(), W = B.data, G = W ? g(W.status) : !1, K = te({
|
|
36
|
+
connectionId: I,
|
|
37
|
+
pagination: {
|
|
38
|
+
limit: P,
|
|
39
|
+
offset: 0
|
|
40
|
+
}
|
|
41
|
+
}, { enabled: !!I }), q = K.data?.items ?? [], [J, Y] = b(null), [X, Z] = b(null), [re, Q] = b(!1), $ = y((e) => Z(e instanceof Error ? e.message : "Action failed. Please try again."), []), ie = y((e) => {
|
|
42
|
+
I && (Z(null), V.mutate({
|
|
43
|
+
id: I,
|
|
35
44
|
status: e
|
|
36
|
-
}, { onError:
|
|
45
|
+
}, { onError: $ }));
|
|
37
46
|
}, [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
]),
|
|
42
|
-
|
|
43
|
-
onSuccess: () =>
|
|
44
|
-
onError:
|
|
47
|
+
I,
|
|
48
|
+
V,
|
|
49
|
+
$
|
|
50
|
+
]), ae = y(() => {
|
|
51
|
+
I && (Z(null), H.mutate(I, {
|
|
52
|
+
onSuccess: () => Q(!1),
|
|
53
|
+
onError: $
|
|
45
54
|
}));
|
|
46
55
|
}, [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
]),
|
|
51
|
-
!
|
|
52
|
-
connectionId:
|
|
56
|
+
I,
|
|
57
|
+
H,
|
|
58
|
+
$
|
|
59
|
+
]), oe = y((e) => {
|
|
60
|
+
!I || !W || !_(W.status, e) || (Z(null), Y(e), U.mutate({
|
|
61
|
+
connectionId: I,
|
|
53
62
|
kind: e
|
|
54
63
|
}, {
|
|
55
64
|
onSuccess: () => {
|
|
56
|
-
|
|
65
|
+
Y(null), L("/sync-runs");
|
|
57
66
|
},
|
|
58
67
|
onError: (e) => {
|
|
59
|
-
|
|
68
|
+
Y(null), $(e);
|
|
60
69
|
}
|
|
61
70
|
}));
|
|
62
71
|
}, [
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
I,
|
|
73
|
+
W,
|
|
74
|
+
U,
|
|
75
|
+
L,
|
|
76
|
+
$
|
|
68
77
|
]);
|
|
69
78
|
return /* @__PURE__ */ A(t, {
|
|
70
|
-
title:
|
|
71
|
-
description:
|
|
79
|
+
title: W?.name ?? z("adaptercloud.connections.detailTitle", "Connection"),
|
|
80
|
+
description: W?.adapter?.name,
|
|
72
81
|
actions: /* @__PURE__ */ A("div", {
|
|
73
82
|
className: "flex items-center gap-2",
|
|
74
83
|
children: [/* @__PURE__ */ A("button", {
|
|
75
84
|
type: "button",
|
|
76
|
-
onClick: () =>
|
|
85
|
+
onClick: () => L("/connections"),
|
|
77
86
|
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",
|
|
78
|
-
children: [/* @__PURE__ */ k(x, { className: "h-4 w-4" }),
|
|
79
|
-
}),
|
|
87
|
+
children: [/* @__PURE__ */ k(x, { className: "h-4 w-4" }), z("adaptercloud.common.back", "Back")]
|
|
88
|
+
}), W && /* @__PURE__ */ A("button", {
|
|
80
89
|
type: "button",
|
|
81
|
-
onClick: () =>
|
|
90
|
+
onClick: () => L(`/connections/${W.id}/edit`),
|
|
82
91
|
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",
|
|
83
|
-
children: [/* @__PURE__ */ k(w, { className: "h-4 w-4" }),
|
|
92
|
+
children: [/* @__PURE__ */ k(w, { className: "h-4 w-4" }), z("adaptercloud.common.edit", "Edit")]
|
|
84
93
|
})]
|
|
85
94
|
}),
|
|
86
|
-
children: [/* @__PURE__ */ k(
|
|
87
|
-
isLoading:
|
|
88
|
-
isError:
|
|
89
|
-
isEmpty: !
|
|
90
|
-
error:
|
|
91
|
-
onRetry: () => void
|
|
92
|
-
emptyTitle:
|
|
93
|
-
children:
|
|
95
|
+
children: [/* @__PURE__ */ k(l, {
|
|
96
|
+
isLoading: B.isLoading,
|
|
97
|
+
isError: B.isError,
|
|
98
|
+
isEmpty: !B.isLoading && !W,
|
|
99
|
+
error: B.error,
|
|
100
|
+
onRetry: () => void B.refetch(),
|
|
101
|
+
emptyTitle: z("adaptercloud.connections.notFound", "Connection not found"),
|
|
102
|
+
children: W && /* @__PURE__ */ A("div", {
|
|
94
103
|
className: "space-y-6",
|
|
95
104
|
children: [
|
|
96
|
-
|
|
105
|
+
X && /* @__PURE__ */ k("p", {
|
|
97
106
|
role: "alert",
|
|
98
107
|
"aria-live": "polite",
|
|
99
108
|
className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
100
|
-
children:
|
|
109
|
+
children: X
|
|
101
110
|
}),
|
|
102
111
|
/* @__PURE__ */ A(j, {
|
|
103
112
|
className: "p-6",
|
|
104
113
|
children: [
|
|
105
114
|
/* @__PURE__ */ A("div", {
|
|
106
115
|
className: "mb-4 flex flex-wrap items-center gap-3",
|
|
107
|
-
children: [/* @__PURE__ */ k(
|
|
116
|
+
children: [/* @__PURE__ */ k(c, { status: W.status }), /* @__PURE__ */ k("span", {
|
|
108
117
|
className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
|
|
109
|
-
children: n[
|
|
118
|
+
children: n[W.authMethod]
|
|
110
119
|
})]
|
|
111
120
|
}),
|
|
112
121
|
/* @__PURE__ */ A("dl", {
|
|
@@ -114,57 +123,98 @@ function P() {
|
|
|
114
123
|
children: [
|
|
115
124
|
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
116
125
|
className: "text-text-secondary",
|
|
117
|
-
children:
|
|
126
|
+
children: z("adaptercloud.connections.adapter", "Adapter")
|
|
118
127
|
}), /* @__PURE__ */ k("dd", {
|
|
119
128
|
className: "mt-0.5 font-medium text-text-primary",
|
|
120
|
-
children:
|
|
129
|
+
children: W.adapter ? /* @__PURE__ */ A("button", {
|
|
130
|
+
type: "button",
|
|
131
|
+
onClick: () => L(`/adapters/${W.adapterId}`),
|
|
132
|
+
className: "max-w-full truncate text-left text-accent-blue hover:underline",
|
|
133
|
+
children: [W.adapter.name, W.adapter.version ? ` v${W.adapter.version}` : ""]
|
|
134
|
+
}) : "—"
|
|
121
135
|
})] }),
|
|
122
136
|
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
123
137
|
className: "text-text-secondary",
|
|
124
|
-
children:
|
|
138
|
+
children: z("adaptercloud.connections.region", "Region")
|
|
125
139
|
}), /* @__PURE__ */ k("dd", {
|
|
126
140
|
className: "mt-0.5 font-medium text-text-primary",
|
|
127
|
-
children:
|
|
141
|
+
children: W.region ?? "—"
|
|
128
142
|
})] }),
|
|
129
143
|
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
130
144
|
className: "text-text-secondary",
|
|
131
|
-
children:
|
|
145
|
+
children: z("adaptercloud.connections.environment", "Environment")
|
|
146
|
+
}), /* @__PURE__ */ k("dd", {
|
|
147
|
+
className: "mt-0.5 font-medium text-text-primary",
|
|
148
|
+
children: W.environment ?? "—"
|
|
149
|
+
})] }),
|
|
150
|
+
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
151
|
+
className: "text-text-secondary",
|
|
152
|
+
children: z("adaptercloud.connections.resourceCount", "Resources")
|
|
132
153
|
}), /* @__PURE__ */ k("dd", {
|
|
133
154
|
className: "mt-0.5 font-medium tabular-nums text-text-primary",
|
|
134
|
-
children:
|
|
155
|
+
children: W.resourceCount
|
|
135
156
|
})] }),
|
|
136
157
|
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
137
158
|
className: "text-text-secondary",
|
|
138
|
-
children:
|
|
159
|
+
children: z("adaptercloud.connections.lastSynced", "Last synced")
|
|
139
160
|
}), /* @__PURE__ */ k("dd", {
|
|
140
161
|
className: "mt-0.5 font-medium text-text-primary",
|
|
141
|
-
children:
|
|
162
|
+
children: W.lastSyncedAt ? p(W.lastSyncedAt) : "—"
|
|
142
163
|
})] })
|
|
143
164
|
]
|
|
144
165
|
}),
|
|
145
|
-
|
|
166
|
+
(W.targetRef || W.secretRef) && /* @__PURE__ */ A("dl", {
|
|
167
|
+
className: "mt-4 space-y-3 border-t border-border-subtle pt-4 text-sm",
|
|
168
|
+
children: [W.targetRef && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
169
|
+
className: "text-text-secondary",
|
|
170
|
+
children: z("adaptercloud.connections.targetRef", "Target ref")
|
|
171
|
+
}), /* @__PURE__ */ k("dd", {
|
|
172
|
+
className: "mt-1 break-all rounded-lg bg-bg-sunken px-3 py-1.5 font-mono text-xs text-text-primary",
|
|
173
|
+
children: W.targetRef
|
|
174
|
+
})] }), W.secretRef && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
175
|
+
className: "text-text-secondary",
|
|
176
|
+
children: z("adaptercloud.connections.secretRef", "Secret ref")
|
|
177
|
+
}), /* @__PURE__ */ k("dd", {
|
|
178
|
+
className: "mt-1 break-all rounded-lg bg-bg-sunken px-3 py-1.5 font-mono text-xs text-text-primary",
|
|
179
|
+
children: W.secretRef
|
|
180
|
+
})] })]
|
|
181
|
+
}),
|
|
182
|
+
W.tags.length > 0 && /* @__PURE__ */ A("div", {
|
|
183
|
+
className: "mt-4",
|
|
184
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
185
|
+
className: "mb-2 text-sm font-semibold text-text-primary",
|
|
186
|
+
children: z("adaptercloud.common.tags", "Tags")
|
|
187
|
+
}), /* @__PURE__ */ k("div", {
|
|
188
|
+
className: "flex flex-wrap gap-1.5",
|
|
189
|
+
children: W.tags.map((e) => /* @__PURE__ */ k("span", {
|
|
190
|
+
className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary",
|
|
191
|
+
children: e
|
|
192
|
+
}, e))
|
|
193
|
+
})]
|
|
194
|
+
}),
|
|
195
|
+
W.lastError && /* @__PURE__ */ k("p", {
|
|
146
196
|
className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
147
|
-
children:
|
|
197
|
+
children: W.lastError
|
|
148
198
|
}),
|
|
149
199
|
/* @__PURE__ */ A("div", {
|
|
150
200
|
className: "mt-5 border-t border-border-subtle pt-5",
|
|
151
201
|
children: [/* @__PURE__ */ k("h3", {
|
|
152
202
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
153
|
-
children:
|
|
203
|
+
children: z("adaptercloud.connections.setHealth", "Set health")
|
|
154
204
|
}), /* @__PURE__ */ A("div", {
|
|
155
205
|
className: "flex flex-wrap gap-2",
|
|
156
206
|
children: [M.map((e) => /* @__PURE__ */ k("button", {
|
|
157
207
|
type: "button",
|
|
158
|
-
disabled:
|
|
159
|
-
onClick: () =>
|
|
208
|
+
disabled: V.isPending || W.status === e,
|
|
209
|
+
onClick: () => ie(e),
|
|
160
210
|
className: "rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40",
|
|
161
211
|
children: r[e]
|
|
162
|
-
}, e)),
|
|
212
|
+
}, e)), W.status !== "DISABLED" && /* @__PURE__ */ A("button", {
|
|
163
213
|
type: "button",
|
|
164
|
-
disabled:
|
|
165
|
-
onClick: () =>
|
|
214
|
+
disabled: H.isPending,
|
|
215
|
+
onClick: () => Q(!0),
|
|
166
216
|
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-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-40",
|
|
167
|
-
children: [/* @__PURE__ */ k(S, { className: "h-3.5 w-3.5" }),
|
|
217
|
+
children: [/* @__PURE__ */ k(S, { className: "h-3.5 w-3.5" }), z("adaptercloud.connections.disable", "Disable")]
|
|
168
218
|
})]
|
|
169
219
|
})]
|
|
170
220
|
}),
|
|
@@ -173,35 +223,35 @@ function P() {
|
|
|
173
223
|
children: [
|
|
174
224
|
/* @__PURE__ */ A("h3", {
|
|
175
225
|
className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
176
|
-
children: [/* @__PURE__ */ k(E, { className: "h-4 w-4" }),
|
|
226
|
+
children: [/* @__PURE__ */ k(E, { className: "h-4 w-4" }), z("adaptercloud.connections.startSync", "Start a sync run")]
|
|
177
227
|
}),
|
|
178
|
-
!
|
|
228
|
+
!G && /* @__PURE__ */ k("p", {
|
|
179
229
|
id: "disabled-connection-sync-help",
|
|
180
230
|
className: "mb-3 text-sm text-text-secondary",
|
|
181
|
-
children:
|
|
231
|
+
children: z("adaptercloud.connections.disabledSyncHelp", "Sync runs are unavailable while this connection is disabled. Set its health to re-enable sync.")
|
|
182
232
|
}),
|
|
183
233
|
/* @__PURE__ */ k("p", {
|
|
184
234
|
id: "unsupported-sync-kind-help",
|
|
185
235
|
className: "mb-3 text-sm text-text-secondary",
|
|
186
|
-
children:
|
|
236
|
+
children: z("adaptercloud.connections.syncModeAvailabilityHelp", "Discovery is executable today. Reconcile, Cost Ingest, and Full need distinct backend workers and are not available yet.")
|
|
187
237
|
}),
|
|
188
238
|
/* @__PURE__ */ k("div", {
|
|
189
239
|
className: "flex flex-wrap gap-2",
|
|
190
240
|
children: N.map((e) => {
|
|
191
|
-
let t =
|
|
241
|
+
let t = U.isPending && J === e, n = v(e);
|
|
192
242
|
return /* @__PURE__ */ A("button", {
|
|
193
243
|
type: "button",
|
|
194
|
-
disabled:
|
|
195
|
-
"aria-describedby": n ?
|
|
196
|
-
title: n ?
|
|
197
|
-
onClick: () =>
|
|
244
|
+
disabled: U.isPending || !G || !n,
|
|
245
|
+
"aria-describedby": n ? G ? void 0 : "disabled-connection-sync-help" : "unsupported-sync-kind-help",
|
|
246
|
+
title: n ? G ? void 0 : z("adaptercloud.connections.disabledSyncTooltip", "Re-enable this connection before starting a sync run.") : z("adaptercloud.connections.unsupportedSyncModeTooltip", "This sync mode is not available yet because it needs a distinct backend worker."),
|
|
247
|
+
onClick: () => oe(e),
|
|
198
248
|
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 disabled:cursor-not-allowed disabled:opacity-50",
|
|
199
249
|
children: [
|
|
200
250
|
t ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(T, { className: "h-4 w-4" }),
|
|
201
251
|
o[e],
|
|
202
252
|
!n && /* @__PURE__ */ k("span", {
|
|
203
253
|
className: "rounded bg-bg-sunken px-1.5 py-0.5 text-[10px] font-normal text-text-secondary",
|
|
204
|
-
children:
|
|
254
|
+
children: z("adaptercloud.connections.notAvailable", "Not available")
|
|
205
255
|
})
|
|
206
256
|
]
|
|
207
257
|
}, e);
|
|
@@ -211,32 +261,95 @@ function P() {
|
|
|
211
261
|
})
|
|
212
262
|
]
|
|
213
263
|
}),
|
|
214
|
-
|
|
264
|
+
/* @__PURE__ */ A("section", { children: [/* @__PURE__ */ A("div", {
|
|
265
|
+
className: "mb-3 flex items-center justify-between",
|
|
266
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
267
|
+
className: "text-base font-semibold text-text-primary",
|
|
268
|
+
children: z("adaptercloud.connections.recentRuns", "Recent Sync Runs")
|
|
269
|
+
}), /* @__PURE__ */ k("button", {
|
|
270
|
+
type: "button",
|
|
271
|
+
onClick: () => L(`/sync-runs?connectionId=${W.id}`),
|
|
272
|
+
className: "text-sm font-medium text-accent-blue hover:underline",
|
|
273
|
+
children: z("adaptercloud.common.viewAll", "View all")
|
|
274
|
+
})]
|
|
275
|
+
}), /* @__PURE__ */ k(l, {
|
|
276
|
+
isLoading: K.isLoading,
|
|
277
|
+
isError: K.isError,
|
|
278
|
+
isEmpty: q.length === 0,
|
|
279
|
+
error: K.error,
|
|
280
|
+
onRetry: () => void K.refetch(),
|
|
281
|
+
emptyTitle: z("adaptercloud.connections.noRuns", "No sync runs yet"),
|
|
282
|
+
emptyDescription: z("adaptercloud.connections.noRunsDescription", "Start a sync run above to keep this connection’s inventory current."),
|
|
283
|
+
emptyIcon: /* @__PURE__ */ k(E, { className: "h-10 w-10" }),
|
|
284
|
+
children: /* @__PURE__ */ k("div", {
|
|
285
|
+
className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
|
|
286
|
+
children: q.map((e) => /* @__PURE__ */ A("div", {
|
|
287
|
+
className: "flex flex-wrap items-center gap-x-4 gap-y-2 px-4 py-3",
|
|
288
|
+
children: [
|
|
289
|
+
/* @__PURE__ */ k("span", {
|
|
290
|
+
className: "min-w-24 text-sm font-medium text-text-primary",
|
|
291
|
+
children: o[e.kind]
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ k(c, {
|
|
294
|
+
status: e.status,
|
|
295
|
+
label: s[e.status]
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ A("span", {
|
|
298
|
+
className: "text-xs text-text-secondary",
|
|
299
|
+
children: [
|
|
300
|
+
z("adaptercloud.syncRuns.discovered", "Discovered"),
|
|
301
|
+
" ",
|
|
302
|
+
/* @__PURE__ */ k("span", {
|
|
303
|
+
className: "tabular-nums text-text-primary",
|
|
304
|
+
children: F(e.status) ? "—" : e.discoveredCount
|
|
305
|
+
})
|
|
306
|
+
]
|
|
307
|
+
}),
|
|
308
|
+
/* @__PURE__ */ A("span", {
|
|
309
|
+
className: "text-xs text-text-secondary",
|
|
310
|
+
children: [
|
|
311
|
+
z("adaptercloud.syncRuns.drift", "Drift"),
|
|
312
|
+
" ",
|
|
313
|
+
/* @__PURE__ */ k("span", {
|
|
314
|
+
className: "tabular-nums text-text-primary",
|
|
315
|
+
children: F(e.status) ? "—" : e.driftCount
|
|
316
|
+
})
|
|
317
|
+
]
|
|
318
|
+
}),
|
|
319
|
+
/* @__PURE__ */ k("span", {
|
|
320
|
+
className: "ml-auto text-xs text-text-secondary",
|
|
321
|
+
children: e.finishedAt ? m(e.finishedAt) : z("adaptercloud.syncRuns.notFinished", "Not finished")
|
|
322
|
+
})
|
|
323
|
+
]
|
|
324
|
+
}, e.id))
|
|
325
|
+
})
|
|
326
|
+
})] }),
|
|
327
|
+
W.config != null && /* @__PURE__ */ A(j, {
|
|
215
328
|
className: "p-6",
|
|
216
329
|
children: [/* @__PURE__ */ k("h3", {
|
|
217
330
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
218
|
-
children:
|
|
331
|
+
children: z("adaptercloud.connections.config", "Configuration")
|
|
219
332
|
}), /* @__PURE__ */ k("pre", {
|
|
220
333
|
className: "overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary",
|
|
221
|
-
children: JSON.stringify(
|
|
334
|
+
children: JSON.stringify(W.config, null, 2)
|
|
222
335
|
})]
|
|
223
336
|
}),
|
|
224
337
|
/* @__PURE__ */ A("section", { children: [/* @__PURE__ */ A("div", {
|
|
225
338
|
className: "mb-3 flex items-center justify-between",
|
|
226
339
|
children: [/* @__PURE__ */ k("h3", {
|
|
227
340
|
className: "text-base font-semibold text-text-primary",
|
|
228
|
-
children:
|
|
341
|
+
children: z("adaptercloud.connections.discoveredResources", "Discovered Resources")
|
|
229
342
|
}), /* @__PURE__ */ k("button", {
|
|
230
343
|
type: "button",
|
|
231
|
-
onClick: () =>
|
|
344
|
+
onClick: () => L(`/resources?connectionId=${W.id}`),
|
|
232
345
|
className: "text-sm font-medium text-accent-blue hover:underline",
|
|
233
|
-
children:
|
|
346
|
+
children: z("adaptercloud.common.viewAll", "View all")
|
|
234
347
|
})]
|
|
235
|
-
}),
|
|
348
|
+
}), W.resources && W.resources.length > 0 ? /* @__PURE__ */ k("div", {
|
|
236
349
|
className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
|
|
237
|
-
children:
|
|
350
|
+
children: W.resources.slice(0, 10).map((e) => /* @__PURE__ */ A("button", {
|
|
238
351
|
type: "button",
|
|
239
|
-
onClick: () =>
|
|
352
|
+
onClick: () => L(`/resources/${e.id}`),
|
|
240
353
|
className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50",
|
|
241
354
|
children: [
|
|
242
355
|
/* @__PURE__ */ k(D, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
|
|
@@ -254,7 +367,7 @@ function P() {
|
|
|
254
367
|
className: "hidden text-xs text-text-secondary sm:inline",
|
|
255
368
|
children: i(e.monthlyCost)
|
|
256
369
|
}),
|
|
257
|
-
/* @__PURE__ */ k(
|
|
370
|
+
/* @__PURE__ */ k(c, {
|
|
258
371
|
status: e.state,
|
|
259
372
|
label: a[e.state]
|
|
260
373
|
})
|
|
@@ -262,24 +375,24 @@ function P() {
|
|
|
262
375
|
}, e.id))
|
|
263
376
|
}) : /* @__PURE__ */ k("p", {
|
|
264
377
|
className: "rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary",
|
|
265
|
-
children:
|
|
378
|
+
children: z("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
|
|
266
379
|
})] })
|
|
267
380
|
]
|
|
268
381
|
})
|
|
269
|
-
}), /* @__PURE__ */ k(
|
|
270
|
-
open:
|
|
271
|
-
onOpenChange:
|
|
272
|
-
title:
|
|
273
|
-
description:
|
|
274
|
-
confirmLabel:
|
|
275
|
-
cancelLabel:
|
|
276
|
-
onConfirm:
|
|
277
|
-
isPending:
|
|
382
|
+
}), /* @__PURE__ */ k(h, {
|
|
383
|
+
open: re,
|
|
384
|
+
onOpenChange: Q,
|
|
385
|
+
title: z("adaptercloud.connections.disableTitle", "Disable this connection?"),
|
|
386
|
+
description: z("adaptercloud.connections.disablePrompt", "Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health."),
|
|
387
|
+
confirmLabel: z("adaptercloud.connections.disable", "Disable"),
|
|
388
|
+
cancelLabel: z("adaptercloud.common.cancel", "Cancel"),
|
|
389
|
+
onConfirm: ae,
|
|
390
|
+
isPending: H.isPending,
|
|
278
391
|
tone: "danger"
|
|
279
392
|
})]
|
|
280
393
|
});
|
|
281
394
|
}
|
|
282
395
|
//#endregion
|
|
283
|
-
export {
|
|
396
|
+
export { I as ConnectionDetailPage };
|
|
284
397
|
|
|
285
398
|
//# sourceMappingURL=ConnectionDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"sourcesContent":["/**\n * Connection Detail Page\n * @module adaptercloud/pages/connections\n *\n * One connection (`adaConnection`) — its adapter, health, config, and the\n * resources it has discovered. Supports the validated health transition\n * (`adaSetConnectionStatus`), disable (`adaDisableConnection`), and starting a\n * sync run (`adaStartSyncRun`) against it.\n */\n\nimport { useCallback, useState } from 'react';\nimport { Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Ban, Pencil, Play, RefreshCw, Server } 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 {\n useConnection,\n useDisableConnection,\n useSetConnectionStatus,\n useStartSyncRun,\n} from '../../hooks/useAdapterCloudApi';\nimport {\n authMethodLabels,\n connectionStatusLabels,\n resourceStateLabels,\n syncKindLabels,\n} from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport { formatMoney } from '../../utils/domain';\nimport type { AdaConnectionStatus, AdaSyncKind } from '../../types';\nimport {\n canStartConnectionSync,\n canStartConnectionSyncKind,\n isConnectionSyncKindExecutable,\n} from './connectionSync';\n\nconst TRANSITIONABLE: AdaConnectionStatus[] = ['CONNECTED', 'DEGRADED', 'ERROR', 'PENDING'];\nconst SYNC_KINDS: AdaSyncKind[] = ['DISCOVERY', 'RECONCILE', 'COST_INGEST', 'FULL'];\n\nexport function ConnectionDetailPage() {\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 = useConnection(id);\n const setStatus = useSetConnectionStatus();\n const disable = useDisableConnection();\n const startRun = useStartSyncRun();\n const conn = query.data;\n const syncEnabled = conn ? canStartConnectionSync(conn.status) : false;\n\n const [runningKind, setRunningKind] = useState<AdaSyncKind | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmDisableOpen, setConfirmDisableOpen] = useState(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 handleSetStatus = useCallback(\n (newStatus: AdaConnectionStatus) => {\n if (!id) return;\n setActionError(null);\n setStatus.mutate({ id, status: newStatus }, { onError });\n },\n [id, setStatus, onError]\n );\n\n const handleDisable = useCallback(() => {\n if (!id) return;\n setActionError(null);\n disable.mutate(id, {\n onSuccess: () => setConfirmDisableOpen(false),\n onError,\n });\n }, [id, disable, onError]);\n\n const handleStartKind = useCallback(\n (kind: AdaSyncKind) => {\n if (!id || !conn || !canStartConnectionSyncKind(conn.status, kind)) return;\n setActionError(null);\n setRunningKind(kind);\n startRun.mutate(\n { connectionId: id, kind },\n {\n onSuccess: () => {\n setRunningKind(null);\n navigateTo('/sync-runs');\n },\n onError: (err) => {\n setRunningKind(null);\n onError(err);\n },\n }\n );\n },\n [id, conn, startRun, navigateTo, onError]\n );\n\n return (\n <PageLayout\n title={conn?.name ?? t('adaptercloud.connections.detailTitle', 'Connection')}\n description={conn?.adapter?.name}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\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 {conn && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${conn.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 )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !conn}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.notFound', 'Connection not found')}\n >\n {conn && (\n <div className=\"space-y-6\">\n {actionError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"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 {/* Health + actions */}\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <StatusBadge status={conn.status} />\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 {authMethodLabels[conn.authMethod]}\n </span>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-4\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.region', 'Region')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">{conn.region ?? '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.environment', 'Environment')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.environment ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.resourceCount', 'Resources')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {conn.resourceCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.lastSynced', 'Last synced')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.lastSyncedAt ? formatDate(conn.lastSyncedAt) : '—'}\n </dd>\n </div>\n </dl>\n\n {conn.lastError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n {/* Health transitions */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.setHealth', 'Set health')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {TRANSITIONABLE.map((s) => (\n <button\n key={s}\n type=\"button\"\n disabled={setStatus.isPending || conn.status === s}\n onClick={() => handleSetStatus(s)}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {connectionStatusLabels[s]}\n </button>\n ))}\n {conn.status !== 'DISABLED' && (\n <button\n type=\"button\"\n disabled={disable.isPending}\n onClick={() => setConfirmDisableOpen(true)}\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-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-40\"\n >\n <Ban className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.connections.disable', 'Disable')}\n </button>\n )}\n </div>\n </div>\n\n {/* Start sync run */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.connections.startSync', 'Start a sync run')}\n </h3>\n {!syncEnabled && (\n <p\n id=\"disabled-connection-sync-help\"\n className=\"mb-3 text-sm text-text-secondary\"\n >\n {t(\n 'adaptercloud.connections.disabledSyncHelp',\n 'Sync runs are unavailable while this connection is disabled. Set its health to re-enable sync.'\n )}\n </p>\n )}\n <p id=\"unsupported-sync-kind-help\" className=\"mb-3 text-sm text-text-secondary\">\n {t(\n 'adaptercloud.connections.syncModeAvailabilityHelp',\n 'Discovery is executable today. Reconcile, Cost Ingest, and Full need distinct backend workers and are not available yet.'\n )}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {SYNC_KINDS.map((k) => {\n const pending = startRun.isPending && runningKind === k;\n const executable = isConnectionSyncKindExecutable(k);\n return (\n <button\n key={k}\n type=\"button\"\n disabled={startRun.isPending || !syncEnabled || !executable}\n aria-describedby={\n !executable\n ? 'unsupported-sync-kind-help'\n : syncEnabled\n ? undefined\n : 'disabled-connection-sync-help'\n }\n title={\n !executable\n ? t(\n 'adaptercloud.connections.unsupportedSyncModeTooltip',\n 'This sync mode is not available yet because it needs a distinct backend worker.'\n )\n : !syncEnabled\n ? t(\n 'adaptercloud.connections.disabledSyncTooltip',\n 'Re-enable this connection before starting a sync run.'\n )\n : undefined\n }\n onClick={() => handleStartKind(k)}\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 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {pending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Play className=\"h-4 w-4\" />\n )}\n {syncKindLabels[k]}\n {!executable && (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-[10px] font-normal text-text-secondary\">\n {t('adaptercloud.connections.notAvailable', 'Not available')}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n </GlassCard>\n\n {/* Config */}\n {conn.config != null && (\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.config', 'Configuration')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(conn.config, null, 2)}\n </pre>\n </GlassCard>\n )}\n\n {/* Resources */}\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.connections.discoveredResources', 'Discovered Resources')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources?connectionId=${conn.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 {conn.resources && conn.resources.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {conn.resources.slice(0, 10).map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/resources/${r.id}`)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <Server className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {r.resourceType}\n {r.region ? ` · ${r.region}` : ''}\n </p>\n </div>\n <span className=\"hidden text-xs text-text-secondary sm:inline\">\n {formatMoney(r.monthlyCost)}\n </span>\n <StatusBadge status={r.state} label={resourceStateLabels[r.state]} />\n </button>\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.connections.noResources',\n 'No resources discovered yet. Start a discovery sync run.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={confirmDisableOpen}\n onOpenChange={setConfirmDisableOpen}\n title={t('adaptercloud.connections.disableTitle', 'Disable this connection?')}\n description={t(\n 'adaptercloud.connections.disablePrompt',\n 'Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health.'\n )}\n confirmLabel={t('adaptercloud.connections.disable', 'Disable')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={handleDisable}\n isPending={disable.isPending}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConnectionDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"sourcesContent":["/**\n * Connection Detail Page\n * @module adaptercloud/pages/connections\n *\n * One connection (`adaConnection`) — its adapter, health, config, and the\n * resources it has discovered. Supports the validated health transition\n * (`adaSetConnectionStatus`), disable (`adaDisableConnection`), and starting a\n * sync run (`adaStartSyncRun`) against it.\n */\n\nimport { useCallback, useState } from 'react';\nimport { Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Ban, Pencil, Play, RefreshCw, Server } 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 {\n useConnection,\n useDisableConnection,\n useSetConnectionStatus,\n useStartSyncRun,\n useSyncRuns,\n} from '../../hooks/useAdapterCloudApi';\nimport {\n authMethodLabels,\n connectionStatusLabels,\n resourceStateLabels,\n syncKindLabels,\n syncStatusLabels,\n} from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\nimport { formatMoney } from '../../utils/domain';\nimport type { AdaConnectionStatus, AdaSyncKind, AdaSyncStatus } from '../../types';\nimport {\n canStartConnectionSync,\n canStartConnectionSyncKind,\n isConnectionSyncKindExecutable,\n} from './connectionSync';\n\nconst TRANSITIONABLE: AdaConnectionStatus[] = ['CONNECTED', 'DEGRADED', 'ERROR', 'PENDING'];\nconst SYNC_KINDS: AdaSyncKind[] = ['DISCOVERY', 'RECONCILE', 'COST_INGEST', 'FULL'];\n\n/** How many of this connection's most recent runs the detail panel shows. */\nconst RECENT_RUN_COUNT = 5;\n\n/** Counters are meaningless until a run has produced results. */\nfunction isRunPending(status: AdaSyncStatus): boolean {\n return status === 'QUEUED' || status === 'RUNNING';\n}\n\nexport function ConnectionDetailPage() {\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 = useConnection(id);\n const setStatus = useSetConnectionStatus();\n const disable = useDisableConnection();\n const startRun = useStartSyncRun();\n const conn = query.data;\n const syncEnabled = conn ? canStartConnectionSync(conn.status) : false;\n\n // The operations log scoped to this connection — `adaListSyncRuns` filters\n // server-side by `connectionId`, so this is the real run history, not a\n // client-side slice of the estate-wide list.\n const recentRuns = useSyncRuns(\n { connectionId: id, pagination: { limit: RECENT_RUN_COUNT, offset: 0 } },\n { enabled: Boolean(id) }\n );\n const runItems = recentRuns.data?.items ?? [];\n\n const [runningKind, setRunningKind] = useState<AdaSyncKind | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmDisableOpen, setConfirmDisableOpen] = useState(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 handleSetStatus = useCallback(\n (newStatus: AdaConnectionStatus) => {\n if (!id) return;\n setActionError(null);\n setStatus.mutate({ id, status: newStatus }, { onError });\n },\n [id, setStatus, onError]\n );\n\n const handleDisable = useCallback(() => {\n if (!id) return;\n setActionError(null);\n disable.mutate(id, {\n onSuccess: () => setConfirmDisableOpen(false),\n onError,\n });\n }, [id, disable, onError]);\n\n const handleStartKind = useCallback(\n (kind: AdaSyncKind) => {\n if (!id || !conn || !canStartConnectionSyncKind(conn.status, kind)) return;\n setActionError(null);\n setRunningKind(kind);\n startRun.mutate(\n { connectionId: id, kind },\n {\n onSuccess: () => {\n setRunningKind(null);\n navigateTo('/sync-runs');\n },\n onError: (err) => {\n setRunningKind(null);\n onError(err);\n },\n }\n );\n },\n [id, conn, startRun, navigateTo, onError]\n );\n\n return (\n <PageLayout\n title={conn?.name ?? t('adaptercloud.connections.detailTitle', 'Connection')}\n description={conn?.adapter?.name}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\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 {conn && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${conn.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 )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !conn}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.notFound', 'Connection not found')}\n >\n {conn && (\n <div className=\"space-y-6\">\n {actionError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"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 {/* Health + actions */}\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <StatusBadge status={conn.status} />\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 {authMethodLabels[conn.authMethod]}\n </span>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-4\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.adapter', 'Adapter')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.adapter ? (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/adapters/${conn.adapterId}`)}\n className=\"max-w-full truncate text-left text-accent-blue hover:underline\"\n >\n {conn.adapter.name}\n {conn.adapter.version ? ` v${conn.adapter.version}` : ''}\n </button>\n ) : (\n '—'\n )}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.region', 'Region')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">{conn.region ?? '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.environment', 'Environment')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.environment ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.resourceCount', 'Resources')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {conn.resourceCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.lastSynced', 'Last synced')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.lastSyncedAt ? formatDate(conn.lastSyncedAt) : '—'}\n </dd>\n </div>\n </dl>\n\n {/* Binding references — the target this connection points at and\n the secret-store reference used to authenticate against it.\n Both are opaque references stored on the connection, never a\n credential value. */}\n {(conn.targetRef || conn.secretRef) && (\n <dl className=\"mt-4 space-y-3 border-t border-border-subtle pt-4 text-sm\">\n {conn.targetRef && (\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.targetRef', 'Target ref')}\n </dt>\n <dd className=\"mt-1 break-all rounded-lg bg-bg-sunken px-3 py-1.5 font-mono text-xs text-text-primary\">\n {conn.targetRef}\n </dd>\n </div>\n )}\n {conn.secretRef && (\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.secretRef', 'Secret ref')}\n </dt>\n <dd className=\"mt-1 break-all rounded-lg bg-bg-sunken px-3 py-1.5 font-mono text-xs text-text-primary\">\n {conn.secretRef}\n </dd>\n </div>\n )}\n </dl>\n )}\n\n {conn.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 {conn.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\n {conn.lastError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n {/* Health transitions */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.setHealth', 'Set health')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {TRANSITIONABLE.map((s) => (\n <button\n key={s}\n type=\"button\"\n disabled={setStatus.isPending || conn.status === s}\n onClick={() => handleSetStatus(s)}\n className=\"rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\"\n >\n {connectionStatusLabels[s]}\n </button>\n ))}\n {conn.status !== 'DISABLED' && (\n <button\n type=\"button\"\n disabled={disable.isPending}\n onClick={() => setConfirmDisableOpen(true)}\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-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-40\"\n >\n <Ban className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.connections.disable', 'Disable')}\n </button>\n )}\n </div>\n </div>\n\n {/* Start sync run */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.connections.startSync', 'Start a sync run')}\n </h3>\n {!syncEnabled && (\n <p\n id=\"disabled-connection-sync-help\"\n className=\"mb-3 text-sm text-text-secondary\"\n >\n {t(\n 'adaptercloud.connections.disabledSyncHelp',\n 'Sync runs are unavailable while this connection is disabled. Set its health to re-enable sync.'\n )}\n </p>\n )}\n <p id=\"unsupported-sync-kind-help\" className=\"mb-3 text-sm text-text-secondary\">\n {t(\n 'adaptercloud.connections.syncModeAvailabilityHelp',\n 'Discovery is executable today. Reconcile, Cost Ingest, and Full need distinct backend workers and are not available yet.'\n )}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {SYNC_KINDS.map((k) => {\n const pending = startRun.isPending && runningKind === k;\n const executable = isConnectionSyncKindExecutable(k);\n return (\n <button\n key={k}\n type=\"button\"\n disabled={startRun.isPending || !syncEnabled || !executable}\n aria-describedby={\n !executable\n ? 'unsupported-sync-kind-help'\n : syncEnabled\n ? undefined\n : 'disabled-connection-sync-help'\n }\n title={\n !executable\n ? t(\n 'adaptercloud.connections.unsupportedSyncModeTooltip',\n 'This sync mode is not available yet because it needs a distinct backend worker.'\n )\n : !syncEnabled\n ? t(\n 'adaptercloud.connections.disabledSyncTooltip',\n 'Re-enable this connection before starting a sync run.'\n )\n : undefined\n }\n onClick={() => handleStartKind(k)}\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 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {pending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Play className=\"h-4 w-4\" />\n )}\n {syncKindLabels[k]}\n {!executable && (\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-[10px] font-normal text-text-secondary\">\n {t('adaptercloud.connections.notAvailable', 'Not available')}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n </GlassCard>\n\n {/* Recent sync runs against this connection */}\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.connections.recentRuns', 'Recent Sync Runs')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/sync-runs?connectionId=${conn.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 <DataState\n isLoading={recentRuns.isLoading}\n isError={recentRuns.isError}\n isEmpty={runItems.length === 0}\n error={recentRuns.error}\n onRetry={() => void recentRuns.refetch()}\n emptyTitle={t('adaptercloud.connections.noRuns', 'No sync runs yet')}\n emptyDescription={t(\n 'adaptercloud.connections.noRunsDescription',\n 'Start a sync run above to keep this connection’s inventory current.'\n )}\n emptyIcon={<RefreshCw className=\"h-10 w-10\" />}\n >\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {runItems.map((run) => (\n <div\n key={run.id}\n className=\"flex flex-wrap items-center gap-x-4 gap-y-2 px-4 py-3\"\n >\n <span className=\"min-w-24 text-sm font-medium text-text-primary\">\n {syncKindLabels[run.kind]}\n </span>\n <StatusBadge status={run.status} label={syncStatusLabels[run.status]} />\n <span className=\"text-xs text-text-secondary\">\n {t('adaptercloud.syncRuns.discovered', 'Discovered')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {isRunPending(run.status) ? '—' : run.discoveredCount}\n </span>\n </span>\n <span className=\"text-xs text-text-secondary\">\n {t('adaptercloud.syncRuns.drift', 'Drift')}{' '}\n <span className=\"tabular-nums text-text-primary\">\n {isRunPending(run.status) ? '—' : run.driftCount}\n </span>\n </span>\n <span className=\"ml-auto text-xs text-text-secondary\">\n {run.finishedAt\n ? formatRelativeTime(run.finishedAt)\n : t('adaptercloud.syncRuns.notFinished', 'Not finished')}\n </span>\n </div>\n ))}\n </div>\n </DataState>\n </section>\n\n {/* Config */}\n {conn.config != null && (\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.config', 'Configuration')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(conn.config, null, 2)}\n </pre>\n </GlassCard>\n )}\n\n {/* Resources */}\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.connections.discoveredResources', 'Discovered Resources')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources?connectionId=${conn.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 {conn.resources && conn.resources.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {conn.resources.slice(0, 10).map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/resources/${r.id}`)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <Server className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {r.resourceType}\n {r.region ? ` · ${r.region}` : ''}\n </p>\n </div>\n <span className=\"hidden text-xs text-text-secondary sm:inline\">\n {formatMoney(r.monthlyCost)}\n </span>\n <StatusBadge status={r.state} label={resourceStateLabels[r.state]} />\n </button>\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.connections.noResources',\n 'No resources discovered yet. Start a discovery sync run.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={confirmDisableOpen}\n onOpenChange={setConfirmDisableOpen}\n title={t('adaptercloud.connections.disableTitle', 'Disable this connection?')}\n description={t(\n 'adaptercloud.connections.disablePrompt',\n 'Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health.'\n )}\n confirmLabel={t('adaptercloud.connections.disable', 'Disable')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={handleDisable}\n isPending={disable.isPending}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsListPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoDH,wBAAgB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"ConnectionsListPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoDH,wBAAgB,mBAAmB,gCAoPlC"}
|