@burdenoff/microfe-adaptercloud 2026.825.2 → 2026.825.4
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/pages/connections/ConnectionDetailPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +148 -136
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/connectionSync.d.ts +3 -1
- package/dist/adaptercloud/pages/connections/connectionSync.d.ts.map +1 -1
- package/dist/adaptercloud/pages/connections/connectionSync.js +9 -2
- package/dist/adaptercloud/pages/connections/connectionSync.js.map +1 -1
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +24 -7
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +8 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"ConnectionDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH,wBAAgB,oBAAoB,gCA2VnC"}
|
|
@@ -6,192 +6,204 @@ import { DataState as c } from "../../components/DataState.js";
|
|
|
6
6
|
import { useConnection as l, useDisableConnection as u, useSetConnectionStatus as d, useStartSyncRun as f } from "../../hooks/useAdapterCloudApi.js";
|
|
7
7
|
import { formatDate as p } from "../../utils/formatters.js";
|
|
8
8
|
import { ConfirmDialog as m } from "../../components/ConfirmDialog.js";
|
|
9
|
-
import { canStartConnectionSync as h } from "./connectionSync.js";
|
|
10
|
-
import { useCallback as
|
|
11
|
-
import { useI18n as
|
|
12
|
-
import { ArrowLeft as
|
|
13
|
-
import { useParams as
|
|
14
|
-
import { jsx as
|
|
15
|
-
import { GlassCard as
|
|
9
|
+
import { canStartConnectionSync as h, canStartConnectionSyncKind as g, isConnectionSyncKindExecutable as _ } from "./connectionSync.js";
|
|
10
|
+
import { useCallback as v, useState as y } from "react";
|
|
11
|
+
import { useI18n as b } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
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
|
+
import { useParams as O } from "react-router";
|
|
14
|
+
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
15
|
+
import { GlassCard as j } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/adaptercloud/pages/connections/ConnectionDetailPage.tsx
|
|
17
|
-
var
|
|
17
|
+
var M = [
|
|
18
18
|
"CONNECTED",
|
|
19
19
|
"DEGRADED",
|
|
20
20
|
"ERROR",
|
|
21
21
|
"PENDING"
|
|
22
|
-
],
|
|
22
|
+
], N = [
|
|
23
23
|
"DISCOVERY",
|
|
24
24
|
"RECONCILE",
|
|
25
25
|
"COST_INGEST",
|
|
26
26
|
"FULL"
|
|
27
27
|
];
|
|
28
|
-
function
|
|
29
|
-
let { id:
|
|
30
|
-
let n =
|
|
28
|
+
function P() {
|
|
29
|
+
let { id: P } = O(), { navigateTo: F } = e(), { t: I } = b(), L = v((e, t) => {
|
|
30
|
+
let n = I(e);
|
|
31
31
|
return n === e ? t : n;
|
|
32
|
-
}, [
|
|
33
|
-
|
|
34
|
-
id:
|
|
32
|
+
}, [I]), R = l(P), z = d(), B = u(), V = f(), H = R.data, U = H ? h(H.status) : !1, [W, G] = y(null), [K, q] = y(null), [J, Y] = y(!1), X = v((e) => q(e instanceof Error ? e.message : "Action failed. Please try again."), []), Z = v((e) => {
|
|
33
|
+
P && (q(null), z.mutate({
|
|
34
|
+
id: P,
|
|
35
35
|
status: e
|
|
36
|
-
}, { onError:
|
|
36
|
+
}, { onError: X }));
|
|
37
37
|
}, [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
]),
|
|
42
|
-
|
|
43
|
-
onSuccess: () =>
|
|
44
|
-
onError:
|
|
38
|
+
P,
|
|
39
|
+
z,
|
|
40
|
+
X
|
|
41
|
+
]), Q = v(() => {
|
|
42
|
+
P && (q(null), B.mutate(P, {
|
|
43
|
+
onSuccess: () => Y(!1),
|
|
44
|
+
onError: X
|
|
45
45
|
}));
|
|
46
46
|
}, [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
]),
|
|
51
|
-
!
|
|
52
|
-
connectionId:
|
|
47
|
+
P,
|
|
48
|
+
B,
|
|
49
|
+
X
|
|
50
|
+
]), $ = v((e) => {
|
|
51
|
+
!P || !H || !g(H.status, e) || (q(null), G(e), V.mutate({
|
|
52
|
+
connectionId: P,
|
|
53
53
|
kind: e
|
|
54
54
|
}, {
|
|
55
55
|
onSuccess: () => {
|
|
56
|
-
|
|
56
|
+
G(null), F("/sync-runs");
|
|
57
57
|
},
|
|
58
58
|
onError: (e) => {
|
|
59
|
-
|
|
59
|
+
G(null), X(e);
|
|
60
60
|
}
|
|
61
61
|
}));
|
|
62
62
|
}, [
|
|
63
|
-
|
|
63
|
+
P,
|
|
64
|
+
H,
|
|
64
65
|
V,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
J
|
|
66
|
+
F,
|
|
67
|
+
X
|
|
68
68
|
]);
|
|
69
|
-
return /* @__PURE__ */
|
|
70
|
-
title:
|
|
71
|
-
description:
|
|
72
|
-
actions: /* @__PURE__ */
|
|
69
|
+
return /* @__PURE__ */ A(t, {
|
|
70
|
+
title: H?.name ?? L("adaptercloud.connections.detailTitle", "Connection"),
|
|
71
|
+
description: H?.adapter?.name,
|
|
72
|
+
actions: /* @__PURE__ */ A("div", {
|
|
73
73
|
className: "flex items-center gap-2",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ A("button", {
|
|
75
75
|
type: "button",
|
|
76
|
-
onClick: () =>
|
|
76
|
+
onClick: () => F("/connections"),
|
|
77
77
|
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__ */
|
|
79
|
-
}),
|
|
78
|
+
children: [/* @__PURE__ */ k(x, { className: "h-4 w-4" }), L("adaptercloud.common.back", "Back")]
|
|
79
|
+
}), H && /* @__PURE__ */ A("button", {
|
|
80
80
|
type: "button",
|
|
81
|
-
onClick: () =>
|
|
81
|
+
onClick: () => F(`/connections/${H.id}/edit`),
|
|
82
82
|
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__ */
|
|
83
|
+
children: [/* @__PURE__ */ k(w, { className: "h-4 w-4" }), L("adaptercloud.common.edit", "Edit")]
|
|
84
84
|
})]
|
|
85
85
|
}),
|
|
86
|
-
children: [/* @__PURE__ */
|
|
87
|
-
isLoading:
|
|
88
|
-
isError:
|
|
89
|
-
isEmpty: !
|
|
90
|
-
error:
|
|
91
|
-
onRetry: () => void
|
|
92
|
-
emptyTitle:
|
|
93
|
-
children:
|
|
86
|
+
children: [/* @__PURE__ */ k(c, {
|
|
87
|
+
isLoading: R.isLoading,
|
|
88
|
+
isError: R.isError,
|
|
89
|
+
isEmpty: !R.isLoading && !H,
|
|
90
|
+
error: R.error,
|
|
91
|
+
onRetry: () => void R.refetch(),
|
|
92
|
+
emptyTitle: L("adaptercloud.connections.notFound", "Connection not found"),
|
|
93
|
+
children: H && /* @__PURE__ */ A("div", {
|
|
94
94
|
className: "space-y-6",
|
|
95
95
|
children: [
|
|
96
|
-
|
|
96
|
+
K && /* @__PURE__ */ k("p", {
|
|
97
97
|
role: "alert",
|
|
98
98
|
"aria-live": "polite",
|
|
99
99
|
className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
100
|
-
children:
|
|
100
|
+
children: K
|
|
101
101
|
}),
|
|
102
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ A(j, {
|
|
103
103
|
className: "p-6",
|
|
104
104
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ A("div", {
|
|
106
106
|
className: "mb-4 flex flex-wrap items-center gap-3",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ k(s, { status: H.status }), /* @__PURE__ */ k("span", {
|
|
108
108
|
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[
|
|
109
|
+
children: n[H.authMethod]
|
|
110
110
|
})]
|
|
111
111
|
}),
|
|
112
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ A("dl", {
|
|
113
113
|
className: "grid grid-cols-2 gap-4 text-sm sm:grid-cols-4",
|
|
114
114
|
children: [
|
|
115
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
116
116
|
className: "text-text-secondary",
|
|
117
|
-
children:
|
|
118
|
-
}), /* @__PURE__ */
|
|
117
|
+
children: L("adaptercloud.connections.region", "Region")
|
|
118
|
+
}), /* @__PURE__ */ k("dd", {
|
|
119
119
|
className: "mt-0.5 font-medium text-text-primary",
|
|
120
|
-
children:
|
|
120
|
+
children: H.region ?? "—"
|
|
121
121
|
})] }),
|
|
122
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
123
123
|
className: "text-text-secondary",
|
|
124
|
-
children:
|
|
125
|
-
}), /* @__PURE__ */
|
|
124
|
+
children: L("adaptercloud.connections.environment", "Environment")
|
|
125
|
+
}), /* @__PURE__ */ k("dd", {
|
|
126
126
|
className: "mt-0.5 font-medium text-text-primary",
|
|
127
|
-
children:
|
|
127
|
+
children: H.environment ?? "—"
|
|
128
128
|
})] }),
|
|
129
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
130
130
|
className: "text-text-secondary",
|
|
131
|
-
children:
|
|
132
|
-
}), /* @__PURE__ */
|
|
131
|
+
children: L("adaptercloud.connections.resourceCount", "Resources")
|
|
132
|
+
}), /* @__PURE__ */ k("dd", {
|
|
133
133
|
className: "mt-0.5 font-medium tabular-nums text-text-primary",
|
|
134
|
-
children:
|
|
134
|
+
children: H.resourceCount
|
|
135
135
|
})] }),
|
|
136
|
-
/* @__PURE__ */
|
|
136
|
+
/* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("dt", {
|
|
137
137
|
className: "text-text-secondary",
|
|
138
|
-
children:
|
|
139
|
-
}), /* @__PURE__ */
|
|
138
|
+
children: L("adaptercloud.connections.lastSynced", "Last synced")
|
|
139
|
+
}), /* @__PURE__ */ k("dd", {
|
|
140
140
|
className: "mt-0.5 font-medium text-text-primary",
|
|
141
|
-
children:
|
|
141
|
+
children: H.lastSyncedAt ? p(H.lastSyncedAt) : "—"
|
|
142
142
|
})] })
|
|
143
143
|
]
|
|
144
144
|
}),
|
|
145
|
-
|
|
145
|
+
H.lastError && /* @__PURE__ */ k("p", {
|
|
146
146
|
className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
147
|
-
children:
|
|
147
|
+
children: H.lastError
|
|
148
148
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ A("div", {
|
|
150
150
|
className: "mt-5 border-t border-border-subtle pt-5",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
151
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
152
152
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
153
|
-
children:
|
|
154
|
-
}), /* @__PURE__ */
|
|
153
|
+
children: L("adaptercloud.connections.setHealth", "Set health")
|
|
154
|
+
}), /* @__PURE__ */ A("div", {
|
|
155
155
|
className: "flex flex-wrap gap-2",
|
|
156
|
-
children: [
|
|
156
|
+
children: [M.map((e) => /* @__PURE__ */ k("button", {
|
|
157
157
|
type: "button",
|
|
158
|
-
disabled:
|
|
159
|
-
onClick: () =>
|
|
158
|
+
disabled: z.isPending || H.status === e,
|
|
159
|
+
onClick: () => Z(e),
|
|
160
160
|
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
161
|
children: r[e]
|
|
162
|
-
}, e)),
|
|
162
|
+
}, e)), H.status !== "DISABLED" && /* @__PURE__ */ A("button", {
|
|
163
163
|
type: "button",
|
|
164
|
-
disabled:
|
|
165
|
-
onClick: () =>
|
|
164
|
+
disabled: B.isPending,
|
|
165
|
+
onClick: () => Y(!0),
|
|
166
166
|
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__ */
|
|
167
|
+
children: [/* @__PURE__ */ k(S, { className: "h-3.5 w-3.5" }), L("adaptercloud.connections.disable", "Disable")]
|
|
168
168
|
})]
|
|
169
169
|
})]
|
|
170
170
|
}),
|
|
171
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ A("div", {
|
|
172
172
|
className: "mt-5 border-t border-border-subtle pt-5",
|
|
173
173
|
children: [
|
|
174
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ A("h3", {
|
|
175
175
|
className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
176
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ k(E, { className: "h-4 w-4" }), L("adaptercloud.connections.startSync", "Start a sync run")]
|
|
177
177
|
}),
|
|
178
|
-
!
|
|
178
|
+
!U && /* @__PURE__ */ k("p", {
|
|
179
179
|
id: "disabled-connection-sync-help",
|
|
180
180
|
className: "mb-3 text-sm text-text-secondary",
|
|
181
|
-
children:
|
|
181
|
+
children: L("adaptercloud.connections.disabledSyncHelp", "Sync runs are unavailable while this connection is disabled. Set its health to re-enable sync.")
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ k("p", {
|
|
184
|
+
id: "unsupported-sync-kind-help",
|
|
185
|
+
className: "mb-3 text-sm text-text-secondary",
|
|
186
|
+
children: L("adaptercloud.connections.syncModeAvailabilityHelp", "Discovery is executable today. Reconcile, Cost Ingest, and Full need distinct backend workers and are not available yet.")
|
|
182
187
|
}),
|
|
183
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ k("div", {
|
|
184
189
|
className: "flex flex-wrap gap-2",
|
|
185
|
-
children:
|
|
186
|
-
let t =
|
|
187
|
-
return /* @__PURE__ */
|
|
190
|
+
children: N.map((e) => {
|
|
191
|
+
let t = V.isPending && W === e, n = _(e);
|
|
192
|
+
return /* @__PURE__ */ A("button", {
|
|
188
193
|
type: "button",
|
|
189
|
-
disabled:
|
|
190
|
-
"aria-describedby":
|
|
191
|
-
title:
|
|
192
|
-
onClick: () =>
|
|
193
|
-
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:opacity-50",
|
|
194
|
-
children: [
|
|
194
|
+
disabled: V.isPending || !U || !n,
|
|
195
|
+
"aria-describedby": n ? U ? void 0 : "disabled-connection-sync-help" : "unsupported-sync-kind-help",
|
|
196
|
+
title: n ? U ? void 0 : L("adaptercloud.connections.disabledSyncTooltip", "Re-enable this connection before starting a sync run.") : L("adaptercloud.connections.unsupportedSyncModeTooltip", "This sync mode is not available yet because it needs a distinct backend worker."),
|
|
197
|
+
onClick: () => $(e),
|
|
198
|
+
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
|
+
children: [
|
|
200
|
+
t ? /* @__PURE__ */ k(C, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(T, { className: "h-4 w-4" }),
|
|
201
|
+
o[e],
|
|
202
|
+
!n && /* @__PURE__ */ k("span", {
|
|
203
|
+
className: "rounded bg-bg-sunken px-1.5 py-0.5 text-[10px] font-normal text-text-secondary",
|
|
204
|
+
children: L("adaptercloud.connections.notAvailable", "Not available")
|
|
205
|
+
})
|
|
206
|
+
]
|
|
195
207
|
}, e);
|
|
196
208
|
})
|
|
197
209
|
})
|
|
@@ -199,75 +211,75 @@ function M() {
|
|
|
199
211
|
})
|
|
200
212
|
]
|
|
201
213
|
}),
|
|
202
|
-
|
|
214
|
+
H.config != null && /* @__PURE__ */ A(j, {
|
|
203
215
|
className: "p-6",
|
|
204
|
-
children: [/* @__PURE__ */
|
|
216
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
205
217
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
206
|
-
children:
|
|
207
|
-
}), /* @__PURE__ */
|
|
218
|
+
children: L("adaptercloud.connections.config", "Configuration")
|
|
219
|
+
}), /* @__PURE__ */ k("pre", {
|
|
208
220
|
className: "overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary",
|
|
209
|
-
children: JSON.stringify(
|
|
221
|
+
children: JSON.stringify(H.config, null, 2)
|
|
210
222
|
})]
|
|
211
223
|
}),
|
|
212
|
-
/* @__PURE__ */
|
|
224
|
+
/* @__PURE__ */ A("section", { children: [/* @__PURE__ */ A("div", {
|
|
213
225
|
className: "mb-3 flex items-center justify-between",
|
|
214
|
-
children: [/* @__PURE__ */
|
|
226
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
215
227
|
className: "text-base font-semibold text-text-primary",
|
|
216
|
-
children:
|
|
217
|
-
}), /* @__PURE__ */
|
|
228
|
+
children: L("adaptercloud.connections.discoveredResources", "Discovered Resources")
|
|
229
|
+
}), /* @__PURE__ */ k("button", {
|
|
218
230
|
type: "button",
|
|
219
|
-
onClick: () =>
|
|
231
|
+
onClick: () => F(`/resources?connectionId=${H.id}`),
|
|
220
232
|
className: "text-sm font-medium text-accent-blue hover:underline",
|
|
221
|
-
children:
|
|
233
|
+
children: L("adaptercloud.common.viewAll", "View all")
|
|
222
234
|
})]
|
|
223
|
-
}),
|
|
235
|
+
}), H.resources && H.resources.length > 0 ? /* @__PURE__ */ k("div", {
|
|
224
236
|
className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
|
|
225
|
-
children:
|
|
237
|
+
children: H.resources.slice(0, 10).map((e) => /* @__PURE__ */ A("button", {
|
|
226
238
|
type: "button",
|
|
227
|
-
onClick: () =>
|
|
239
|
+
onClick: () => F(`/resources/${e.id}`),
|
|
228
240
|
className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50",
|
|
229
241
|
children: [
|
|
230
|
-
/* @__PURE__ */ D
|
|
231
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ k(D, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
|
|
243
|
+
/* @__PURE__ */ A("div", {
|
|
232
244
|
className: "min-w-0 flex-1",
|
|
233
|
-
children: [/* @__PURE__ */
|
|
245
|
+
children: [/* @__PURE__ */ k("p", {
|
|
234
246
|
className: "truncate text-sm font-medium text-text-primary",
|
|
235
247
|
children: e.name
|
|
236
|
-
}), /* @__PURE__ */
|
|
248
|
+
}), /* @__PURE__ */ A("p", {
|
|
237
249
|
className: "mt-0.5 text-xs text-text-secondary",
|
|
238
250
|
children: [e.resourceType, e.region ? ` · ${e.region}` : ""]
|
|
239
251
|
})]
|
|
240
252
|
}),
|
|
241
|
-
/* @__PURE__ */
|
|
253
|
+
/* @__PURE__ */ k("span", {
|
|
242
254
|
className: "hidden text-xs text-text-secondary sm:inline",
|
|
243
255
|
children: i(e.monthlyCost)
|
|
244
256
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ k(s, {
|
|
246
258
|
status: e.state,
|
|
247
259
|
label: a[e.state]
|
|
248
260
|
})
|
|
249
261
|
]
|
|
250
262
|
}, e.id))
|
|
251
|
-
}) : /* @__PURE__ */
|
|
263
|
+
}) : /* @__PURE__ */ k("p", {
|
|
252
264
|
className: "rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary",
|
|
253
|
-
children:
|
|
265
|
+
children: L("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
|
|
254
266
|
})] })
|
|
255
267
|
]
|
|
256
268
|
})
|
|
257
|
-
}), /* @__PURE__ */
|
|
258
|
-
open:
|
|
259
|
-
onOpenChange:
|
|
260
|
-
title:
|
|
261
|
-
description:
|
|
262
|
-
confirmLabel:
|
|
263
|
-
cancelLabel:
|
|
264
|
-
onConfirm:
|
|
265
|
-
isPending:
|
|
269
|
+
}), /* @__PURE__ */ k(m, {
|
|
270
|
+
open: J,
|
|
271
|
+
onOpenChange: Y,
|
|
272
|
+
title: L("adaptercloud.connections.disableTitle", "Disable this connection?"),
|
|
273
|
+
description: L("adaptercloud.connections.disablePrompt", "Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health."),
|
|
274
|
+
confirmLabel: L("adaptercloud.connections.disable", "Disable"),
|
|
275
|
+
cancelLabel: L("adaptercloud.common.cancel", "Cancel"),
|
|
276
|
+
onConfirm: Q,
|
|
277
|
+
isPending: B.isPending,
|
|
266
278
|
tone: "danger"
|
|
267
279
|
})]
|
|
268
280
|
});
|
|
269
281
|
}
|
|
270
282
|
//#endregion
|
|
271
|
-
export {
|
|
283
|
+
export { P as ConnectionDetailPage };
|
|
272
284
|
|
|
273
285
|
//# 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 { canStartConnectionSync } 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 || !syncEnabled) 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, syncEnabled, 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 <div className=\"flex flex-wrap gap-2\">\n {SYNC_KINDS.map((k) => {\n const pending = startRun.isPending && runningKind === k;\n return (\n <button\n key={k}\n type=\"button\"\n disabled={startRun.isPending || !syncEnabled}\n aria-describedby={syncEnabled ? undefined : 'disabled-connection-sync-help'}\n title={\n syncEnabled\n ? undefined\n : t(\n 'adaptercloud.connections.disabledSyncTooltip',\n 'Re-enable this connection before starting a sync run.'\n )\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: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 </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} 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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"}
|
|
@@ -37,7 +37,7 @@ function N() {
|
|
|
37
37
|
}), L = o({
|
|
38
38
|
status: "PUBLISHED",
|
|
39
39
|
pagination: { limit: 100 }
|
|
40
|
-
}).data?.items ?? [], R = I.data?.items ?? [], z = I.data?.pageInfo.hasMore ?? !1, B = u(() => {
|
|
40
|
+
}).data?.items ?? [], R = u(() => I.data?.items ?? [], [I.data?.items]), z = I.data?.pageInfo.hasMore ?? !1, B = u(() => {
|
|
41
41
|
let e = T.trim().toLowerCase();
|
|
42
42
|
return e ? R.filter((t) => t.name.toLowerCase().includes(e) || (t.region?.toLowerCase().includes(e) ?? !1) || (t.environment?.toLowerCase().includes(e) ?? !1)) : R;
|
|
43
43
|
}, [R, T]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n * @module adaptercloud/pages/connections\n *\n * Every configured, authenticated target in the workspace. Lists from\n * `adaListConnections` with an adapter + status filter, a client-side search,\n * and offset pagination. Each card carries a per-adapter-kind glyph tile so the\n * fabric's reach reads at a glance (mirrors the aws/azure/gke/snowflake logos in\n * the mock).\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Cable,\n Plus,\n ChevronLeft,\n ChevronRight,\n MapPin,\n Server,\n Search,\n Cloud,\n Radio,\n Cpu,\n Boxes,\n Network,\n Database,\n HardDrive,\n Puzzle,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useConnections, useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { authMethodLabels, connectionStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaConnectionStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\n/**\n * Per-adapter-kind glyph — stands in for the vendor logos (aws / azure / gke /\n * snowflake) in the mock. Keyed off the connection's bound adapter kind; every\n * `AdaAdapterKind` maps to one of the eight allowed lucide marks.\n */\nconst adapterKindIcon: Record<AdaAdapterKind, LucideIcon> = {\n PUBLIC_CLOUD: Cloud,\n PRIVATE_CLOUD: Cloud,\n SAAS: Cloud,\n ON_PREM: HardDrive,\n EDGE: Radio,\n IOT: Cpu,\n KUBERNETES: Boxes,\n NETWORK: Network,\n DATA_SYSTEM: Database,\n CUSTOM: Puzzle,\n};\n\nexport function ConnectionsListPage() {\n const { navigateTo } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaConnectionStatus | ''>('');\n const [adapterId, setAdapterId] = useState('');\n const [search, setSearch] = useState('');\n const [offset, setOffset] = useState(0);\n\n const query = useConnections({\n adapterId: adapterId || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n // Published adapters power the adapter filter dropdown (mock's \"Adapter filter\").\n const adaptersQuery = useAdapters({ status: 'PUBLISHED', pagination: { limit: 100 } });\n const adapterOptions = adaptersQuery.data?.items ?? [];\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n // Client-side search over the loaded page (name / region / environment).\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return items;\n return items.filter(\n (c) =>\n c.name.toLowerCase().includes(q) ||\n (c.region?.toLowerCase().includes(q) ?? false) ||\n (c.environment?.toLowerCase().includes(q) ?? false)\n );\n }, [items, search]);\n\n return (\n <PageLayout\n title={t('adaptercloud.connections.title', 'Connections')}\n description={t(\n 'adaptercloud.connections.subtitle',\n 'Configured, authenticated targets — each connection is where the fabric actually reaches.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaConnectionStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByStatus', 'Filter by status')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.connections.allStatuses', 'All statuses')}</option>\n {(Object.keys(connectionStatusLabels) as AdaConnectionStatus[]).map((s) => (\n <option key={s} value={s}>\n {connectionStatusLabels[s]}\n </option>\n ))}\n </select>\n\n <select\n value={adapterId}\n onChange={(e) => {\n setAdapterId(e.target.value);\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByAdapter', 'Filter by adapter')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.connections.allAdapters', 'All adapters')}</option>\n {adapterOptions.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n\n <div className=\"relative w-full sm:ml-auto sm:w-64\">\n <Search\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label={t('adaptercloud.connections.search', 'Search connections')}\n placeholder={t('adaptercloud.connections.searchPlaceholder', 'Search…')}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.emptyTitle', 'No connections yet')}\n emptyDescription={t(\n 'adaptercloud.connections.emptyDescription',\n 'Create a connection to a real target to start discovering resources.'\n )}\n emptyIcon={<Cable className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-10 text-center text-sm text-text-secondary\">\n {t('adaptercloud.connections.noSearchMatch', 'No connections match your search.')}\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((conn) => {\n const KindIcon = conn.adapter?.kind ? adapterKindIcon[conn.adapter.kind] : Cable;\n return (\n <GlassCard\n key={conn.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/connections/${conn.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/connections/${conn.id}`);\n }\n }}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-accent-blue\">\n <KindIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {conn.name}\n </h3>\n {conn.adapter && (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n {conn.adapter.name}\n </p>\n )}\n </div>\n <StatusBadge status={conn.status} />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {authMethodLabels[conn.authMethod]}\n </span>\n {conn.region && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" /> {conn.region}\n </span>\n )}\n {conn.environment && <span>· {conn.environment}</span>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-2 text-sm text-text-primary\">\n <Server className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"font-semibold tabular-nums\">{conn.resourceCount}</span>\n <span className=\"text-text-secondary\">\n {t('adaptercloud.connections.resources', 'resources')}\n </span>\n </div>\n\n {conn.lastError && (\n <p className=\"mt-3 line-clamp-2 rounded-lg bg-status-error-bg-subtle px-2 py-1 text-xs text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {conn.lastSyncedAt\n ? `${t('adaptercloud.connections.lastSynced', 'Last synced')} ${formatRelativeTime(conn.lastSyncedAt)}`\n : t('adaptercloud.connections.neverSynced', 'Never synced')}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAyCA,IAAM,IAAY,IAOZ,IAAsD;CAC1D,cAAc;CACd,eAAe;CACf,MAAM;CACN,SAAS;CACT,MAAM;CACN,KAAK;CACL,YAAY;CACZ,SAAS;CACT,aAAa;CACb,QAAQ;AACV;AAEA,SAAgB,IAAsB;CACpC,IAAM,EAAE,kBAAe,EAAgB,GACjC,EAAE,GAAG,MAAc,EAAQ,GAC3B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,CAAG;EAC3B,OAAO,MAAU,IAAM,IAAW;CACpC,GACA,CAAC,CAAS,CACZ,GAEM,CAAC,GAAQ,KAAa,EAAmC,EAAE,GAC3D,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,CAAC,GAAQ,KAAa,EAAS,CAAC,GAEhC,IAAQ,EAAe;EAC3B,WAAW,KAAa,KAAA;EACxB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW;EAAO;CACzC,CAAC,GAIK,IADgB,EAAY;EAAE,QAAQ;EAAa,YAAY,EAAE,OAAO,IAAI;CAAE,CAC7D,EAAc,MAAM,SAAS,CAAC,GAE/C,IAAQ,EAAM,MAAM,SAAS,CAAC,GAC9B,IAAU,EAAM,MAAM,SAAS,WAAW,IAG1C,IAAW,QAAc;EAC7B,IAAM,IAAI,EAAO,KAAK,EAAE,YAAY;EAEpC,OADK,IACE,EAAM,QACV,MACC,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,MAC9B,EAAE,QAAQ,YAAY,EAAE,SAAS,CAAC,KAAK,QACvC,EAAE,aAAa,YAAY,EAAE,SAAS,CAAC,KAAK,GACjD,IANe;CAOjB,GAAG,CAAC,GAAO,CAAM,CAAC;CAElB,OACE,kBAAC,GAAD;EACE,OAAO,EAAE,kCAAkC,aAAa;EACxD,aAAa,EACX,qCACA,2FACF;EACA,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,kBAAkB;GAC5C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,GAC1B,EAAE,gCAAgC,gBAAgB,CAC7C;;YAdZ,CAiBE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM;MAEf,AADA,EAAU,EAAE,OAAO,KAAiC,GACpD,EAAU,CAAC;KACb;KACA,cAAY,EAAE,2CAA2C,kBAAkB;KAC3E,WAAU;eAPZ,CASE,kBAAC,UAAD;MAAQ,OAAM;gBAAI,EAAE,wCAAwC,cAAc;KAAU,CAAA,GAClF,OAAO,KAAK,CAAsB,EAA4B,KAAK,MACnE,kBAAC,UAAD;MAAgB,OAAO;gBACpB,EAAuB;KAClB,GAFK,CAEL,CACT,CACK;;IAER,kBAAC,UAAD;KACE,OAAO;KACP,WAAW,MAAM;MAEf,AADA,EAAa,EAAE,OAAO,KAAK,GAC3B,EAAU,CAAC;KACb;KACA,cAAY,EAAE,4CAA4C,mBAAmB;KAC7E,WAAU;eAPZ,CASE,kBAAC,UAAD;MAAQ,OAAM;gBAAI,EAAE,wCAAwC,cAAc;KAAU,CAAA,GACnF,EAAe,KAAK,MACnB,kBAAC,UAAD;MAAmB,OAAO,EAAE;gBACzB,EAAE;KACG,GAFK,EAAE,EAEP,CACT,CACK;;IAER,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,eAAY;MACZ,WAAU;KACX,CAAA,GACD,kBAAC,SAAD;MACE,MAAK;MACL,OAAO;MACP,WAAW,MAAM,EAAU,EAAE,OAAO,KAAK;MACzC,cAAY,EAAE,mCAAmC,oBAAoB;MACrE,aAAa,EAAE,8CAA8C,SAAS;MACtE,WAAU;KACX,CAAA,CACE;;GACF;MAEL,kBAAC,GAAD;GACE,WAAW,EAAM;GACjB,SAAS,EAAM;GACf,SAAS,EAAM,WAAW;GAC1B,OAAO,EAAM;GACb,eAAe,KAAK,EAAM,QAAQ;GAClC,YAAY,EAAE,uCAAuC,oBAAoB;GACzE,kBAAkB,EAChB,6CACA,sEACF;GACA,WAAW,kBAAC,GAAD,EAAO,WAAU,YAAa,CAAA;GACzC,aACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,kBAAkB;IAC5C,WAAU;cAET,EAAE,gCAAgC,gBAAgB;GAC7C,CAAA;aAnBZ,CAsBG,EAAS,WAAW,IACnB,kBAAC,KAAD;IAAG,WAAU;cACV,EAAE,0CAA0C,mCAAmC;GAC/E,CAAA,IAEH,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MAGX,kBAAC,GAAD;KAEE,MAAK;KACL,UAAU;KACV,eAAe,EAAW,gBAAgB,EAAK,IAAI;KACnD,YAAY,MAAM;MAChB,CAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,eAAe,GACjB,EAAW,gBAAgB,EAAK,IAAI;KAExC;KACA,WAAU;eAXZ;MAaE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAjBS,EAAK,SAAS,OAAO,EAAgB,EAAK,QAAQ,QAAQ,GAiBnE;SAAU,WAAU;SAAU,eAAY;QAAQ,CAAA;OAC/C,CAAA,GACL,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAK;UACJ,CAAA,GACH,EAAK,WACJ,kBAAC,KAAD;WAAG,WAAU;qBACV,EAAK,QAAQ;UACb,CAAA,CAEF;aACL,kBAAC,GAAD,EAAa,QAAQ,EAAK,OAAS,CAAA,CAChC;;OACF,CAAA,CACF;;MAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAiB,EAAK;QACnB,CAAA;QACL,EAAK,UACJ,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;UAAC;UAAE,EAAK;SACjC;;QAEP,EAAK,eAAe,kBAAC,QAAD,EAAA,UAAA,CAAM,MAAG,EAAK,WAAkB,EAAA,CAAA;OAClD;;MAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;QACjD,kBAAC,QAAD;SAAM,WAAU;mBAA8B,EAAK;QAAoB,CAAA;QACvE,kBAAC,QAAD;SAAM,WAAU;mBACb,EAAE,sCAAsC,WAAW;QAChD,CAAA;OACH;;MAEJ,EAAK,aACJ,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAK;MACL,CAAA;MAGL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAK,eACF,GAAG,EAAE,uCAAuC,aAAa,EAAE,GAAG,EAAmB,EAAK,YAAY,MAClG,EAAE,wCAAwC,cAAc;MAC3D,CAAA;KACM;OAhEJ,EAAK,EAgED,CAEd;GACE,CAAA,IAGL,IAAS,KAAK,MACd,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MACE,MAAK;MACL,UAAU,MAAW;MACrB,eAAe,GAAW,MAAM,KAAK,IAAI,GAAG,IAAI,CAAS,CAAC;MAC1D,WAAU;gBAJZ,CAME,kBAAC,GAAD,EAAa,WAAU,UAAW,CAAA,GACjC,EAAE,4BAA4B,UAAU,CACnC;;KACR,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACG,EAAE,+BAA+B,SAAS;OAAE;OAAE,IAAS;OAAE;OAAE,IAAS,EAAM;MACvE;;KACN,kBAAC,UAAD;MACE,MAAK;MACL,UAAU,CAAC;MACX,eAAe,GAAW,MAAM,IAAI,CAAS;MAC7C,WAAU;gBAJZ,CAMG,EAAE,4BAA4B,MAAM,GACrC,kBAAC,GAAD,EAAc,WAAU,UAAW,CAAA,CAC7B;;IACL;KAEE;IACD;;AAEhB"}
|
|
1
|
+
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n * @module adaptercloud/pages/connections\n *\n * Every configured, authenticated target in the workspace. Lists from\n * `adaListConnections` with an adapter + status filter, a client-side search,\n * and offset pagination. Each card carries a per-adapter-kind glyph tile so the\n * fabric's reach reads at a glance (mirrors the aws/azure/gke/snowflake logos in\n * the mock).\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Cable,\n Plus,\n ChevronLeft,\n ChevronRight,\n MapPin,\n Server,\n Search,\n Cloud,\n Radio,\n Cpu,\n Boxes,\n Network,\n Database,\n HardDrive,\n Puzzle,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useConnections, useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { authMethodLabels, connectionStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaConnectionStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\n/**\n * Per-adapter-kind glyph — stands in for the vendor logos (aws / azure / gke /\n * snowflake) in the mock. Keyed off the connection's bound adapter kind; every\n * `AdaAdapterKind` maps to one of the eight allowed lucide marks.\n */\nconst adapterKindIcon: Record<AdaAdapterKind, LucideIcon> = {\n PUBLIC_CLOUD: Cloud,\n PRIVATE_CLOUD: Cloud,\n SAAS: Cloud,\n ON_PREM: HardDrive,\n EDGE: Radio,\n IOT: Cpu,\n KUBERNETES: Boxes,\n NETWORK: Network,\n DATA_SYSTEM: Database,\n CUSTOM: Puzzle,\n};\n\nexport function ConnectionsListPage() {\n const { navigateTo } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n const [status, setStatus] = useState<AdaConnectionStatus | ''>('');\n const [adapterId, setAdapterId] = useState('');\n const [search, setSearch] = useState('');\n const [offset, setOffset] = useState(0);\n\n const query = useConnections({\n adapterId: adapterId || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n // Published adapters power the adapter filter dropdown (mock's \"Adapter filter\").\n const adaptersQuery = useAdapters({ status: 'PUBLISHED', pagination: { limit: 100 } });\n const adapterOptions = adaptersQuery.data?.items ?? [];\n\n const items = useMemo(() => query.data?.items ?? [], [query.data?.items]);\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n // Client-side search over the loaded page (name / region / environment).\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return items;\n return items.filter(\n (c) =>\n c.name.toLowerCase().includes(q) ||\n (c.region?.toLowerCase().includes(q) ?? false) ||\n (c.environment?.toLowerCase().includes(q) ?? false)\n );\n }, [items, search]);\n\n return (\n <PageLayout\n title={t('adaptercloud.connections.title', 'Connections')}\n description={t(\n 'adaptercloud.connections.subtitle',\n 'Configured, authenticated targets — each connection is where the fabric actually reaches.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaConnectionStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByStatus', 'Filter by status')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.connections.allStatuses', 'All statuses')}</option>\n {(Object.keys(connectionStatusLabels) as AdaConnectionStatus[]).map((s) => (\n <option key={s} value={s}>\n {connectionStatusLabels[s]}\n </option>\n ))}\n </select>\n\n <select\n value={adapterId}\n onChange={(e) => {\n setAdapterId(e.target.value);\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByAdapter', 'Filter by adapter')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">{t('adaptercloud.connections.allAdapters', 'All adapters')}</option>\n {adapterOptions.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n\n <div className=\"relative w-full sm:ml-auto sm:w-64\">\n <Search\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label={t('adaptercloud.connections.search', 'Search connections')}\n placeholder={t('adaptercloud.connections.searchPlaceholder', 'Search…')}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.emptyTitle', 'No connections yet')}\n emptyDescription={t(\n 'adaptercloud.connections.emptyDescription',\n 'Create a connection to a real target to start discovering resources.'\n )}\n emptyIcon={<Cable className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-10 text-center text-sm text-text-secondary\">\n {t('adaptercloud.connections.noSearchMatch', 'No connections match your search.')}\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((conn) => {\n const KindIcon = conn.adapter?.kind ? adapterKindIcon[conn.adapter.kind] : Cable;\n return (\n <GlassCard\n key={conn.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/connections/${conn.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/connections/${conn.id}`);\n }\n }}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-accent-blue\">\n <KindIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {conn.name}\n </h3>\n {conn.adapter && (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n {conn.adapter.name}\n </p>\n )}\n </div>\n <StatusBadge status={conn.status} />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {authMethodLabels[conn.authMethod]}\n </span>\n {conn.region && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" /> {conn.region}\n </span>\n )}\n {conn.environment && <span>· {conn.environment}</span>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-2 text-sm text-text-primary\">\n <Server className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"font-semibold tabular-nums\">{conn.resourceCount}</span>\n <span className=\"text-text-secondary\">\n {t('adaptercloud.connections.resources', 'resources')}\n </span>\n </div>\n\n {conn.lastError && (\n <p className=\"mt-3 line-clamp-2 rounded-lg bg-status-error-bg-subtle px-2 py-1 text-xs text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {conn.lastSyncedAt\n ? `${t('adaptercloud.connections.lastSynced', 'Last synced')} ${formatRelativeTime(conn.lastSyncedAt)}`\n : t('adaptercloud.connections.neverSynced', 'Never synced')}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { AdaConnectionStatus } from '../../types';
|
|
1
|
+
import { AdaConnectionStatus, AdaSyncKind } from '../../types';
|
|
2
2
|
|
|
3
3
|
export declare function canStartConnectionSync(status: AdaConnectionStatus): boolean;
|
|
4
|
+
export declare function isConnectionSyncKindExecutable(kind: AdaSyncKind): boolean;
|
|
5
|
+
export declare function canStartConnectionSyncKind(status: AdaConnectionStatus, kind: AdaSyncKind): boolean;
|
|
4
6
|
//# sourceMappingURL=connectionSync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionSync.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/connectionSync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"connectionSync.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/connectionSync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAIpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAE3E;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEzE;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE,WAAW,GAChB,OAAO,CAET"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
//#region src/adaptercloud/pages/connections/connectionSync.ts
|
|
2
|
-
|
|
2
|
+
var e = new Set(["DISCOVERY"]);
|
|
3
|
+
function t(e) {
|
|
3
4
|
return e !== "DISABLED";
|
|
4
5
|
}
|
|
6
|
+
function n(t) {
|
|
7
|
+
return e.has(t);
|
|
8
|
+
}
|
|
9
|
+
function r(e, r) {
|
|
10
|
+
return t(e) && n(r);
|
|
11
|
+
}
|
|
5
12
|
//#endregion
|
|
6
|
-
export {
|
|
13
|
+
export { t as canStartConnectionSync, r as canStartConnectionSyncKind, n as isConnectionSyncKindExecutable };
|
|
7
14
|
|
|
8
15
|
//# sourceMappingURL=connectionSync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionSync.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/connectionSync.ts"],"sourcesContent":["import type { AdaConnectionStatus } from '../../types';\n\nexport function canStartConnectionSync(status: AdaConnectionStatus): boolean {\n return status !== 'DISABLED';\n}\n"],"mappings":";AAEA,SAAgB,EAAuB,GAAsC;CAC3E,OAAO,MAAW;AACpB"}
|
|
1
|
+
{"version":3,"file":"connectionSync.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/connectionSync.ts"],"sourcesContent":["import type { AdaConnectionStatus, AdaSyncKind } from '../../types';\n\nconst EXECUTABLE_SYNC_KINDS: ReadonlySet<AdaSyncKind> = new Set(['DISCOVERY']);\n\nexport function canStartConnectionSync(status: AdaConnectionStatus): boolean {\n return status !== 'DISABLED';\n}\n\nexport function isConnectionSyncKindExecutable(kind: AdaSyncKind): boolean {\n return EXECUTABLE_SYNC_KINDS.has(kind);\n}\n\nexport function canStartConnectionSyncKind(\n status: AdaConnectionStatus,\n kind: AdaSyncKind\n): boolean {\n return canStartConnectionSync(status) && isConnectionSyncKindExecutable(kind);\n}\n"],"mappings":";AAEA,IAAM,IAAkD,IAAI,IAAI,CAAC,WAAW,CAAC;AAE7E,SAAgB,EAAuB,GAAsC;CAC3E,OAAO,MAAW;AACpB;AAEA,SAAgB,EAA+B,GAA4B;CACzE,OAAO,EAAsB,IAAI,CAAI;AACvC;AAEA,SAAgB,EACd,GACA,GACS;CACT,OAAO,EAAuB,CAAM,KAAK,EAA+B,CAAI;AAC9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAG1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAoB/C;AAMD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,wBAAwB,
|
|
1
|
+
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAG1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAoB/C;AAMD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,wBAAwB,CA+D1B"}
|
|
@@ -17,12 +17,29 @@ function t(e, t) {
|
|
|
17
17
|
return t.match(e);
|
|
18
18
|
}
|
|
19
19
|
function n(e, n) {
|
|
20
|
-
let r = new URLSearchParams(n)
|
|
20
|
+
let r = new URLSearchParams(n), i = new Map([
|
|
21
|
+
["/adaptercloud/adapters", "ADAPTERCLOUD_ADAPTER"],
|
|
22
|
+
["/adaptercloud/adapters/new", "ADAPTERCLOUD_ADAPTER"],
|
|
23
|
+
["/adaptercloud/connections", "ADAPTERCLOUD_CONNECTION"],
|
|
24
|
+
["/adaptercloud/connections/new", "ADAPTERCLOUD_CONNECTION"],
|
|
25
|
+
["/adaptercloud/resources", "ADAPTERCLOUD_RESOURCE"],
|
|
26
|
+
["/adaptercloud/topology", "ADAPTERCLOUD_TOPOLOGY"],
|
|
27
|
+
["/adaptercloud/policies", "ADAPTERCLOUD_POLICY"],
|
|
28
|
+
["/adaptercloud/policies/new", "ADAPTERCLOUD_POLICY"],
|
|
29
|
+
["/adaptercloud/violations", "ADAPTERCLOUD_VIOLATION"],
|
|
30
|
+
["/adaptercloud/drift", "ADAPTERCLOUD_DRIFT"],
|
|
31
|
+
["/adaptercloud/sync-runs", "ADAPTERCLOUD_SYNC_RUN"],
|
|
32
|
+
["/adaptercloud/costs", "ADAPTERCLOUD_COST"]
|
|
33
|
+
]).get(e);
|
|
34
|
+
if (i) return {
|
|
35
|
+
entityType: i,
|
|
36
|
+
metadata: { routePattern: e }
|
|
37
|
+
};
|
|
21
38
|
for (let [n, r] of [
|
|
22
|
-
[/^\/adaptercloud\/adapters\/([^/]+)
|
|
23
|
-
[/^\/adaptercloud\/connections\/([^/]+)
|
|
39
|
+
[/^\/adaptercloud\/adapters\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_ADAPTER"],
|
|
40
|
+
[/^\/adaptercloud\/connections\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_CONNECTION"],
|
|
24
41
|
[/^\/adaptercloud\/resources\/([^/]+)$/, "ADAPTERCLOUD_RESOURCE"],
|
|
25
|
-
[/^\/adaptercloud\/policies\/([^/]+)
|
|
42
|
+
[/^\/adaptercloud\/policies\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_POLICY"],
|
|
26
43
|
[/^\/adaptercloud\/sync-runs\/([^/]+)$/, "ADAPTERCLOUD_SYNC_RUN"]
|
|
27
44
|
]) {
|
|
28
45
|
let i = t(n, e);
|
|
@@ -32,13 +49,13 @@ function n(e, n) {
|
|
|
32
49
|
metadata: { routePattern: n.source }
|
|
33
50
|
};
|
|
34
51
|
}
|
|
35
|
-
let
|
|
52
|
+
let a = r.get("tab") ?? (() => {
|
|
36
53
|
let t = e.split("/").filter(Boolean);
|
|
37
54
|
return t.length > 2 ? t[t.length - 1] : void 0;
|
|
38
55
|
})();
|
|
39
56
|
return {
|
|
40
|
-
activeTab:
|
|
41
|
-
metadata: { ...
|
|
57
|
+
activeTab: a ?? void 0,
|
|
58
|
+
metadata: { ...a ? { activeTab: a } : {} }
|
|
42
59
|
};
|
|
43
60
|
}
|
|
44
61
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAdapterCloudConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: 'adaptercloud',\n version: import.meta.env.VITE_APP_VERSION ?? '2026.707.1',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveAdapterCloudConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/adaptercloud\\/adapters\\/([^/]+)
|
|
1
|
+
{"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAdapterCloudConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: 'adaptercloud',\n version: import.meta.env.VITE_APP_VERSION ?? '2026.707.1',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveAdapterCloudConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n // List, tool, and creation routes still identify the product entity family,\n // but intentionally carry no entityId. This lets the assistant understand\n // \"this page\" without fabricating a record identifier from route words such\n // as `new` (BOFF-3697).\n const pageMatches = new Map<string, string>([\n ['/adaptercloud/adapters', 'ADAPTERCLOUD_ADAPTER'],\n ['/adaptercloud/adapters/new', 'ADAPTERCLOUD_ADAPTER'],\n ['/adaptercloud/connections', 'ADAPTERCLOUD_CONNECTION'],\n ['/adaptercloud/connections/new', 'ADAPTERCLOUD_CONNECTION'],\n ['/adaptercloud/resources', 'ADAPTERCLOUD_RESOURCE'],\n ['/adaptercloud/topology', 'ADAPTERCLOUD_TOPOLOGY'],\n ['/adaptercloud/policies', 'ADAPTERCLOUD_POLICY'],\n ['/adaptercloud/policies/new', 'ADAPTERCLOUD_POLICY'],\n ['/adaptercloud/violations', 'ADAPTERCLOUD_VIOLATION'],\n ['/adaptercloud/drift', 'ADAPTERCLOUD_DRIFT'],\n ['/adaptercloud/sync-runs', 'ADAPTERCLOUD_SYNC_RUN'],\n ['/adaptercloud/costs', 'ADAPTERCLOUD_COST'],\n ]);\n const pageEntityType = pageMatches.get(pathname);\n if (pageEntityType) {\n return {\n entityType: pageEntityType,\n metadata: { routePattern: pathname },\n };\n }\n\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/adaptercloud\\/adapters\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_ADAPTER'],\n [/^\\/adaptercloud\\/connections\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_CONNECTION'],\n [/^\\/adaptercloud\\/resources\\/([^/]+)$/, 'ADAPTERCLOUD_RESOURCE'],\n [/^\\/adaptercloud\\/policies\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_POLICY'],\n [/^\\/adaptercloud\\/sync-runs\\/([^/]+)$/, 'ADAPTERCLOUD_SYNC_RUN'],\n ];\n\n for (const [pattern, entityType] of directMatches) {\n const match = matchPath(pattern, pathname);\n if (match) {\n return {\n entityType,\n entityId: match[1],\n metadata: {\n routePattern: pattern.source,\n },\n };\n }\n }\n\n const activeTab =\n params.get('tab') ??\n (() => {\n const segments = pathname.split('/').filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n },\n };\n}\n"],"mappings":";AA0BA,SAAgB,IAAiC;CAC/C,IAAM,IAAM,OAAO,SAAS,MAEtB,IADe,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAC5C,EAAa,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,QACpD,IAAS,EACb,OAAO,SAAS,UAChB,OAAO,SAAS,MAClB;CAEA,OAAO;EACL,YAAY;EACZ;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,UAAU;EACV,SAA6C;EAC7C,cAAc,GAAG,OAAO,WAAW,GAAG,OAAO;EAC7C,WAAW,UAAU;EACrB,4BAAW,IAAI,KAAK,GAAE,YAAY;CACpC;AACF;AAEA,SAAS,EAAU,GAAiB,GAA2C;CAC7E,OAAO,EAAS,MAAM,CAAO;AAC/B;AAEA,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAS,IAAI,gBAAgB,CAAM,GAoBnC,IAAiB,IAdC,IAAoB;EAC1C,CAAC,0BAA0B,sBAAsB;EACjD,CAAC,8BAA8B,sBAAsB;EACrD,CAAC,6BAA6B,yBAAyB;EACvD,CAAC,iCAAiC,yBAAyB;EAC3D,CAAC,2BAA2B,uBAAuB;EACnD,CAAC,0BAA0B,uBAAuB;EAClD,CAAC,0BAA0B,qBAAqB;EAChD,CAAC,8BAA8B,qBAAqB;EACpD,CAAC,4BAA4B,wBAAwB;EACrD,CAAC,uBAAuB,oBAAoB;EAC5C,CAAC,2BAA2B,uBAAuB;EACnD,CAAC,uBAAuB,mBAAmB;CAC7C,CACuB,EAAY,IAAI,CAAQ;CAC/C,IAAI,GACF,OAAO;EACL,YAAY;EACZ,UAAU,EAAE,cAAc,EAAS;CACrC;CAWF,KAAK,IAAM,CAAC,GAAS,MAAe;EAPlC,CAAC,kDAAkD,sBAAsB;EACzE,CAAC,qDAAqD,yBAAyB;EAC/E,CAAC,wCAAwC,uBAAuB;EAChE,CAAC,kDAAkD,qBAAqB;EACxE,CAAC,wCAAwC,uBAAuB;CAG9B,GAAe;EACjD,IAAM,IAAQ,EAAU,GAAS,CAAQ;EACzC,IAAI,GACF,OAAO;GACL;GACA,UAAU,EAAM;GAChB,UAAU,EACR,cAAc,EAAQ,OACxB;EACF;CAEJ;CAEA,IAAM,IACJ,EAAO,IAAI,KAAK,YACT;EACL,IAAM,IAAW,EAAS,MAAM,GAAG,EAAE,OAAO,OAAO;EACnD,OAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;CAC/D,GAAG;CAEL,OAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU,EACR,GAAI,IAAY,EAAE,aAAU,IAAI,CAAC,EACnC;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-adaptercloud",
|
|
3
|
-
"version": "2026.825.
|
|
3
|
+
"version": "2026.825.4",
|
|
4
4
|
"description": "Burdenoff AdapterCloud Microfrontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
"lint:sanity": "if [ \"${CI:-}\" = \"true\" ]; then bun run lint; else bun run lint -- --cache --cache-location .eslintcache; fi",
|
|
35
35
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
36
36
|
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
37
|
-
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run build && bun run build-storybook'",
|
|
37
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build && bun run build-storybook'",
|
|
38
38
|
"storybook": "storybook dev -p 6006",
|
|
39
39
|
"build-storybook": "storybook build",
|
|
40
|
+
"test": "bun test",
|
|
40
41
|
"test:storybook": "test-storybook",
|
|
41
42
|
"switch:status": "bun scripts/deps-mode.ts status",
|
|
42
43
|
"switch:remote": "bun scripts/deps-mode.ts remote",
|
|
@@ -83,14 +84,15 @@
|
|
|
83
84
|
"eslint-plugin-react": "^7.37.5",
|
|
84
85
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
85
86
|
"lefthook": "^2.1.1",
|
|
86
|
-
"postcss": "^8.
|
|
87
|
+
"postcss": "^8.5.26",
|
|
87
88
|
"prettier": "^3.4.2",
|
|
88
89
|
"storybook": "^8.6.0",
|
|
89
90
|
"tailwindcss": "^4.0.0",
|
|
90
91
|
"typescript": "^5.9.0",
|
|
91
92
|
"typescript-eslint": "^8.46.0",
|
|
92
93
|
"vite": "8.0.16",
|
|
93
|
-
"vite-plugin-dts": "3.9.1"
|
|
94
|
+
"vite-plugin-dts": "3.9.1",
|
|
95
|
+
"vitest": "^4.1.11"
|
|
94
96
|
},
|
|
95
97
|
"peerDependencies": {
|
|
96
98
|
"@apollo/client": "^4.0.11",
|
|
@@ -109,12 +111,13 @@
|
|
|
109
111
|
"fast-xml-parser": ">=4.5.5",
|
|
110
112
|
"@xmldom/xmldom": ">=0.8.12",
|
|
111
113
|
"swiper": ">=12.1.2",
|
|
112
|
-
"brace-expansion": ">=
|
|
114
|
+
"brace-expansion": ">=5.0.8",
|
|
113
115
|
"follow-redirects": ">=1.15.12",
|
|
114
116
|
"smol-toml": ">=1.6.1",
|
|
115
117
|
"axios": ">=1.15.0",
|
|
116
118
|
"flatted": ">=3.4.1",
|
|
117
119
|
"yaml": ">=2.8.3",
|
|
120
|
+
"js-yaml": "4.3.1",
|
|
118
121
|
"picomatch": ">=2.3.2",
|
|
119
122
|
"immutable": ">=3.8.3",
|
|
120
123
|
"minimatch": ">=3.1.3"
|