@burdenoff/microfe-devportal 2026.1112.1 → 2026.1112.2
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/devportal/pages/CreateOrganizationPage.js +120 -114
- package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
- package/dist/devportal/pages/EditApplicationPage.js +84 -73
- package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientDetailPage.js +134 -115
- package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
- package/dist/devportal/pages/SetupPage.js +141 -143
- package/dist/devportal/pages/SetupPage.js.map +1 -1
- package/dist/devportal/utils/errorMessage.d.ts +2 -0
- package/dist/devportal/utils/errorMessage.js +7 -0
- package/dist/devportal/utils/errorMessage.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,228 +1,247 @@
|
|
|
1
1
|
import { PageLayout as e } from "../components/PageLayout.js";
|
|
2
2
|
import { ActiveIndicator as t } from "../components/StatusBadge.js";
|
|
3
|
-
import { useDeactivateAppMutation as n, useGetAuthAppQuery as
|
|
4
|
-
import { getErrorMessage as
|
|
5
|
-
import { useDevportal as o } from "../providers/DevportalProvider.js";
|
|
3
|
+
import { useDeactivateAppMutation as n, useGetAuthAppQuery as ee, useRotateAppSecretMutation as r, useUpdateAuthAppMutation as i } from "../../generated/global-operations.js";
|
|
4
|
+
import { getErrorMessage as a } from "../hooks/useGraphQL.js";
|
|
5
|
+
import { useDevportal as o, useIsFluidgridsVariant as te } from "../providers/DevportalProvider.js";
|
|
6
|
+
import { errorMessage as s } from "../utils/errorMessage.js";
|
|
6
7
|
import "../components/index.js";
|
|
7
|
-
import { cn as te } from "../utils/cn.js";
|
|
8
8
|
import { PermissionGuard as ne } from "../components/PermissionGuard.js";
|
|
9
|
-
import {
|
|
9
|
+
import { cn as re } from "../utils/cn.js";
|
|
10
|
+
import { nativeCopyText as ie, nativeImpact as ae, nativeNotify as c } from "../../utils/nativeBridge.js";
|
|
10
11
|
import "../hooks/index.js";
|
|
11
12
|
import { useState as l } from "react";
|
|
12
|
-
import { AlertCircle as
|
|
13
|
-
import { useParams as
|
|
14
|
-
import { jsx as
|
|
15
|
-
import { useI18n as
|
|
13
|
+
import { AlertCircle as u, ArrowLeft as d, Copy as f, Eye as p, EyeOff as m, Loader2 as h, RefreshCw as g, Trash2 as oe } from "lucide-react";
|
|
14
|
+
import { useParams as _ } from "react-router";
|
|
15
|
+
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
16
|
+
import { useI18n as se } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
16
17
|
import { AlertDialog as b, AlertDialogAction as x, AlertDialogCancel as S, AlertDialogContent as C, AlertDialogDescription as w, AlertDialogFooter as T, AlertDialogHeader as E, AlertDialogTitle as D, CTAOverflowMenu as O, GlassCard as k } from "@burdenoff/fe-libs/ui";
|
|
17
18
|
// src/devportal/pages/OAuthClientDetailPage.tsx
|
|
18
19
|
var A = () => {
|
|
19
|
-
let { clientId: A } =
|
|
20
|
+
let { clientId: A } = _(), { navigate: j, basePath: M } = o(), { t: N } = se(), P = (e, t) => {
|
|
20
21
|
let n = N(e);
|
|
21
22
|
return n === e ? t : n;
|
|
22
|
-
}, [F, I] = l(!1), [L, R] = l(null), [z, B] = l(!1), [V, H] = l(!1), { data:
|
|
23
|
+
}, [F, I] = l(!1), [L, R] = l(null), [z, B] = l(!1), [V, H] = l(!1), [U, W] = l(null), G = te(), { data: K, loading: ce, error: q, refetch: J } = ee({
|
|
23
24
|
variables: { id: A || "" },
|
|
24
25
|
skip: !A,
|
|
25
26
|
fetchPolicy: "cache-and-network"
|
|
26
|
-
}), [
|
|
27
|
-
id:
|
|
28
|
-
name:
|
|
29
|
-
description:
|
|
30
|
-
clientId:
|
|
31
|
-
type:
|
|
32
|
-
status:
|
|
33
|
-
scopes:
|
|
34
|
-
redirectUris:
|
|
35
|
-
ownerUserId:
|
|
36
|
-
tenantId:
|
|
37
|
-
createdAt:
|
|
38
|
-
updatedAt:
|
|
27
|
+
}), [le, { loading: Y }] = r(), [ue, { loading: X }] = n(), [de] = i(), Z = K?.app ? {
|
|
28
|
+
id: K.app.id,
|
|
29
|
+
name: K.app.name,
|
|
30
|
+
description: K.app.description ?? void 0,
|
|
31
|
+
clientId: K.app.clientId,
|
|
32
|
+
type: K.app.type,
|
|
33
|
+
status: K.app.status,
|
|
34
|
+
scopes: K.app.scopes ?? [],
|
|
35
|
+
redirectUris: K.app.redirectUris ?? [],
|
|
36
|
+
ownerUserId: K.app.ownerUserId,
|
|
37
|
+
tenantId: K.app.tenantId,
|
|
38
|
+
createdAt: K.app.createdAt,
|
|
39
|
+
updatedAt: K.app.updatedAt
|
|
39
40
|
} : null, Q = (e) => {
|
|
40
41
|
j?.(`${M}${e}`);
|
|
41
42
|
}, $ = async (e) => {
|
|
42
|
-
|
|
43
|
-
let t = await
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
if (A)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
ae("light");
|
|
44
|
+
let t = await ie(e);
|
|
45
|
+
c(t ? "success" : "error");
|
|
46
|
+
}, fe = async () => {
|
|
47
|
+
if (A) {
|
|
48
|
+
W(null);
|
|
49
|
+
try {
|
|
50
|
+
let e = (await le({ variables: { id: A } })).data?.rotateAppSecret?.clientSecret;
|
|
51
|
+
e && (R(e), I(!0)), H(!1), J();
|
|
52
|
+
} catch (e) {
|
|
53
|
+
W(s(e, P("devportal.oauthActionFailed", "That did not work. Nothing was changed. Please try again.")));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, pe = async () => {
|
|
57
|
+
if (A) {
|
|
58
|
+
W(null);
|
|
59
|
+
try {
|
|
60
|
+
await ue({ variables: { id: A } }), B(!1), Q("/oauth");
|
|
61
|
+
} catch (e) {
|
|
62
|
+
W(s(e, P("devportal.oauthActionFailed", "That did not work. Nothing was changed. Please try again.")));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
54
65
|
};
|
|
55
|
-
return
|
|
66
|
+
return ce && !K ? /* @__PURE__ */ v(e, {
|
|
56
67
|
title: P("devportal.appDetails", "App Details"),
|
|
57
68
|
description: P("devportal.loadingDots", "Loading..."),
|
|
58
69
|
backLink: "/oauth",
|
|
59
70
|
backLabel: P("devportal.backToApps", "Back to Apps"),
|
|
60
|
-
children: /* @__PURE__ */
|
|
71
|
+
children: /* @__PURE__ */ v("div", {
|
|
61
72
|
className: "flex items-center justify-center py-12",
|
|
62
|
-
children: /* @__PURE__ */
|
|
73
|
+
children: /* @__PURE__ */ v(h, { className: "h-8 w-8 animate-spin text-text-secondary" })
|
|
63
74
|
})
|
|
64
|
-
}) :
|
|
75
|
+
}) : q || !Z ? /* @__PURE__ */ v(e, {
|
|
65
76
|
title: P("devportal.appDetails", "App Details"),
|
|
66
77
|
description: P("devportal.failedToLoad", "Failed to load"),
|
|
67
78
|
backLink: "/oauth",
|
|
68
79
|
backLabel: P("devportal.backToApps", "Back to Apps"),
|
|
69
|
-
children: /* @__PURE__ */
|
|
80
|
+
children: /* @__PURE__ */ y("div", {
|
|
70
81
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
71
82
|
children: [
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
/* @__PURE__ */
|
|
83
|
+
/* @__PURE__ */ v(u, { className: "mx-auto h-8 w-8 text-status-error-text" }),
|
|
84
|
+
/* @__PURE__ */ v("h3", {
|
|
74
85
|
className: "mt-2 font-medium text-status-error-text",
|
|
75
|
-
children:
|
|
86
|
+
children: q ? P("devportal.failedToLoadApp", "Failed to load app") : P("devportal.appNotFound", "App not found")
|
|
76
87
|
}),
|
|
77
|
-
|
|
88
|
+
q && /* @__PURE__ */ v("p", {
|
|
78
89
|
className: "mt-1 text-sm text-text-secondary",
|
|
79
|
-
children:
|
|
90
|
+
children: a(q)
|
|
80
91
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ y("button", {
|
|
82
93
|
onClick: () => Q("/oauth"),
|
|
83
94
|
className: "mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
84
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ v(d, { size: 16 }), P("devportal.backToApps", "Back to Apps")]
|
|
85
96
|
})
|
|
86
97
|
]
|
|
87
98
|
})
|
|
88
|
-
}) : /* @__PURE__ */
|
|
99
|
+
}) : /* @__PURE__ */ v(ne, {
|
|
89
100
|
authOnly: !0,
|
|
90
|
-
children: /* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ y(e, {
|
|
91
102
|
title: Z.name,
|
|
92
103
|
description: Z.description || P("devportal.oauthAppDetailsAndCredentials", "OAuth App details and credentials"),
|
|
93
104
|
purpose: P("devportal.oauthAppDetailPurpose", "These are this OAuth app's credentials and the scopes it may request. Copy the client ID for your integration, rotate the secret if it leaks, and keep scopes minimal so users only grant what the app truly needs."),
|
|
94
105
|
backLink: "/oauth",
|
|
95
106
|
backLabel: P("devportal.backToApps", "Back to Apps"),
|
|
96
|
-
actions: /* @__PURE__ */
|
|
107
|
+
actions: /* @__PURE__ */ v(O, {
|
|
97
108
|
primary: {
|
|
98
109
|
label: Z.status === "ACTIVE" ? P("devportal.deactivate", "Deactivate") : P("devportal.activate", "Activate"),
|
|
99
110
|
onSelect: async () => {
|
|
100
111
|
if (!A || !Z) return;
|
|
112
|
+
W(null);
|
|
101
113
|
let e = Z.status === "ACTIVE" ? "INACTIVE" : "ACTIVE";
|
|
102
114
|
try {
|
|
103
|
-
await
|
|
115
|
+
await de({ variables: {
|
|
104
116
|
id: A,
|
|
105
117
|
input: { status: e }
|
|
106
|
-
} }),
|
|
107
|
-
} catch {
|
|
118
|
+
} }), J();
|
|
119
|
+
} catch (e) {
|
|
120
|
+
W(s(e, P("devportal.oauthActionFailed", "That did not work. Nothing was changed. Please try again.")));
|
|
121
|
+
}
|
|
108
122
|
}
|
|
109
123
|
},
|
|
110
124
|
actions: [{
|
|
111
|
-
label: P("devportal.delete", "Delete"),
|
|
112
|
-
icon: /* @__PURE__ */
|
|
125
|
+
label: G ? P("devportal.deactivate", "Deactivate") : P("devportal.delete", "Delete"),
|
|
126
|
+
icon: /* @__PURE__ */ v(oe, { size: 16 }),
|
|
113
127
|
intent: "destructive",
|
|
114
128
|
onSelect: () => B(!0)
|
|
115
129
|
}]
|
|
116
130
|
}),
|
|
117
131
|
children: [
|
|
118
|
-
/* @__PURE__ */ v("div", {
|
|
132
|
+
U && /* @__PURE__ */ v("div", {
|
|
133
|
+
role: "alert",
|
|
134
|
+
className: "mb-4 rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-text",
|
|
135
|
+
children: U
|
|
136
|
+
}),
|
|
137
|
+
/* @__PURE__ */ y("div", {
|
|
119
138
|
className: "grid gap-6 md:grid-cols-2",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ y("div", {
|
|
121
140
|
className: "rounded-card border border-border-seam bg-bg-surface p-6",
|
|
122
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
123
142
|
className: "text-sm font-medium text-text-secondary mb-4",
|
|
124
143
|
children: P("devportal.statusAndConfiguration", "Status & Configuration")
|
|
125
|
-
}), /* @__PURE__ */
|
|
144
|
+
}), /* @__PURE__ */ y("div", {
|
|
126
145
|
className: "space-y-3",
|
|
127
146
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ y("div", {
|
|
129
148
|
className: "flex justify-between",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ v("span", {
|
|
131
150
|
className: "text-sm text-text-secondary",
|
|
132
151
|
children: P("devportal.status", "Status")
|
|
133
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ y("div", {
|
|
134
153
|
className: "flex items-center gap-2",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ v(t, { active: Z.status === "ACTIVE" }), /* @__PURE__ */ v("span", {
|
|
136
155
|
className: "text-sm font-medium",
|
|
137
156
|
children: Z.status
|
|
138
157
|
})]
|
|
139
158
|
})]
|
|
140
159
|
}),
|
|
141
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ y("div", {
|
|
142
161
|
className: "flex justify-between",
|
|
143
|
-
children: [/* @__PURE__ */
|
|
162
|
+
children: [/* @__PURE__ */ v("span", {
|
|
144
163
|
className: "text-sm text-text-secondary",
|
|
145
164
|
children: P("devportal.type", "Type")
|
|
146
|
-
}), /* @__PURE__ */
|
|
147
|
-
className:
|
|
165
|
+
}), /* @__PURE__ */ v("span", {
|
|
166
|
+
className: re("rounded px-2 py-0.5 text-xs font-medium", Z.type === "SERVICE" ? "bg-accent-purple-subtle text-accent-purple" : Z.type === "INTEGRATION" || Z.type === "API_INTEGRATION" ? "bg-status-info-bg-subtle text-status-info-text" : "bg-status-success-bg-subtle text-status-success-text"),
|
|
148
167
|
children: Z.type
|
|
149
168
|
})]
|
|
150
169
|
}),
|
|
151
|
-
/* @__PURE__ */
|
|
170
|
+
/* @__PURE__ */ y("div", {
|
|
152
171
|
className: "flex justify-between",
|
|
153
|
-
children: [/* @__PURE__ */
|
|
172
|
+
children: [/* @__PURE__ */ v("span", {
|
|
154
173
|
className: "text-sm text-text-secondary",
|
|
155
174
|
children: P("devportal.created", "Created")
|
|
156
|
-
}), /* @__PURE__ */
|
|
175
|
+
}), /* @__PURE__ */ v("span", {
|
|
157
176
|
className: "text-sm",
|
|
158
177
|
children: new Date(Z.createdAt).toLocaleDateString()
|
|
159
178
|
})]
|
|
160
179
|
})
|
|
161
180
|
]
|
|
162
181
|
})]
|
|
163
|
-
}), /* @__PURE__ */
|
|
182
|
+
}), /* @__PURE__ */ y(k, {
|
|
164
183
|
treatment: "glass",
|
|
165
184
|
glow: !0,
|
|
166
185
|
className: "p-6",
|
|
167
|
-
children: [/* @__PURE__ */
|
|
186
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
168
187
|
className: "text-sm font-medium text-text-secondary mb-4",
|
|
169
188
|
children: P("devportal.credentials", "Credentials")
|
|
170
|
-
}), /* @__PURE__ */
|
|
189
|
+
}), /* @__PURE__ */ y("div", {
|
|
171
190
|
className: "space-y-3",
|
|
172
191
|
children: [
|
|
173
|
-
/* @__PURE__ */
|
|
192
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
174
193
|
className: "text-xs text-text-secondary",
|
|
175
194
|
children: P("devportal.clientId", "Client ID")
|
|
176
|
-
}), /* @__PURE__ */
|
|
195
|
+
}), /* @__PURE__ */ y("div", {
|
|
177
196
|
className: "mt-1 flex items-center gap-2",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
197
|
+
children: [/* @__PURE__ */ v("code", {
|
|
179
198
|
className: "flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono",
|
|
180
199
|
children: Z.clientId
|
|
181
|
-
}), /* @__PURE__ */
|
|
200
|
+
}), /* @__PURE__ */ v("button", {
|
|
182
201
|
onClick: () => $(Z.clientId),
|
|
183
202
|
className: "rounded p-1.5 hover:bg-bg-sunken transition-colors",
|
|
184
203
|
title: "Copy",
|
|
185
|
-
children: /* @__PURE__ */
|
|
204
|
+
children: /* @__PURE__ */ v(f, { size: 14 })
|
|
186
205
|
})]
|
|
187
206
|
})] }),
|
|
188
|
-
L && /* @__PURE__ */
|
|
207
|
+
L && /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
189
208
|
className: "text-xs text-status-error-text font-medium",
|
|
190
209
|
children: P("devportal.newClientSecretShownOnce", "New Client Secret (shown only once!)")
|
|
191
|
-
}), /* @__PURE__ */
|
|
210
|
+
}), /* @__PURE__ */ y("div", {
|
|
192
211
|
className: "mt-1 flex items-center gap-2",
|
|
193
212
|
children: [
|
|
194
|
-
/* @__PURE__ */
|
|
213
|
+
/* @__PURE__ */ v("code", {
|
|
195
214
|
className: "flex-1 rounded bg-status-error-bg/10 border border-status-error-border/30 px-3 py-1.5 text-sm font-mono",
|
|
196
215
|
children: F ? L : "••••••••••••••••"
|
|
197
216
|
}),
|
|
198
|
-
/* @__PURE__ */
|
|
217
|
+
/* @__PURE__ */ v("button", {
|
|
199
218
|
onClick: () => I(!F),
|
|
200
219
|
className: "rounded p-1.5 hover:bg-bg-sunken transition-colors",
|
|
201
|
-
children:
|
|
220
|
+
children: v(F ? m : p, { size: 14 })
|
|
202
221
|
}),
|
|
203
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ v("button", {
|
|
204
223
|
onClick: () => $(L),
|
|
205
224
|
className: "rounded p-1.5 hover:bg-bg-sunken transition-colors",
|
|
206
|
-
children: /* @__PURE__ */
|
|
225
|
+
children: /* @__PURE__ */ v(f, { size: 14 })
|
|
207
226
|
})
|
|
208
227
|
]
|
|
209
228
|
})] }),
|
|
210
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ y("button", {
|
|
211
230
|
onClick: () => H(!0),
|
|
212
|
-
disabled:
|
|
231
|
+
disabled: Y,
|
|
213
232
|
className: "mt-2 inline-flex items-center gap-2 rounded-md bg-status-warning-bg-subtle px-3 py-1.5 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle transition-colors disabled:opacity-50",
|
|
214
|
-
children: [/* @__PURE__ */
|
|
233
|
+
children: [/* @__PURE__ */ v(g, {
|
|
215
234
|
size: 14,
|
|
216
|
-
className:
|
|
235
|
+
className: Y ? "animate-spin" : ""
|
|
217
236
|
}), P("devportal.rotateSecret", "Rotate Secret")]
|
|
218
237
|
})
|
|
219
238
|
]
|
|
220
239
|
})]
|
|
221
240
|
})]
|
|
222
241
|
}),
|
|
223
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ y("div", {
|
|
224
243
|
className: "rounded-card border border-border-seam bg-bg-surface p-6",
|
|
225
|
-
children: [/* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
226
245
|
className: "text-sm font-medium text-text-secondary mb-3",
|
|
227
246
|
children: [
|
|
228
247
|
P("devportal.scopes", "Scopes"),
|
|
@@ -230,20 +249,20 @@ var A = () => {
|
|
|
230
249
|
Z.scopes.length,
|
|
231
250
|
")"
|
|
232
251
|
]
|
|
233
|
-
}), Z.scopes.length > 0 ? /* @__PURE__ */
|
|
252
|
+
}), Z.scopes.length > 0 ? /* @__PURE__ */ v("div", {
|
|
234
253
|
className: "flex flex-wrap gap-2",
|
|
235
|
-
children: Z.scopes.map((e) => /* @__PURE__ */
|
|
254
|
+
children: Z.scopes.map((e) => /* @__PURE__ */ v("span", {
|
|
236
255
|
className: "rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary",
|
|
237
256
|
children: e
|
|
238
257
|
}, e))
|
|
239
|
-
}) : /* @__PURE__ */
|
|
258
|
+
}) : /* @__PURE__ */ v("p", {
|
|
240
259
|
className: "text-sm text-text-secondary",
|
|
241
260
|
children: P("devportal.noScopesConfigured", "No scopes configured")
|
|
242
261
|
})]
|
|
243
262
|
}),
|
|
244
|
-
/* @__PURE__ */
|
|
263
|
+
/* @__PURE__ */ y("div", {
|
|
245
264
|
className: "rounded-card border border-border-seam bg-bg-surface p-6",
|
|
246
|
-
children: [/* @__PURE__ */
|
|
265
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
247
266
|
className: "text-sm font-medium text-text-secondary mb-3",
|
|
248
267
|
children: [
|
|
249
268
|
P("devportal.redirectUris", "Redirect URIs"),
|
|
@@ -251,51 +270,51 @@ var A = () => {
|
|
|
251
270
|
Z.redirectUris.length,
|
|
252
271
|
")"
|
|
253
272
|
]
|
|
254
|
-
}), Z.redirectUris.length > 0 ? /* @__PURE__ */
|
|
273
|
+
}), Z.redirectUris.length > 0 ? /* @__PURE__ */ v("div", {
|
|
255
274
|
className: "space-y-2",
|
|
256
|
-
children: Z.redirectUris.map((e) => /* @__PURE__ */
|
|
275
|
+
children: Z.redirectUris.map((e) => /* @__PURE__ */ y("div", {
|
|
257
276
|
className: "flex items-center gap-2",
|
|
258
|
-
children: [/* @__PURE__ */
|
|
277
|
+
children: [/* @__PURE__ */ v("code", {
|
|
259
278
|
className: "rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono",
|
|
260
279
|
children: e
|
|
261
|
-
}), /* @__PURE__ */
|
|
280
|
+
}), /* @__PURE__ */ v("button", {
|
|
262
281
|
onClick: () => $(e),
|
|
263
282
|
className: "rounded p-1 hover:bg-bg-sunken transition-colors",
|
|
264
|
-
children: /* @__PURE__ */
|
|
283
|
+
children: /* @__PURE__ */ v(f, { size: 12 })
|
|
265
284
|
})]
|
|
266
285
|
}, e))
|
|
267
|
-
}) : /* @__PURE__ */
|
|
286
|
+
}) : /* @__PURE__ */ v("p", {
|
|
268
287
|
className: "text-sm text-text-secondary",
|
|
269
288
|
children: P("devportal.noRedirectUrisConfigured", "No redirect URIs configured")
|
|
270
289
|
})]
|
|
271
290
|
}),
|
|
272
|
-
/* @__PURE__ */
|
|
291
|
+
/* @__PURE__ */ v(b, {
|
|
273
292
|
open: V,
|
|
274
293
|
onOpenChange: H,
|
|
275
|
-
children: /* @__PURE__ */
|
|
276
|
-
disabled:
|
|
294
|
+
children: /* @__PURE__ */ y(C, { children: [/* @__PURE__ */ y(E, { children: [/* @__PURE__ */ v(D, { children: P("devportal.rotateClientSecretQuestion", "Rotate Client Secret?") }), /* @__PURE__ */ v(w, { children: P("devportal.rotateSecretWarning", "This will invalidate the current client secret. All integrations using the old secret will stop working immediately.") })] }), /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(S, {
|
|
295
|
+
disabled: Y,
|
|
277
296
|
children: P("devportal.cancel", "Cancel")
|
|
278
|
-
}), /* @__PURE__ */
|
|
297
|
+
}), /* @__PURE__ */ v(x, {
|
|
279
298
|
onClick: (e) => {
|
|
280
|
-
e.preventDefault(),
|
|
299
|
+
e.preventDefault(), fe();
|
|
281
300
|
},
|
|
282
|
-
disabled:
|
|
301
|
+
disabled: Y,
|
|
283
302
|
className: "bg-status-warning-bg text-white hover:bg-status-warning-bg/90",
|
|
284
|
-
children:
|
|
303
|
+
children: Y ? P("devportal.rotating", "Rotating...") : P("devportal.rotateSecret", "Rotate Secret")
|
|
285
304
|
})] })] })
|
|
286
305
|
}),
|
|
287
|
-
/* @__PURE__ */
|
|
306
|
+
/* @__PURE__ */ v(b, {
|
|
288
307
|
open: z,
|
|
289
308
|
onOpenChange: B,
|
|
290
|
-
children: /* @__PURE__ */
|
|
309
|
+
children: /* @__PURE__ */ y(C, { children: [/* @__PURE__ */ y(E, { children: [/* @__PURE__ */ v(D, {
|
|
291
310
|
className: "text-status-error-text",
|
|
292
311
|
children: P("devportal.deactivateAppQuestion", "Deactivate App?")
|
|
293
|
-
}), /* @__PURE__ */
|
|
312
|
+
}), /* @__PURE__ */ v(w, { children: P("devportal.deactivateAppWarning", "This will deactivate the app and revoke all tokens. This action cannot be undone easily.") })] }), /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(S, {
|
|
294
313
|
disabled: X,
|
|
295
314
|
children: P("devportal.cancel", "Cancel")
|
|
296
|
-
}), /* @__PURE__ */
|
|
315
|
+
}), /* @__PURE__ */ v(x, {
|
|
297
316
|
onClick: (e) => {
|
|
298
|
-
e.preventDefault(),
|
|
317
|
+
e.preventDefault(), pe();
|
|
299
318
|
},
|
|
300
319
|
disabled: X,
|
|
301
320
|
className: "bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OAuthClientDetailPage.js","names":["OAuthClientDetailPage","appId","useParams","useDevportal","useI18n","tr","value","t","key","fallback","showSecret","setShowSecret","useState","newSecret","setNewSecret","confirmDelete","setConfirmDelete","confirmRotate","setConfirmRotate","useGetAuthAppQuery","rotateSecret","rotating","useRotateAppSecretMutation","deactivateApp","deactivating","useDeactivateAppMutation","updateApp","useUpdateAuthAppMutation","app","data","handleNavigate","basePath","path","handleCopy","ok","nativeCopyText","text","handleRotateSecret","secret","refetch","handleDeactivate","loading","PageLayout","Loader2","error","AlertCircle","getErrorMessage","ArrowLeft","PermissionGuard","CTAOverflowMenu","newStatus","Trash2","ActiveIndicator","cn","GlassCard","Copy","jsx","EyeOff","Eye","RefreshCw","scope","uri","AlertDialog","AlertDialogContent","AlertDialogHeader","AlertDialogTitle","AlertDialogDescription","AlertDialogFooter","AlertDialogCancel","AlertDialogAction"],"sources":["../../../src/devportal/pages/OAuthClientDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Copy,\n Eye,\n EyeOff,\n Loader2,\n AlertCircle,\n RefreshCw,\n Trash2,\n ArrowLeft,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n CTAOverflowMenu,\n GlassCard,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useParams } from \"react-router\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { ActiveIndicator } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport type { AuthApp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport {\n useGetAuthAppQuery,\n useRotateAppSecretMutation,\n useDeactivateAppMutation,\n useUpdateAuthAppMutation,\n getErrorMessage,\n} from \"../hooks\";\n\n/**\n * OAuth App Detail page\n *\n * Shows details for an auth-svc App (replaces devportal-svc OAuthClient detail).\n * Supports secret rotation, deactivation, and status toggle.\n */\nexport const OAuthClientDetailPage: FC = () => {\n const { clientId: appId } = useParams<{ clientId: string }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [showSecret, setShowSecret] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [confirmRotate, setConfirmRotate] = useState(false);\n\n const { data, loading, error, refetch } = useGetAuthAppQuery({\n variables: { id: appId || \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const [rotateSecret, { loading: rotating }] = useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivating }] = useDeactivateAppMutation();\n const [updateApp] = useUpdateAuthAppMutation();\n\n const app: AuthApp | null = data?.app\n ? {\n id: data.app.id,\n name: data.app.name,\n description: data.app.description ?? undefined,\n clientId: data.app.clientId,\n type: data.app.type as AuthApp[\"type\"],\n status: data.app.status as AuthApp[\"status\"],\n scopes: data.app.scopes ?? [],\n redirectUris: data.app.redirectUris ?? [],\n ownerUserId: data.app.ownerUserId,\n tenantId: data.app.tenantId,\n createdAt: data.app.createdAt,\n updatedAt: data.app.updatedAt,\n }\n : null;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleCopy = async (text: string) => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n };\n\n const handleRotateSecret = async () => {\n if (!appId) return;\n try {\n const result = await rotateSecret({ variables: { id: appId } });\n const secret = result.data?.rotateAppSecret?.clientSecret;\n if (secret) {\n setNewSecret(secret);\n setShowSecret(true);\n }\n setConfirmRotate(false);\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleDeactivate = async () => {\n if (!appId) return;\n try {\n await deactivateApp({ variables: { id: appId } });\n setConfirmDelete(false);\n handleNavigate(\"/oauth\");\n } catch {\n // error handled by Apollo\n }\n };\n\n const handleToggleStatus = async () => {\n if (!appId || !app) return;\n const newStatus = app.status === \"ACTIVE\" ? \"INACTIVE\" : \"ACTIVE\";\n try {\n await updateApp({\n variables: { id: appId, input: { status: newStatus } },\n });\n refetch();\n } catch {\n // error handled by Apollo\n }\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.loadingDots\", \"Loading...\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.failedToLoad\", \"Failed to load\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {error\n ? tr(\"devportal.failedToLoadApp\", \"Failed to load app\")\n : tr(\"devportal.appNotFound\", \"App not found\")}\n </h3>\n {error && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <ArrowLeft size={16} />\n {tr(\"devportal.backToApps\", \"Back to Apps\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={app.name}\n description={\n app.description ||\n tr(\n \"devportal.oauthAppDetailsAndCredentials\",\n \"OAuth App details and credentials\",\n )\n }\n purpose={tr(\n \"devportal.oauthAppDetailPurpose\",\n \"These are this OAuth app's credentials and the scopes it may request. Copy the client ID for your integration, rotate the secret if it leaks, and keep scopes minimal so users only grant what the app truly needs.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n actions={\n <CTAOverflowMenu\n primary={{\n label:\n app.status === \"ACTIVE\"\n ? tr(\"devportal.deactivate\", \"Deactivate\")\n : tr(\"devportal.activate\", \"Activate\"),\n onSelect: handleToggleStatus,\n }}\n actions={[\n {\n label: tr(\"devportal.delete\", \"Delete\"),\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n onSelect: () => setConfirmDelete(true),\n },\n ]}\n />\n }\n >\n {/* Status & Type */}\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.statusAndConfiguration\", \"Status & Configuration\")}\n </h3>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </span>\n <div className=\"flex items-center gap-2\">\n <ActiveIndicator active={app.status === \"ACTIVE\"} />\n <span className=\"text-sm font-medium\">{app.status}</span>\n </div>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </span>\n <span\n className={cn(\n \"rounded px-2 py-0.5 text-xs font-medium\",\n app.type === \"SERVICE\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : app.type === \"INTEGRATION\" ||\n app.type === \"API_INTEGRATION\"\n ? \"bg-status-info-bg-subtle text-status-info-text\"\n : \"bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n {app.type}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </span>\n <span className=\"text-sm\">\n {new Date(app.createdAt).toLocaleDateString()}\n </span>\n </div>\n </div>\n </div>\n\n {/* Credentials — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.credentials\", \"Credentials\")}\n </h3>\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs text-text-secondary\">\n {tr(\"devportal.clientId\", \"Client ID\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {app.clientId}\n </code>\n <button\n onClick={() => handleCopy(app.clientId)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n title=\"Copy\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n {newSecret && (\n <div>\n <label className=\"text-xs text-status-error-text font-medium\">\n {tr(\n \"devportal.newClientSecretShownOnce\",\n \"New Client Secret (shown only once!)\",\n )}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-status-error-bg/10 border border-status-error-border/30 px-3 py-1.5 text-sm font-mono\">\n {showSecret\n ? newSecret\n : \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\"}\n </code>\n <button\n onClick={() => setShowSecret(!showSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n {showSecret ? <EyeOff size={14} /> : <Eye size={14} />}\n </button>\n <button\n onClick={() => handleCopy(newSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n )}\n <button\n onClick={() => setConfirmRotate(true)}\n disabled={rotating}\n className=\"mt-2 inline-flex items-center gap-2 rounded-md bg-status-warning-bg-subtle px-3 py-1.5 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle transition-colors disabled:opacity-50\"\n >\n <RefreshCw\n size={14}\n className={rotating ? \"animate-spin\" : \"\"}\n />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n </div>\n </GlassCard>\n </div>\n\n {/* Scopes */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.scopes\", \"Scopes\")} ({app.scopes.length})\n </h3>\n {app.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {app.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.noScopesConfigured\", \"No scopes configured\")}\n </p>\n )}\n </div>\n\n {/* Redirect URIs */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.redirectUris\", \"Redirect URIs\")} (\n {app.redirectUris.length})\n </h3>\n {app.redirectUris.length > 0 ? (\n <div className=\"space-y-2\">\n {app.redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n onClick={() => handleCopy(uri)}\n className=\"rounded p-1 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={12} />\n </button>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.noRedirectUrisConfigured\",\n \"No redirect URIs configured\",\n )}\n </p>\n )}\n </div>\n\n {/* Confirm Rotate Dialog */}\n <AlertDialog open={confirmRotate} onOpenChange={setConfirmRotate}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {tr(\n \"devportal.rotateClientSecretQuestion\",\n \"Rotate Client Secret?\",\n )}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.rotateSecretWarning\",\n \"This will invalidate the current client secret. All integrations using the old secret will stop working immediately.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={rotating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleRotateSecret();\n }}\n disabled={rotating}\n className=\"bg-status-warning-bg text-white hover:bg-status-warning-bg/90\"\n >\n {rotating\n ? tr(\"devportal.rotating\", \"Rotating...\")\n : tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Confirm Deactivate Dialog */}\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle className=\"text-status-error-text\">\n {tr(\"devportal.deactivateAppQuestion\", \"Deactivate App?\")}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.deactivateAppWarning\",\n \"This will deactivate the app and revoke all tokens. This action cannot be undone easily.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deactivating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleDeactivate();\n }}\n disabled={deactivating}\n className=\"bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90\"\n >\n {deactivating\n ? tr(\"devportal.deactivating\", \"Deactivating...\")\n : tr(\"devportal.deactivate\", \"Deactivate\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OAuthClientDetailPage.js","names":["OAuthClientDetailPage","appId","useParams","useDevportal","useI18n","tr","value","t","key","fallback","showSecret","setShowSecret","useState","newSecret","setNewSecret","confirmDelete","setConfirmDelete","confirmRotate","setConfirmRotate","actionError","setActionError","isFluidgrids","useIsFluidgridsVariant","useGetAuthAppQuery","rotateSecret","rotating","useRotateAppSecretMutation","deactivateApp","deactivating","useDeactivateAppMutation","updateApp","useUpdateAuthAppMutation","app","data","handleNavigate","basePath","path","handleCopy","ok","nativeCopyText","text","handleRotateSecret","secret","refetch","err","errorMessage","handleDeactivate","loading","PageLayout","Loader2","error","AlertCircle","getErrorMessage","ArrowLeft","PermissionGuard","CTAOverflowMenu","newStatus","Trash2","ActiveIndicator","cn","GlassCard","Copy","jsx","EyeOff","Eye","RefreshCw","scope","uri","AlertDialog","AlertDialogContent","AlertDialogHeader","AlertDialogTitle","AlertDialogDescription","AlertDialogFooter","AlertDialogCancel","AlertDialogAction"],"sources":["../../../src/devportal/pages/OAuthClientDetailPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Copy,\n Eye,\n EyeOff,\n Loader2,\n AlertCircle,\n RefreshCw,\n Trash2,\n ArrowLeft,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n CTAOverflowMenu,\n GlassCard,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useParams } from \"react-router\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { ActiveIndicator } from \"../components/StatusBadge\";\nimport {\n useDevportal,\n useIsFluidgridsVariant,\n} from \"../providers/DevportalProvider\";\nimport { errorMessage } from \"../utils/errorMessage\";\nimport { PermissionGuard } from \"../components\";\nimport type { AuthApp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\nimport {\n useGetAuthAppQuery,\n useRotateAppSecretMutation,\n useDeactivateAppMutation,\n useUpdateAuthAppMutation,\n getErrorMessage,\n} from \"../hooks\";\n\n/**\n * OAuth App Detail page\n *\n * Shows details for an auth-svc App (replaces devportal-svc OAuthClient detail).\n * Supports secret rotation, deactivation, and status toggle.\n */\nexport const OAuthClientDetailPage: FC = () => {\n const { clientId: appId } = useParams<{ clientId: string }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [showSecret, setShowSecret] = useState(false);\n const [newSecret, setNewSecret] = useState<string | null>(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [confirmRotate, setConfirmRotate] = useState(false);\n // A failed rotate / deactivate / status change stays visible (never swallowed).\n const [actionError, setActionError] = useState<string | null>(null);\n // FluidGrids: the \"Delete\" action only deactivates, so it is labelled that way.\n const isFluidgrids = useIsFluidgridsVariant();\n\n const { data, loading, error, refetch } = useGetAuthAppQuery({\n variables: { id: appId || \"\" },\n skip: !appId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const [rotateSecret, { loading: rotating }] = useRotateAppSecretMutation();\n const [deactivateApp, { loading: deactivating }] = useDeactivateAppMutation();\n const [updateApp] = useUpdateAuthAppMutation();\n\n const app: AuthApp | null = data?.app\n ? {\n id: data.app.id,\n name: data.app.name,\n description: data.app.description ?? undefined,\n clientId: data.app.clientId,\n type: data.app.type as AuthApp[\"type\"],\n status: data.app.status as AuthApp[\"status\"],\n scopes: data.app.scopes ?? [],\n redirectUris: data.app.redirectUris ?? [],\n ownerUserId: data.app.ownerUserId,\n tenantId: data.app.tenantId,\n createdAt: data.app.createdAt,\n updatedAt: data.app.updatedAt,\n }\n : null;\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n const handleCopy = async (text: string) => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(text);\n void nativeNotify(ok ? \"success\" : \"error\");\n };\n\n const handleRotateSecret = async () => {\n if (!appId) return;\n setActionError(null);\n try {\n const result = await rotateSecret({ variables: { id: appId } });\n const secret = result.data?.rotateAppSecret?.clientSecret;\n if (secret) {\n setNewSecret(secret);\n setShowSecret(true);\n }\n setConfirmRotate(false);\n refetch();\n } catch (err) {\n setActionError(\n errorMessage(\n err,\n tr(\n \"devportal.oauthActionFailed\",\n \"That did not work. Nothing was changed. Please try again.\",\n ),\n ),\n );\n }\n };\n\n const handleDeactivate = async () => {\n if (!appId) return;\n setActionError(null);\n try {\n await deactivateApp({ variables: { id: appId } });\n setConfirmDelete(false);\n handleNavigate(\"/oauth\");\n } catch (err) {\n setActionError(\n errorMessage(\n err,\n tr(\n \"devportal.oauthActionFailed\",\n \"That did not work. Nothing was changed. Please try again.\",\n ),\n ),\n );\n }\n };\n\n const handleToggleStatus = async () => {\n if (!appId || !app) return;\n setActionError(null);\n const newStatus = app.status === \"ACTIVE\" ? \"INACTIVE\" : \"ACTIVE\";\n try {\n await updateApp({\n variables: { id: appId, input: { status: newStatus } },\n });\n refetch();\n } catch (err) {\n setActionError(\n errorMessage(\n err,\n tr(\n \"devportal.oauthActionFailed\",\n \"That did not work. Nothing was changed. Please try again.\",\n ),\n ),\n );\n }\n };\n\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.loadingDots\", \"Loading...\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (error || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.appDetails\", \"App Details\")}\n description={tr(\"devportal.failedToLoad\", \"Failed to load\")}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {error\n ? tr(\"devportal.failedToLoadApp\", \"Failed to load app\")\n : tr(\"devportal.appNotFound\", \"App not found\")}\n </h3>\n {error && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n )}\n <button\n onClick={() => handleNavigate(\"/oauth\")}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <ArrowLeft size={16} />\n {tr(\"devportal.backToApps\", \"Back to Apps\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard authOnly>\n <PageLayout\n title={app.name}\n description={\n app.description ||\n tr(\n \"devportal.oauthAppDetailsAndCredentials\",\n \"OAuth App details and credentials\",\n )\n }\n purpose={tr(\n \"devportal.oauthAppDetailPurpose\",\n \"These are this OAuth app's credentials and the scopes it may request. Copy the client ID for your integration, rotate the secret if it leaks, and keep scopes minimal so users only grant what the app truly needs.\",\n )}\n backLink=\"/oauth\"\n backLabel={tr(\"devportal.backToApps\", \"Back to Apps\")}\n actions={\n <CTAOverflowMenu\n primary={{\n label:\n app.status === \"ACTIVE\"\n ? tr(\"devportal.deactivate\", \"Deactivate\")\n : tr(\"devportal.activate\", \"Activate\"),\n onSelect: handleToggleStatus,\n }}\n actions={[\n {\n label: isFluidgrids\n ? tr(\"devportal.deactivate\", \"Deactivate\")\n : tr(\"devportal.delete\", \"Delete\"),\n icon: <Trash2 size={16} />,\n intent: \"destructive\",\n onSelect: () => setConfirmDelete(true),\n },\n ]}\n />\n }\n >\n {actionError && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-text\"\n >\n {actionError}\n </div>\n )}\n {/* Status & Type */}\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.statusAndConfiguration\", \"Status & Configuration\")}\n </h3>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.status\", \"Status\")}\n </span>\n <div className=\"flex items-center gap-2\">\n <ActiveIndicator active={app.status === \"ACTIVE\"} />\n <span className=\"text-sm font-medium\">{app.status}</span>\n </div>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.type\", \"Type\")}\n </span>\n <span\n className={cn(\n \"rounded px-2 py-0.5 text-xs font-medium\",\n app.type === \"SERVICE\"\n ? \"bg-accent-purple-subtle text-accent-purple\"\n : app.type === \"INTEGRATION\" ||\n app.type === \"API_INTEGRATION\"\n ? \"bg-status-info-bg-subtle text-status-info-text\"\n : \"bg-status-success-bg-subtle text-status-success-text\",\n )}\n >\n {app.type}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr(\"devportal.created\", \"Created\")}\n </span>\n <span className=\"text-sm\">\n {new Date(app.createdAt).toLocaleDateString()}\n </span>\n </div>\n </div>\n </div>\n\n {/* Credentials — primary emphasis zone */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-4\">\n {tr(\"devportal.credentials\", \"Credentials\")}\n </h3>\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs text-text-secondary\">\n {tr(\"devportal.clientId\", \"Client ID\")}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {app.clientId}\n </code>\n <button\n onClick={() => handleCopy(app.clientId)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n title=\"Copy\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n {newSecret && (\n <div>\n <label className=\"text-xs text-status-error-text font-medium\">\n {tr(\n \"devportal.newClientSecretShownOnce\",\n \"New Client Secret (shown only once!)\",\n )}\n </label>\n <div className=\"mt-1 flex items-center gap-2\">\n <code className=\"flex-1 rounded bg-status-error-bg/10 border border-status-error-border/30 px-3 py-1.5 text-sm font-mono\">\n {showSecret\n ? newSecret\n : \"\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\"}\n </code>\n <button\n onClick={() => setShowSecret(!showSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n {showSecret ? <EyeOff size={14} /> : <Eye size={14} />}\n </button>\n <button\n onClick={() => handleCopy(newSecret)}\n className=\"rounded p-1.5 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={14} />\n </button>\n </div>\n </div>\n )}\n <button\n onClick={() => setConfirmRotate(true)}\n disabled={rotating}\n className=\"mt-2 inline-flex items-center gap-2 rounded-md bg-status-warning-bg-subtle px-3 py-1.5 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle transition-colors disabled:opacity-50\"\n >\n <RefreshCw\n size={14}\n className={rotating ? \"animate-spin\" : \"\"}\n />\n {tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </button>\n </div>\n </GlassCard>\n </div>\n\n {/* Scopes */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.scopes\", \"Scopes\")} ({app.scopes.length})\n </h3>\n {app.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {app.scopes.map((scope) => (\n <span\n key={scope}\n className=\"rounded-full bg-action-primary-bg/10 px-3 py-1 text-xs font-medium text-primary\"\n >\n {scope}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"devportal.noScopesConfigured\", \"No scopes configured\")}\n </p>\n )}\n </div>\n\n {/* Redirect URIs */}\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-6\">\n <h3 className=\"text-sm font-medium text-text-secondary mb-3\">\n {tr(\"devportal.redirectUris\", \"Redirect URIs\")} (\n {app.redirectUris.length})\n </h3>\n {app.redirectUris.length > 0 ? (\n <div className=\"space-y-2\">\n {app.redirectUris.map((uri) => (\n <div key={uri} className=\"flex items-center gap-2\">\n <code className=\"rounded bg-bg-sunken px-3 py-1.5 text-sm font-mono\">\n {uri}\n </code>\n <button\n onClick={() => handleCopy(uri)}\n className=\"rounded p-1 hover:bg-bg-sunken transition-colors\"\n >\n <Copy size={12} />\n </button>\n </div>\n ))}\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.noRedirectUrisConfigured\",\n \"No redirect URIs configured\",\n )}\n </p>\n )}\n </div>\n\n {/* Confirm Rotate Dialog */}\n <AlertDialog open={confirmRotate} onOpenChange={setConfirmRotate}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {tr(\n \"devportal.rotateClientSecretQuestion\",\n \"Rotate Client Secret?\",\n )}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.rotateSecretWarning\",\n \"This will invalidate the current client secret. All integrations using the old secret will stop working immediately.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={rotating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleRotateSecret();\n }}\n disabled={rotating}\n className=\"bg-status-warning-bg text-white hover:bg-status-warning-bg/90\"\n >\n {rotating\n ? tr(\"devportal.rotating\", \"Rotating...\")\n : tr(\"devportal.rotateSecret\", \"Rotate Secret\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Confirm Deactivate Dialog */}\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle className=\"text-status-error-text\">\n {tr(\"devportal.deactivateAppQuestion\", \"Deactivate App?\")}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n \"devportal.deactivateAppWarning\",\n \"This will deactivate the app and revoke all tokens. This action cannot be undone easily.\",\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deactivating}>\n {tr(\"devportal.cancel\", \"Cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={(e) => {\n e.preventDefault();\n void handleDeactivate();\n }}\n disabled={deactivating}\n className=\"bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90\"\n >\n {deactivating\n ? tr(\"devportal.deactivating\", \"Deactivating...\")\n : tr(\"devportal.deactivate\", \"Deactivate\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuDA,IAAaA,UAAkC;CAC7C,IAAM,EAAE,UAAUC,MAAUC,EAAgC,GACtD,EAAE,aAAU,gBAAaC,EAAa,GACtC,EAAE,SAAMC,GAAQ,GAChBC,KAAM,GAAa,MAA6B;EACpD,IAAMC,IAAQC,EAAEC,CAAG;EACnB,OAAOF,MAAUE,IAAMC,IAAWH;CACpC,GACM,CAACI,GAAYC,KAAiBC,EAAS,EAAK,GAC5C,CAACC,GAAWC,KAAgBF,EAAwB,IAAI,GACxD,CAACG,GAAeC,KAAoBJ,EAAS,EAAK,GAClD,CAACK,GAAeC,KAAoBN,EAAS,EAAK,GAElD,CAACO,GAAaC,KAAkBR,EAAwB,IAAI,GAE5DS,IAAeC,GAAuB,GAEtC,EAAE,SAAM,aAAS,UAAO,eAAYC,GAAmB;EAC3D,WAAW,EAAE,IAAItB,KAAS,GAAG;EAC7B,MAAM,CAACA;EACP,aAAa;CACf,CAAC,GAEK,CAACuB,IAAc,EAAE,SAASC,OAAcC,EAA2B,GACnE,CAACC,IAAe,EAAE,SAASC,OAAkBC,EAAyB,GACtE,CAACC,MAAaC,EAAyB,GAEvCC,IAAsBC,GAAM,MAC9B;EACE,IAAIA,EAAK,IAAI;EACb,MAAMA,EAAK,IAAI;EACf,aAAaA,EAAK,IAAI,eAAe,KAAA;EACrC,UAAUA,EAAK,IAAI;EACnB,MAAMA,EAAK,IAAI;EACf,QAAQA,EAAK,IAAI;EACjB,QAAQA,EAAK,IAAI,UAAU,CAAC;EAC5B,cAAcA,EAAK,IAAI,gBAAgB,CAAC;EACxC,aAAaA,EAAK,IAAI;EACtB,UAAUA,EAAK,IAAI;EACnB,WAAWA,EAAK,IAAI;EACpB,WAAWA,EAAK,IAAI;CACtB,IACA,MAEEC,KAAkB,MAAiB;EACvC,IAAW,GAAGC,IAAWC,GAAM;CACjC,GAEMC,IAAa,OAAO,MAAiB;EACzC,GAAkB,OAAO;EACzB,IAAMC,IAAK,MAAMC,GAAeC,CAAI;EACpC,EAAkBF,IAAK,YAAY,OAAO;CAC5C,GAEMG,KAAqB,YAAY;EACrC,IAAKxC,GACL;KAAe,IAAI;GACnB,IAAI;IAEF,IAAMyC,KAAS,MADMlB,GAAa,EAAE,WAAW,EAAE,IAAIvB,EAAM,EAAE,CAAC,EAAA,CACxC,MAAM,iBAAiB;IAM7C,AALIyC,MACF5B,EAAa4B,CAAM,GACnB/B,EAAc,EAAI,IAEpBO,EAAiB,EAAK,GACtByB,EAAQ;GACV,SAASC,GAAK;IACZ,EACEC,EACED,GACAvC,EACE,+BACA,2DACF,CACF,CACF;GACF;EApBmB;CAqBrB,GAEMyC,KAAmB,YAAY;EACnC,IAAK7C,GACL;KAAe,IAAI;GACnB,IAAI;IAGF,AAFA,MAAM0B,GAAc,EAAE,WAAW,EAAE,IAAI1B,EAAM,EAAE,CAAC,GAChDe,EAAiB,EAAK,GACtBkB,EAAe,QAAQ;GACzB,SAASU,GAAK;IACZ,EACEC,EACED,GACAvC,EACE,+BACA,2DACF,CACF,CACF;GACF;EAfmB;CAgBrB;CAuEA,OA/CI0C,MAAW,CAACd,IAEZ,kBAACe,GAAD;EACE,OAAO3C,EAAG,wBAAwB,aAAa;EAC/C,aAAaA,EAAG,yBAAyB,YAAY;EACrD,UAAS;EACT,WAAWA,EAAG,wBAAwB,cAAc;EAEpD,UAAA,kBAAC,OAAD;GAAK,WAAU;GACb,UAAA,kBAAC4C,GAAD,EAAS,WAAU,2CAA4C,CAAA;EAC5D,CAAA;CACK,CAAA,IAIZC,KAAS,CAAClB,IAEV,kBAACgB,GAAD;EACE,OAAO3C,EAAG,wBAAwB,aAAa;EAC/C,aAAaA,EAAG,0BAA0B,gBAAgB;EAC1D,UAAS;EACT,WAAWA,EAAG,wBAAwB,cAAc;EAEpD,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC8C,GAAD,EAAa,WAAU,yCAA0C,CAAA;IACjE,kBAAC,MAAD;KAAI,WAAU;KACX,UAAAD,IACG7C,EAAG,6BAA6B,oBAAoB,IACpDA,EAAG,yBAAyB,eAAe;IAC7C,CAAA;IACH6C,KACC,kBAAC,KAAD;KAAG,WAAU;KACV,UAAAE,EAAgBF,CAAK;IACrB,CAAA;IAEL,kBAAC,UAAD;KACE,eAAehB,EAAe,QAAQ;KACtC,WAAU;KAFZ,UAAA,CAIE,kBAACmB,GAAD,EAAW,MAAM,GAAK,CAAA,GACrBhD,EAAG,wBAAwB,cAAc,CACpC;;GACL;;CACK,CAAA,IAKd,kBAACiD,IAAD;EAAiB,UAAA;EACf,UAAA,kBAACN,GAAD;GACE,OAAOhB,EAAI;GACX,aACEA,EAAI,eACJ3B,EACE,2CACA,mCACF;GAEF,SAASA,EACP,mCACA,qNACF;GACA,UAAS;GACT,WAAWA,EAAG,wBAAwB,cAAc;GACpD,SACE,kBAACkD,GAAD;IACE,SAAS;KACP,OACEvB,EAAI,WAAW,WACX3B,EAAG,wBAAwB,YAAY,IACvCA,EAAG,sBAAsB,UAAU;KACzC,UAAU,YA7FiB;MACrC,IAAI,CAACJ,KAAS,CAAC+B,GAAK;MACpB,EAAe,IAAI;MACnB,IAAMwB,IAAYxB,EAAI,WAAW,WAAW,aAAa;MACzD,IAAI;OAIF,AAHA,MAAMF,GAAU,EACd,WAAW;QAAE,IAAI7B;QAAO,OAAO,EAAE,QAAQuD,EAAU;OAAE,EACvD,CAAC,GACDb,EAAQ;MACV,SAASC,GAAK;OACZ,EACEC,EACED,GACAvC,EACE,+BACA,2DACF,CACF,CACF;MACF;KACF;IA0EU;IACA,SAAS,CACP;KACE,OAAOgB,IACHhB,EAAG,wBAAwB,YAAY,IACvCA,EAAG,oBAAoB,QAAQ;KACnC,MAAM,kBAACoD,IAAD,EAAQ,MAAM,GAAK,CAAA;KACzB,QAAQ;KACR,gBAAgBzC,EAAiB,EAAI;IACvC,CACF;GACD,CAAA;GAlCL,UAAA;IAqCGG,KACC,kBAAC,OAAD;KACE,MAAK;KACL,WAAU;KAET,UAAAA;IACE,CAAA;IAGP,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;OACX,UAAAd,EAAG,oCAAoC,wBAAwB;MAC9D,CAAA,GACJ,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;UACb,UAAAA,EAAG,oBAAoB,QAAQ;SAC5B,CAAA,GACN,kBAAC,OAAD;UAAK,WAAU;UAAf,UAAA,CACE,kBAACqD,GAAD,EAAiB,QAAQ1B,EAAI,WAAW,SAAW,CAAA,GACnD,kBAAC,QAAD;WAAM,WAAU;WAAuB,UAAAA,EAAI;UAAa,CAAA,CACrD;SACF,CAAA,CAAA;;QACL,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;UACb,UAAA3B,EAAG,kBAAkB,MAAM;SACxB,CAAA,GACN,kBAAC,QAAD;UACE,WAAWsD,GACT,2CACA3B,EAAI,SAAS,YACT,+CACAA,EAAI,SAAS,iBACXA,EAAI,SAAS,oBACb,mDACA,sDACR;UAEC,UAAAA,EAAI;SACD,CAAA,CACH;;QACL,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;UACb,UAAA3B,EAAG,qBAAqB,SAAS;SAC9B,CAAA,GACN,kBAAC,QAAD;UAAM,WAAU;UACb,UAAA,IAAI,KAAK2B,EAAI,SAAS,CAAC,CAAC,mBAAmB;SACxC,CAAA,CACH;;OACF;MACF,CAAA,CAAA;KAGL,CAAA,GAAA,kBAAC4B,GAAD;MAAW,WAAU;MAAQ,MAAA;MAAK,WAAU;MAA5C,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;OACX,UAAAvD,EAAG,yBAAyB,aAAa;MACxC,CAAA,GACJ,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;SACd,UAAAA,EAAG,sBAAsB,WAAW;QAChC,CAAA,GACP,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA,CACE,kBAAC,QAAD;UAAM,WAAU;UACb,UAAA2B,EAAI;SACD,CAAA,GACN,kBAAC,UAAD;UACE,eAAeK,EAAWL,EAAI,QAAQ;UACtC,WAAU;UACV,OAAM;UAEN,UAAA,kBAAC6B,GAAD,EAAM,MAAM,GAAK,CAAA;SACX,CAAA,CACL;QACF,CAAA,CAAA,EAAA,CAAA;QACJhD,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;SAAO,WAAU;SACd,UAAAR,EACC,sCACA,sCACF;QACK,CAAA,GACP,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA;UACE,kBAAC,QAAD;WAAM,WAAU;WACb,UAAAK,IACGG,IACA;UACA,CAAA;UACN,kBAAC,UAAD;WACE,eAAeF,EAAc,CAACD,CAAU;WACxC,WAAU;WAET,UAAaoD,EAAbpD,IAAcqD,IAAuBC,GAAxB,EAAQ,MAAM,GAAK,CAAoB;UAC/C,CAAA;UACR,kBAAC,UAAD;WACE,eAAe3B,EAAWxB,CAAS;WACnC,WAAU;WAEV,UAAA,kBAACgD,GAAD,EAAM,MAAM,GAAK,CAAA;UACX,CAAA;SACL;QACF,CAAA,CAAA,EAAA,CAAA;QAEP,kBAAC,UAAD;SACE,eAAe3C,EAAiB,EAAI;SACpC,UAAUO;SACV,WAAU;SAHZ,UAAA,CAKE,kBAACwC,GAAD;UACE,MAAM;UACN,WAAWxC,IAAW,iBAAiB;SACxC,CAAA,GACApB,EAAG,0BAA0B,eAAe,CACvC;;OACL;MACI,CAAA,CAAA;KACR,CAAA,CAAA;;IAGL,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;MAAd,UAAA;OACGA,EAAG,oBAAoB,QAAQ;OAAE;OAAG2B,EAAI,OAAO;OAAO;MACrD;KACH,CAAA,GAAAA,EAAI,OAAO,SAAS,IACnB,kBAAC,OAAD;MAAK,WAAU;MACZ,UAAAA,EAAI,OAAO,KAAK,MACf,kBAAC,QAAD;OAEE,WAAU;OAET,UAAAkC;MACG,GAJCA,CAID,CACP;KACE,CAAA,IAEL,kBAAC,KAAD;MAAG,WAAU;MACV,UAAA7D,EAAG,gCAAgC,sBAAsB;KACzD,CAAA,CAEF;;IAGL,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;MAAd,UAAA;OACGA,EAAG,0BAA0B,eAAe;OAAE;OAC9C2B,EAAI,aAAa;OAAO;MACvB;KACH,CAAA,GAAAA,EAAI,aAAa,SAAS,IACzB,kBAAC,OAAD;MAAK,WAAU;MACZ,UAAAA,EAAI,aAAa,KAAK,MACrB,kBAAC,OAAD;OAAe,WAAU;OAAzB,UAAA,CACE,kBAAC,QAAD;QAAM,WAAU;QACb,UAAAmC;OACG,CAAA,GACN,kBAAC,UAAD;QACE,eAAe9B,EAAW8B,CAAG;QAC7B,WAAU;QAEV,UAAA,kBAACN,GAAD,EAAM,MAAM,GAAK,CAAA;OACX,CAAA,CACL;MAVK,GAAAM,CAUL,CACN;KACE,CAAA,IAEL,kBAAC,KAAD;MAAG,WAAU;MACV,UAAA9D,EACC,sCACA,6BACF;KACC,CAAA,CAEF;;IAGL,kBAAC+D,GAAD;KAAa,MAAMnD;KAAe,cAAcC;KAC9C,UAAA,kBAACmD,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UACGlE,EACC,wCACA,uBACF,EACgB,CAAA,GAClB,kBAACmE,GAAD,EAAA,UACGnE,EACC,iCACA,sHACF,EACsB,CAAA,CACP,EAAA,CAAA,GACnB,kBAACoE,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD;MAAmB,UAAUjD;MAC1B,UAAApB,EAAG,oBAAoB,QAAQ;KACf,CAAA,GACnB,kBAACsE,GAAD;MACE,UAAU,MAAM;OAEd,AADA,EAAE,eAAe,GACjBlC,GAAwB;MAC1B;MACA,UAAUhB;MACV,WAAU;MAET,UAAAA,IACGpB,EAAG,sBAAsB,aAAa,IACtCA,EAAG,0BAA0B,eAAe;KAC/B,CAAA,CACF,EAAA,CAAA,CACD,EAAA,CAAA;IACT,CAAA;IAGb,kBAAC+D,GAAD;KAAa,MAAMrD;KAAe,cAAcC;KAC9C,UAAA,kBAACqD,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD;MAAkB,WAAU;MACzB,UAAAlE,EAAG,mCAAmC,iBAAiB;KACxC,CAAA,GAClB,kBAACmE,GAAD,EAAA,UACGnE,EACC,kCACA,0FACF,EACsB,CAAA,CACP,EAAA,CAAA,GACnB,kBAACoE,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD;MAAmB,UAAU9C;MAC1B,UAAAvB,EAAG,oBAAoB,QAAQ;KACf,CAAA,GACnB,kBAACsE,GAAD;MACE,UAAU,MAAM;OAEd,AADA,EAAE,eAAe,GACjB7B,GAAsB;MACxB;MACA,UAAUlB;MACV,WAAU;MAET,UAAAA,IACGvB,EAAG,0BAA0B,iBAAiB,IAC9CA,EAAG,wBAAwB,YAAY;KAC1B,CAAA,CACF,EAAA,CAAA,CACD,EAAA,CAAA;IACT,CAAA;GACH;;CACG,CAAA;AAErB"}
|