@burdenoff/microfe-vibecontrols 2026.1011.1 → 2026.1013.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/components/agents/CheckSessionHealthDialog.js +19 -0
- package/dist/components/agents/GatewayAuthCard.js +157 -167
- package/dist/components/agents/OneTimeSecretPanel.js +79 -0
- package/dist/components/agents/RepairGatewayAuthDialog.js +19 -0
- package/dist/components/agents/index.js +3 -0
- package/dist/hooks/useRepairGatewayAuth.js +59 -0
- package/dist/pages/AgentDetailsPage.js +1083 -918
- package/dist/pages/SessionsPage.js +691 -648
- package/dist/translations/en.js +34 -0
- package/dist/utils/agentGatewayRecovery.js +10 -0
- package/dist/utils/storeInstallSource.js +17 -0
- package/package.json +2 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
|
|
3
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/agents/CheckSessionHealthDialog.tsx
|
|
5
|
+
function r({ isOpen: r, onClose: i, onConfirm: a, isLoading: o = !1, message: s }) {
|
|
6
|
+
let c = e();
|
|
7
|
+
return /* @__PURE__ */ n(t, {
|
|
8
|
+
isOpen: r,
|
|
9
|
+
onClose: i,
|
|
10
|
+
onConfirm: a,
|
|
11
|
+
title: c("agentDetails.checkSessionHealthTitle", "Check session health?"),
|
|
12
|
+
message: s ?? c("agentDetails.checkSessionHealthMessage", "This checks every running session in the whole workspace, not only this agent’s. Any session whose agent reports it dead or cannot be reached is marked stopped, including sessions that belong to other agents."),
|
|
13
|
+
confirmLabel: c("agentDetails.checkSessionHealthConfirm", "Check all sessions"),
|
|
14
|
+
variant: "warning",
|
|
15
|
+
isLoading: o
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { r as CheckSessionHealthDialog };
|
|
@@ -1,281 +1,271 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useTr as
|
|
3
|
-
import { ConfirmDialog as
|
|
4
|
-
import { Card as
|
|
1
|
+
import { useUpdateAgentMutation as e } from "../../generated/wspace-operations.js";
|
|
2
|
+
import { useTr as t } from "../../shared/hooks/useTr.js";
|
|
3
|
+
import { ConfirmDialog as n } from "../shared/ConfirmDialog.js";
|
|
4
|
+
import { Card as r } from "../shared/Card.js";
|
|
5
5
|
import "../shared/index.js";
|
|
6
|
-
import { isNative as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { isNative as i, nativeCopyText as a, nativeToast as o } from "../../utils/nativeBridge.js";
|
|
7
|
+
import { notify as s } from "../../lib/toast.js";
|
|
8
|
+
import { VIBE_PERMISSIONS as c } from "../../constants/permissions.js";
|
|
9
|
+
import { useRepairGatewayAuth as l } from "../../hooks/useRepairGatewayAuth.js";
|
|
10
|
+
import { OneTimeSecretPanel as u } from "./OneTimeSecretPanel.js";
|
|
11
|
+
import { RepairGatewayAuthDialog as d } from "./RepairGatewayAuthDialog.js";
|
|
12
|
+
import { useState as f } from "react";
|
|
13
|
+
import { Check as p, Copy as m, Link2 as h, Loader2 as g, Monitor as _, RefreshCw as v, Shield as y, Unlink as b, X as x } from "lucide-react";
|
|
14
|
+
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
15
|
+
import { Button as T } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
import { PermissionButton as E } from "@burdenoff/fe-libs/shared/components";
|
|
11
17
|
//#region src/components/agents/GatewayAuthCard.tsx
|
|
12
|
-
function
|
|
13
|
-
let
|
|
14
|
-
|
|
18
|
+
function D({ agent: D, onUpdate: O }) {
|
|
19
|
+
let k = t(), [A] = e(), { repair: j, running: M, rotationEpoch: N } = l(D.id), [P, F] = f(!1), [I, L] = f(null), [R, z] = f(null), B = R && R.epoch === N ? R : null, [V, H] = f(!1), [U, W] = f(!1), [G, K] = f(!1), [q, J] = f(!1), Y = !!(D.appId && D.appClientId), X = D.metadata?.devportalApplicationId, Z = async () => {
|
|
20
|
+
F(!0), L(null);
|
|
15
21
|
try {
|
|
16
|
-
let
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
let e = await j();
|
|
23
|
+
if (e.status === "busy") {
|
|
24
|
+
L(k("agentDetails.repairAlreadyRunning", "A repair for this agent is already running. Wait for it to finish."));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (e.status === "failed") {
|
|
28
|
+
L(e.message || k("agentDetails.failedSetupGatewayAuth", "Failed to set up gateway auth"));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (e.status === "unchanged") {
|
|
32
|
+
s.info(k("agentDetails.repairUnchanged", "Nothing was changed: a credential push for this agent is already in progress or has just completed.")), O();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
z({
|
|
36
|
+
value: e.clientSecret,
|
|
37
|
+
delivered: e.status === "ok",
|
|
38
|
+
epoch: e.epoch
|
|
39
|
+
}), e.status === "delivery-failed" && L(e.error), O();
|
|
21
40
|
} finally {
|
|
22
|
-
|
|
41
|
+
F(!1);
|
|
23
42
|
}
|
|
24
|
-
},
|
|
25
|
-
|
|
43
|
+
}, Q = async () => {
|
|
44
|
+
W(!0), L(null);
|
|
26
45
|
try {
|
|
27
|
-
await
|
|
28
|
-
id:
|
|
46
|
+
await A({ variables: {
|
|
47
|
+
id: D.id,
|
|
29
48
|
input: {
|
|
30
49
|
appId: null,
|
|
31
50
|
appClientId: null
|
|
32
51
|
}
|
|
33
|
-
} }),
|
|
52
|
+
} }), z(null), K(!1), O();
|
|
34
53
|
} catch (e) {
|
|
35
|
-
|
|
54
|
+
K(!1), L(e instanceof Error ? e.message : k("agentDetails.failedUnlinkApp", "Failed to unlink app"));
|
|
36
55
|
} finally {
|
|
37
|
-
|
|
56
|
+
W(!1);
|
|
38
57
|
}
|
|
39
58
|
};
|
|
40
|
-
return /* @__PURE__ */
|
|
59
|
+
return /* @__PURE__ */ w(r, {
|
|
41
60
|
padding: "none",
|
|
42
61
|
children: [
|
|
43
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ C("div", {
|
|
44
63
|
className: "p-4 border-b border-border-default",
|
|
45
|
-
children: /* @__PURE__ */
|
|
64
|
+
children: /* @__PURE__ */ w("h3", {
|
|
46
65
|
className: "font-semibold text-text-primary flex items-center gap-2",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
66
|
+
children: [/* @__PURE__ */ C(y, {
|
|
48
67
|
className: "size-5",
|
|
49
68
|
"aria-hidden": "true"
|
|
50
|
-
}),
|
|
69
|
+
}), k("agentDetails.gatewayAuthTitle", "Gateway Auth (OAuth2)")]
|
|
51
70
|
})
|
|
52
71
|
}),
|
|
53
|
-
/* @__PURE__ */
|
|
72
|
+
/* @__PURE__ */ w("div", {
|
|
54
73
|
className: "p-4 space-y-3",
|
|
55
|
-
children: [
|
|
74
|
+
children: [I && /* @__PURE__ */ w("div", {
|
|
56
75
|
role: "alert",
|
|
57
76
|
className: "flex items-center gap-2 p-3 bg-status-error-bg-subtle border border-status-error-border text-status-error-text rounded-md text-sm",
|
|
58
77
|
children: [
|
|
59
|
-
/* @__PURE__ */ x
|
|
78
|
+
/* @__PURE__ */ C(x, {
|
|
60
79
|
className: "size-4 flex-shrink-0",
|
|
61
80
|
"aria-hidden": "true"
|
|
62
81
|
}),
|
|
63
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ C("span", {
|
|
64
83
|
className: "flex-1 min-w-0 break-words",
|
|
65
|
-
children:
|
|
84
|
+
children: I
|
|
66
85
|
}),
|
|
67
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ C("button", {
|
|
68
87
|
type: "button",
|
|
69
|
-
onClick: () =>
|
|
70
|
-
"aria-label":
|
|
88
|
+
onClick: () => L(null),
|
|
89
|
+
"aria-label": k("agentDetails.dismissError", "Dismiss error"),
|
|
71
90
|
className: "flex-shrink-0 p-0.5 hover:bg-status-error-border/40 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
72
|
-
children: /* @__PURE__ */ x
|
|
91
|
+
children: /* @__PURE__ */ C(x, {
|
|
73
92
|
className: "size-3.5",
|
|
74
93
|
"aria-hidden": "true"
|
|
75
94
|
})
|
|
76
95
|
})
|
|
77
96
|
]
|
|
78
|
-
}),
|
|
79
|
-
/* @__PURE__ */
|
|
97
|
+
}), Y ? /* @__PURE__ */ w(S, { children: [
|
|
98
|
+
/* @__PURE__ */ w("div", {
|
|
80
99
|
className: "flex items-start gap-3",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ C("div", {
|
|
82
101
|
className: "size-8 rounded-lg bg-status-success-bg-subtle flex items-center justify-center flex-shrink-0 mt-0.5",
|
|
83
|
-
children: /* @__PURE__ */
|
|
102
|
+
children: /* @__PURE__ */ C(h, {
|
|
84
103
|
className: "size-4 text-status-success-text",
|
|
85
104
|
"aria-hidden": "true"
|
|
86
105
|
})
|
|
87
|
-
}), /* @__PURE__ */
|
|
106
|
+
}), /* @__PURE__ */ w("div", {
|
|
88
107
|
className: "flex-1 min-w-0 space-y-2",
|
|
89
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
|
|
90
109
|
className: "text-sm font-medium text-text-primary",
|
|
91
|
-
children:
|
|
92
|
-
}), /* @__PURE__ */
|
|
110
|
+
children: k("agentDetails.linkedToOauthApp", "Linked to OAuth App")
|
|
111
|
+
}), /* @__PURE__ */ C("p", {
|
|
93
112
|
className: "text-xs text-text-muted",
|
|
94
|
-
children:
|
|
95
|
-
})] }), /* @__PURE__ */
|
|
113
|
+
children: k("agentDetails.gatewayAuthLinkedDescription", "This agent can authenticate with the API gateway using Client Credentials.")
|
|
114
|
+
})] }), /* @__PURE__ */ w("div", {
|
|
96
115
|
className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
|
|
97
|
-
children: [/* @__PURE__ */
|
|
116
|
+
children: [/* @__PURE__ */ w("div", {
|
|
98
117
|
className: "min-w-0",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
118
|
+
children: [/* @__PURE__ */ C("p", {
|
|
100
119
|
className: "text-xs text-text-secondary mb-1",
|
|
101
|
-
children:
|
|
102
|
-
}), /* @__PURE__ */
|
|
120
|
+
children: k("agentDetails.clientId", "Client ID")
|
|
121
|
+
}), /* @__PURE__ */ w("div", {
|
|
103
122
|
className: "flex items-center gap-2",
|
|
104
|
-
children: [/* @__PURE__ */
|
|
123
|
+
children: [/* @__PURE__ */ C("code", {
|
|
105
124
|
className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded truncate block flex-1 min-w-0",
|
|
106
|
-
children:
|
|
107
|
-
}), /* @__PURE__ */
|
|
125
|
+
children: D.appClientId
|
|
126
|
+
}), /* @__PURE__ */ C("button", {
|
|
108
127
|
type: "button",
|
|
109
128
|
onClick: async () => {
|
|
110
|
-
if (
|
|
111
|
-
await
|
|
129
|
+
if (D.appClientId) try {
|
|
130
|
+
await a(D.appClientId), i() && o("Copied"), H(!0), setTimeout(() => H(!1), 2e3);
|
|
112
131
|
} catch {}
|
|
113
132
|
},
|
|
114
|
-
"aria-label":
|
|
115
|
-
title:
|
|
133
|
+
"aria-label": k("agentDetails.copyClientId", "Copy Client ID"),
|
|
134
|
+
title: k("agentDetails.copyClientId", "Copy Client ID"),
|
|
116
135
|
className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
117
|
-
children:
|
|
136
|
+
children: V ? /* @__PURE__ */ C(p, {
|
|
118
137
|
className: "size-3.5 text-status-success-text",
|
|
119
138
|
"aria-hidden": "true"
|
|
120
|
-
}) : /* @__PURE__ */
|
|
139
|
+
}) : /* @__PURE__ */ C(m, {
|
|
121
140
|
className: "size-3.5 text-text-secondary",
|
|
122
141
|
"aria-hidden": "true"
|
|
123
142
|
})
|
|
124
143
|
})]
|
|
125
144
|
})]
|
|
126
|
-
}), /* @__PURE__ */
|
|
145
|
+
}), /* @__PURE__ */ w("div", {
|
|
127
146
|
className: "min-w-0",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ C("p", {
|
|
129
148
|
className: "text-xs text-text-secondary mb-1",
|
|
130
|
-
children:
|
|
131
|
-
}), /* @__PURE__ */
|
|
149
|
+
children: k("agentDetails.appId", "App ID")
|
|
150
|
+
}), /* @__PURE__ */ C("code", {
|
|
132
151
|
className: "text-xs font-mono text-text-muted bg-bg-sunken px-2 py-1 rounded truncate block",
|
|
133
|
-
children:
|
|
152
|
+
children: D.appId
|
|
134
153
|
})]
|
|
135
154
|
})]
|
|
136
155
|
})]
|
|
137
156
|
})]
|
|
138
157
|
}),
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
children: E("agentDetails.clientSecretOneTimeTitle", "Client Secret (one-time display)")
|
|
145
|
-
}),
|
|
146
|
-
/* @__PURE__ */ x("p", {
|
|
147
|
-
className: "text-xs text-text-secondary",
|
|
148
|
-
children: E("agentDetails.clientSecretOneTimeDescription", "This secret has been automatically sent to the agent. Save it now if you need it — it won't be shown again.")
|
|
149
|
-
}),
|
|
150
|
-
/* @__PURE__ */ S("div", {
|
|
151
|
-
className: "flex items-center gap-2",
|
|
152
|
-
children: [
|
|
153
|
-
/* @__PURE__ */ x("code", {
|
|
154
|
-
className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded flex-1 min-w-0 truncate",
|
|
155
|
-
children: N ? F : "•".repeat(32)
|
|
156
|
-
}),
|
|
157
|
-
/* @__PURE__ */ x("button", {
|
|
158
|
-
type: "button",
|
|
159
|
-
onClick: () => P(!N),
|
|
160
|
-
"aria-label": N ? E("agentDetails.hideClientSecret", "Hide client secret") : E("agentDetails.showClientSecret", "Show client secret"),
|
|
161
|
-
className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
162
|
-
children: x(N ? f : d, {
|
|
163
|
-
className: "size-3.5 text-text-secondary",
|
|
164
|
-
"aria-hidden": "true"
|
|
165
|
-
})
|
|
166
|
-
}),
|
|
167
|
-
/* @__PURE__ */ x("button", {
|
|
168
|
-
type: "button",
|
|
169
|
-
onClick: async () => {
|
|
170
|
-
if (F) try {
|
|
171
|
-
await o(F), a() && s("Secret copied"), R(!0), setTimeout(() => R(!1), 2e3);
|
|
172
|
-
} catch {}
|
|
173
|
-
},
|
|
174
|
-
"aria-label": E("agentDetails.copyClientSecret", "Copy client secret"),
|
|
175
|
-
className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
176
|
-
children: L ? /* @__PURE__ */ x(l, {
|
|
177
|
-
className: "size-3.5 text-status-success-text",
|
|
178
|
-
"aria-hidden": "true"
|
|
179
|
-
}) : /* @__PURE__ */ x(u, {
|
|
180
|
-
className: "size-3.5 text-text-secondary",
|
|
181
|
-
"aria-hidden": "true"
|
|
182
|
-
})
|
|
183
|
-
})
|
|
184
|
-
]
|
|
185
|
-
})
|
|
186
|
-
]
|
|
187
|
-
}),
|
|
188
|
-
/* @__PURE__ */ S("div", {
|
|
158
|
+
B && /* @__PURE__ */ C(u, {
|
|
159
|
+
secret: B.value,
|
|
160
|
+
description: B.delivered ? void 0 : k("agentDetails.clientSecretNotDelivered", "This secret could not be delivered to the agent, and the previous one no longer works. Save it now and configure the agent with it, or run Repair again once the agent is reachable — it won't be shown again.")
|
|
161
|
+
}, B.epoch),
|
|
162
|
+
/* @__PURE__ */ w("div", {
|
|
189
163
|
className: "flex flex-wrap items-center gap-2",
|
|
190
164
|
children: [
|
|
191
|
-
|
|
192
|
-
href: `/devportal/apps/${
|
|
165
|
+
X && /* @__PURE__ */ w("a", {
|
|
166
|
+
href: `/devportal/apps/${X}`,
|
|
193
167
|
className: "inline-flex items-center gap-2 px-3 py-1.5 text-xs font-medium text-text-primary bg-bg-sunken hover:bg-bg-elevated rounded-button transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
168
|
+
children: [/* @__PURE__ */ C(_, {
|
|
195
169
|
className: "size-3",
|
|
196
170
|
"aria-hidden": "true"
|
|
197
|
-
}),
|
|
171
|
+
}), k("agentDetails.viewInDeveloperPortal", "View in Developer Portal")]
|
|
198
172
|
}),
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
"aria-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
173
|
+
/* @__PURE__ */ C(E, {
|
|
174
|
+
permission: c.AGENT_UPDATE,
|
|
175
|
+
deniedBehavior: "disable",
|
|
176
|
+
deniedTooltip: k("agentDetails.repushCredentialsDenied", "You don't have permission to update agents"),
|
|
177
|
+
children: /* @__PURE__ */ w(T, {
|
|
178
|
+
type: "button",
|
|
179
|
+
variant: "secondary",
|
|
180
|
+
size: "sm",
|
|
181
|
+
onClick: () => J(!0),
|
|
182
|
+
disabled: P || M,
|
|
183
|
+
"aria-busy": P || M,
|
|
184
|
+
title: k("agentDetails.repushCredentialsTitle", "Rotate the OAuth secret and push it to the agent. Use this if the agent shows degraded with \"boot state awaiting-config\"."),
|
|
185
|
+
children: [P ? /* @__PURE__ */ C(g, {
|
|
186
|
+
className: "size-3 animate-spin",
|
|
187
|
+
"aria-hidden": "true"
|
|
188
|
+
}) : /* @__PURE__ */ C(v, {
|
|
189
|
+
className: "size-3",
|
|
190
|
+
"aria-hidden": "true"
|
|
191
|
+
}), k("agentDetails.repushCredentials", "Re-push credentials")]
|
|
192
|
+
})
|
|
214
193
|
}),
|
|
215
|
-
/* @__PURE__ */
|
|
194
|
+
/* @__PURE__ */ w(T, {
|
|
216
195
|
type: "button",
|
|
217
196
|
variant: "ghost",
|
|
218
197
|
size: "sm",
|
|
219
|
-
onClick: () =>
|
|
220
|
-
disabled:
|
|
221
|
-
"aria-busy":
|
|
198
|
+
onClick: () => K(!0),
|
|
199
|
+
disabled: U,
|
|
200
|
+
"aria-busy": U,
|
|
222
201
|
className: "text-status-error-text hover:bg-status-error-bg-subtle hover:text-status-error-text",
|
|
223
|
-
children: [
|
|
202
|
+
children: [U ? /* @__PURE__ */ C(g, {
|
|
224
203
|
className: "size-3 animate-spin",
|
|
225
204
|
"aria-hidden": "true"
|
|
226
|
-
}) : /* @__PURE__ */
|
|
205
|
+
}) : /* @__PURE__ */ C(b, {
|
|
227
206
|
className: "size-3",
|
|
228
207
|
"aria-hidden": "true"
|
|
229
|
-
}),
|
|
208
|
+
}), k("agentDetails.unlinkApp", "Unlink App")]
|
|
230
209
|
})
|
|
231
210
|
]
|
|
232
211
|
})
|
|
233
|
-
] }) : /* @__PURE__ */ S
|
|
212
|
+
] }) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ w("div", {
|
|
234
213
|
className: "flex items-start gap-3",
|
|
235
|
-
children: [/* @__PURE__ */
|
|
214
|
+
children: [/* @__PURE__ */ C("div", {
|
|
236
215
|
className: "size-8 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0 mt-0.5",
|
|
237
|
-
children: /* @__PURE__ */
|
|
216
|
+
children: /* @__PURE__ */ C(y, {
|
|
238
217
|
className: "size-4 text-text-muted",
|
|
239
218
|
"aria-hidden": "true"
|
|
240
219
|
})
|
|
241
|
-
}), /* @__PURE__ */
|
|
220
|
+
}), /* @__PURE__ */ w("div", {
|
|
242
221
|
className: "flex-1 min-w-0",
|
|
243
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: [/* @__PURE__ */ C("p", {
|
|
244
223
|
className: "text-sm font-medium text-text-primary",
|
|
245
|
-
children:
|
|
246
|
-
}), /* @__PURE__ */
|
|
224
|
+
children: k("agentDetails.noOauthAppLinked", "No OAuth App Linked")
|
|
225
|
+
}), /* @__PURE__ */ C("p", {
|
|
247
226
|
className: "text-xs text-text-muted mt-0.5",
|
|
248
|
-
children:
|
|
227
|
+
children: k("agentDetails.gatewayAuthSetupDescription", "Set up gateway auth to allow this agent to communicate with the API gateways using OAuth2 Client Credentials. This creates an OAuth app, registers it in the Developer Portal, and pushes the credentials to the agent.")
|
|
249
228
|
})]
|
|
250
229
|
})]
|
|
251
|
-
}), /* @__PURE__ */
|
|
230
|
+
}), /* @__PURE__ */ C(T, {
|
|
252
231
|
type: "button",
|
|
253
|
-
onClick: () => void
|
|
254
|
-
disabled:
|
|
255
|
-
"aria-busy":
|
|
256
|
-
children:
|
|
232
|
+
onClick: () => void Z(),
|
|
233
|
+
disabled: P,
|
|
234
|
+
"aria-busy": P,
|
|
235
|
+
children: P ? /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(g, {
|
|
257
236
|
className: "size-4 animate-spin",
|
|
258
237
|
"aria-hidden": "true"
|
|
259
|
-
}),
|
|
238
|
+
}), k("agentDetails.settingUp", "Setting up...")] }) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(h, {
|
|
260
239
|
className: "size-4",
|
|
261
240
|
"aria-hidden": "true"
|
|
262
|
-
}),
|
|
241
|
+
}), k("agentDetails.setupGatewayAuth", "Setup Gateway Auth")] })
|
|
263
242
|
})] })]
|
|
264
243
|
}),
|
|
265
|
-
/* @__PURE__ */
|
|
266
|
-
isOpen:
|
|
244
|
+
/* @__PURE__ */ C(d, {
|
|
245
|
+
isOpen: q,
|
|
246
|
+
onClose: () => {
|
|
247
|
+
P || J(!1);
|
|
248
|
+
},
|
|
249
|
+
onConfirm: () => {
|
|
250
|
+
Z().finally(() => J(!1));
|
|
251
|
+
},
|
|
252
|
+
agentName: D.name,
|
|
253
|
+
isLoading: P
|
|
254
|
+
}),
|
|
255
|
+
/* @__PURE__ */ C(n, {
|
|
256
|
+
isOpen: G,
|
|
267
257
|
onClose: () => {
|
|
268
|
-
|
|
258
|
+
U || K(!1);
|
|
269
259
|
},
|
|
270
|
-
onConfirm: () => void
|
|
271
|
-
title:
|
|
272
|
-
message:
|
|
273
|
-
confirmLabel:
|
|
260
|
+
onConfirm: () => void Q(),
|
|
261
|
+
title: k("agentDetails.unlinkApp", "Unlink App"),
|
|
262
|
+
message: k("agentDetails.confirmUnlinkOauthApp", "Remove the linked OAuth app from this agent? The app will still exist in auth-svc."),
|
|
263
|
+
confirmLabel: k("agentDetails.unlinkApp", "Unlink App"),
|
|
274
264
|
variant: "danger",
|
|
275
|
-
isLoading:
|
|
265
|
+
isLoading: U
|
|
276
266
|
})
|
|
277
267
|
]
|
|
278
268
|
});
|
|
279
269
|
}
|
|
280
270
|
//#endregion
|
|
281
|
-
export {
|
|
271
|
+
export { D as GatewayAuthCard };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { isNative as t, nativeCopyText as n, nativeToast as r } from "../../utils/nativeBridge.js";
|
|
3
|
+
import { notify as i } from "../../lib/toast.js";
|
|
4
|
+
import { useEffect as a, useRef as o, useState as s } from "react";
|
|
5
|
+
import { Check as c, Copy as l, Eye as u, EyeOff as d } from "lucide-react";
|
|
6
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
7
|
+
import { Button as m } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
//#region src/components/agents/OneTimeSecretPanel.tsx
|
|
9
|
+
function h({ secret: h, description: g, onDismiss: _ }) {
|
|
10
|
+
let v = e(), [y, b] = s(!1), [x, S] = s(!1), C = o(void 0);
|
|
11
|
+
a(() => () => clearTimeout(C.current), []);
|
|
12
|
+
let w = async () => {
|
|
13
|
+
if (!await n(h).catch(() => !1)) {
|
|
14
|
+
i.error(v("agentDetails.copyClientSecretFailed", "The secret could not be copied. Show it and copy it by hand: it will not be shown again."));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
t() && r("Secret copied"), S(!0), clearTimeout(C.current), C.current = setTimeout(() => S(!1), 2e3);
|
|
18
|
+
};
|
|
19
|
+
return /* @__PURE__ */ p("div", {
|
|
20
|
+
"data-testid": "one-time-secret-panel",
|
|
21
|
+
className: "p-3 bg-status-warning-bg-subtle border border-status-warning-border rounded-card space-y-2",
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ f("p", {
|
|
24
|
+
className: "text-sm font-medium text-status-warning-text",
|
|
25
|
+
children: v("agentDetails.clientSecretOneTimeTitle", "Client Secret (one-time display)")
|
|
26
|
+
}),
|
|
27
|
+
/* @__PURE__ */ f("p", {
|
|
28
|
+
className: "text-xs text-text-secondary",
|
|
29
|
+
children: g ?? v("agentDetails.clientSecretOneTimeDescription", "This secret has been automatically sent to the agent. Save it now if you need it — it won't be shown again.")
|
|
30
|
+
}),
|
|
31
|
+
/* @__PURE__ */ p("div", {
|
|
32
|
+
className: "flex items-center gap-2",
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ f("code", {
|
|
35
|
+
"data-testid": "one-time-secret-value",
|
|
36
|
+
className: "text-xs font-mono text-text-primary bg-bg-sunken px-2 py-1 rounded flex-1 min-w-0 truncate",
|
|
37
|
+
children: y ? h : "•".repeat(32)
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ f("button", {
|
|
40
|
+
type: "button",
|
|
41
|
+
onClick: () => b(!y),
|
|
42
|
+
"aria-label": y ? v("agentDetails.hideClientSecret", "Hide client secret") : v("agentDetails.showClientSecret", "Show client secret"),
|
|
43
|
+
className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
44
|
+
children: f(y ? d : u, {
|
|
45
|
+
className: "size-3.5 text-text-secondary",
|
|
46
|
+
"aria-hidden": "true"
|
|
47
|
+
})
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ f("button", {
|
|
50
|
+
type: "button",
|
|
51
|
+
onClick: () => void w(),
|
|
52
|
+
"aria-label": v("agentDetails.copyClientSecret", "Copy client secret"),
|
|
53
|
+
className: "p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
54
|
+
children: x ? /* @__PURE__ */ f(c, {
|
|
55
|
+
className: "size-3.5 text-status-success-text",
|
|
56
|
+
"aria-hidden": "true"
|
|
57
|
+
}) : /* @__PURE__ */ f(l, {
|
|
58
|
+
className: "size-3.5 text-text-secondary",
|
|
59
|
+
"aria-hidden": "true"
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
}),
|
|
64
|
+
_ && /* @__PURE__ */ f("div", {
|
|
65
|
+
className: "flex justify-end",
|
|
66
|
+
children: /* @__PURE__ */ f(m, {
|
|
67
|
+
type: "button",
|
|
68
|
+
size: "sm",
|
|
69
|
+
variant: "ghost",
|
|
70
|
+
"data-testid": "one-time-secret-dismiss",
|
|
71
|
+
onClick: _,
|
|
72
|
+
children: v("agentDetails.dismissSecret", "Dismiss")
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
]
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { h as OneTimeSecretPanel };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { ConfirmDialog as t } from "../shared/ConfirmDialog.js";
|
|
3
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/agents/RepairGatewayAuthDialog.tsx
|
|
5
|
+
function r({ isOpen: r, onClose: i, onConfirm: a, agentName: o, isLoading: s = !1 }) {
|
|
6
|
+
let c = e();
|
|
7
|
+
return /* @__PURE__ */ n(t, {
|
|
8
|
+
isOpen: r,
|
|
9
|
+
onClose: i,
|
|
10
|
+
onConfirm: a,
|
|
11
|
+
title: c("agentDetails.repairGatewayAuthTitle", "Repair gateway auth?"),
|
|
12
|
+
message: c("agentDetails.repairGatewayAuthMessage", "This rotates the OAuth secret of \"{{name}}\" and pushes a new one to the agent. The current secret stops working immediately, and the OAuth app is re-attributed to you. Only continue if the agent reports that it is waiting for its credentials.", { name: o }),
|
|
13
|
+
confirmLabel: c("agentDetails.repairGatewayAuthConfirm", "Rotate and push"),
|
|
14
|
+
variant: "warning",
|
|
15
|
+
isLoading: s
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { r as RepairGatewayAuthDialog };
|
|
@@ -4,8 +4,11 @@ import "./RemoteTaskPermissionsCard.js";
|
|
|
4
4
|
import "./AgentVisibilityCard.js";
|
|
5
5
|
import "./AgentList.js";
|
|
6
6
|
import "./AgentForm.js";
|
|
7
|
+
import "./OneTimeSecretPanel.js";
|
|
8
|
+
import "./RepairGatewayAuthDialog.js";
|
|
7
9
|
import "./GatewayAuthCard.js";
|
|
8
10
|
import "./ConfigureAgentDialog.js";
|
|
11
|
+
import "./CheckSessionHealthDialog.js";
|
|
9
12
|
import "./CreateSessionDialog.js";
|
|
10
13
|
import "./PluginUIPanel.js";
|
|
11
14
|
import "./OpenInBrowserEditorButton.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useSetupAgentGatewayAuthMutation as e } from "../generated/wspace-operations.js";
|
|
2
|
+
import { useCallback as t, useSyncExternalStore as n } from "react";
|
|
3
|
+
//#region src/hooks/useRepairGatewayAuth.ts
|
|
4
|
+
var r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set();
|
|
5
|
+
function o() {
|
|
6
|
+
for (let e of a) e();
|
|
7
|
+
}
|
|
8
|
+
function s(e) {
|
|
9
|
+
let t = (i.get(e) ?? 0) + 1;
|
|
10
|
+
return i.set(e, t), o(), t;
|
|
11
|
+
}
|
|
12
|
+
function c(e) {
|
|
13
|
+
return a.add(e), () => {
|
|
14
|
+
a.delete(e);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function l(a) {
|
|
18
|
+
let [l] = e(), u = n(c, () => a ? r.has(a) : !1, () => !1), d = n(c, () => a ? i.get(a) ?? 0 : 0, () => 0);
|
|
19
|
+
return {
|
|
20
|
+
repair: t(async () => {
|
|
21
|
+
if (!a) return {
|
|
22
|
+
status: "failed",
|
|
23
|
+
message: "No agent"
|
|
24
|
+
};
|
|
25
|
+
if (r.has(a)) return { status: "busy" };
|
|
26
|
+
r.add(a), o();
|
|
27
|
+
try {
|
|
28
|
+
let { data: e, error: t } = await l({ variables: { input: { agentId: a } } }), n = e?.setupAgentGatewayAuth;
|
|
29
|
+
return n ? n.error ? n.clientSecret ? {
|
|
30
|
+
status: "delivery-failed",
|
|
31
|
+
clientSecret: n.clientSecret,
|
|
32
|
+
error: n.error,
|
|
33
|
+
epoch: s(a)
|
|
34
|
+
} : {
|
|
35
|
+
status: "failed",
|
|
36
|
+
message: n.error
|
|
37
|
+
} : n.clientSecret ? {
|
|
38
|
+
status: "ok",
|
|
39
|
+
clientSecret: n.clientSecret,
|
|
40
|
+
epoch: s(a)
|
|
41
|
+
} : { status: "unchanged" } : {
|
|
42
|
+
status: "failed",
|
|
43
|
+
message: t?.message || "No result returned from setupAgentGatewayAuth"
|
|
44
|
+
};
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return {
|
|
47
|
+
status: "failed",
|
|
48
|
+
message: e instanceof Error ? e.message : String(e)
|
|
49
|
+
};
|
|
50
|
+
} finally {
|
|
51
|
+
r.delete(a), o();
|
|
52
|
+
}
|
|
53
|
+
}, [a, l]),
|
|
54
|
+
running: u,
|
|
55
|
+
rotationEpoch: d
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { l as useRepairGatewayAuth };
|