@replicated/portal-components 0.0.1 → 0.0.3
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/components/metadata/registry.json +109 -3
- package/components/metadata/registry.md +53 -3
- package/dist/actions/index.d.mts +590 -2
- package/dist/actions/index.d.ts +590 -2
- package/dist/actions/index.js +1931 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/airgap-instances.d.mts +26 -0
- package/dist/airgap-instances.d.ts +26 -0
- package/dist/airgap-instances.js +354 -0
- package/dist/airgap-instances.js.map +1 -0
- package/dist/error-page.d.mts +14 -0
- package/dist/error-page.d.ts +14 -0
- package/dist/error-page.js +153 -0
- package/dist/error-page.js.map +1 -0
- package/dist/error.d.mts +15 -0
- package/dist/error.d.ts +15 -0
- package/dist/error.js +144 -0
- package/dist/error.js.map +1 -0
- package/dist/esm/actions/index.js +1892 -1
- package/dist/esm/actions/index.js.map +1 -1
- package/dist/esm/airgap-instances.js +352 -0
- package/dist/esm/airgap-instances.js.map +1 -0
- package/dist/esm/error-page.js +151 -0
- package/dist/esm/error-page.js.map +1 -0
- package/dist/esm/error.js +142 -0
- package/dist/esm/error.js.map +1 -0
- package/dist/esm/helm-install-wizard.js +1007 -0
- package/dist/esm/helm-install-wizard.js.map +1 -0
- package/dist/esm/index.js +2240 -82
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/install-actions.js +746 -0
- package/dist/esm/install-actions.js.map +1 -0
- package/dist/esm/install-card.js +115 -0
- package/dist/esm/install-card.js.map +1 -0
- package/dist/esm/install-targets.js +48 -0
- package/dist/esm/install-targets.js.map +1 -0
- package/dist/esm/instance-card.js +197 -0
- package/dist/esm/instance-card.js.map +1 -0
- package/dist/esm/join-team.js +218 -0
- package/dist/esm/join-team.js.map +1 -0
- package/dist/esm/license-card.js +131 -0
- package/dist/esm/license-card.js.map +1 -0
- package/dist/esm/license-details.js +667 -0
- package/dist/esm/license-details.js.map +1 -0
- package/dist/esm/linux-install-wizard.js +1083 -0
- package/dist/esm/linux-install-wizard.js.map +1 -0
- package/dist/esm/login.js +261 -0
- package/dist/esm/login.js.map +1 -0
- package/dist/esm/online-instance-list.js +287 -0
- package/dist/esm/online-instance-list.js.map +1 -0
- package/dist/esm/pending-installations.js +235 -0
- package/dist/esm/pending-installations.js.map +1 -0
- package/dist/esm/release-history-panel.js +100 -0
- package/dist/esm/release-history-panel.js.map +1 -0
- package/dist/esm/release-notes-card.js +23 -0
- package/dist/esm/release-notes-card.js.map +1 -0
- package/dist/esm/security-card.js +700 -0
- package/dist/esm/security-card.js.map +1 -0
- package/dist/esm/support-bundle-collection-card.js +170 -0
- package/dist/esm/support-bundle-collection-card.js.map +1 -0
- package/dist/esm/support-bundles-card.js +306 -0
- package/dist/esm/support-bundles-card.js.map +1 -0
- package/dist/esm/support-card.js +305 -0
- package/dist/esm/support-card.js.map +1 -0
- package/dist/esm/team-selection.js +117 -0
- package/dist/esm/team-selection.js.map +1 -0
- package/dist/esm/team-settings-card.js +78 -0
- package/dist/esm/team-settings-card.js.map +1 -0
- package/dist/esm/team-settings.js +136 -0
- package/dist/esm/team-settings.js.map +1 -0
- package/dist/esm/top-nav-user-menu.js +173 -0
- package/dist/esm/top-nav-user-menu.js.map +1 -0
- package/dist/esm/top-nav.js +398 -0
- package/dist/esm/top-nav.js.map +1 -0
- package/dist/esm/update-layout.js +405 -0
- package/dist/esm/update-layout.js.map +1 -0
- package/dist/esm/updates-card.js +85 -0
- package/dist/esm/updates-card.js.map +1 -0
- package/dist/esm/upload-support-bundle-modal.js +143 -0
- package/dist/esm/upload-support-bundle-modal.js.map +1 -0
- package/dist/esm/user-settings-card.js +21 -0
- package/dist/esm/user-settings-card.js.map +1 -0
- package/dist/esm/user-settings.js +368 -0
- package/dist/esm/user-settings.js.map +1 -0
- package/dist/esm/utils/index.js +170 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/helm-install-wizard.d.mts +38 -0
- package/dist/helm-install-wizard.d.ts +38 -0
- package/dist/helm-install-wizard.js +1011 -0
- package/dist/helm-install-wizard.js.map +1 -0
- package/dist/index.d.mts +11 -20
- package/dist/index.d.ts +11 -20
- package/dist/index.js +2266 -81
- package/dist/index.js.map +1 -1
- package/dist/install-B19AaKF_.d.mts +233 -0
- package/dist/install-Bi1qJ8Bu.d.ts +233 -0
- package/dist/install-actions.d.mts +141 -0
- package/dist/install-actions.d.ts +141 -0
- package/dist/install-actions.js +765 -0
- package/dist/install-actions.js.map +1 -0
- package/dist/install-card.d.mts +15 -0
- package/dist/install-card.d.ts +15 -0
- package/dist/install-card.js +117 -0
- package/dist/install-card.js.map +1 -0
- package/dist/install-targets.d.mts +19 -0
- package/dist/install-targets.d.ts +19 -0
- package/dist/install-targets.js +50 -0
- package/dist/install-targets.js.map +1 -0
- package/dist/instance-card.d.mts +22 -0
- package/dist/instance-card.d.ts +22 -0
- package/dist/instance-card.js +199 -0
- package/dist/instance-card.js.map +1 -0
- package/dist/join-team.d.mts +30 -0
- package/dist/join-team.d.ts +30 -0
- package/dist/join-team.js +220 -0
- package/dist/join-team.js.map +1 -0
- package/dist/license-card.d.mts +15 -0
- package/dist/license-card.d.ts +15 -0
- package/dist/license-card.js +133 -0
- package/dist/license-card.js.map +1 -0
- package/dist/license-details.d.mts +10 -0
- package/dist/license-details.d.ts +10 -0
- package/dist/license-details.js +669 -0
- package/dist/license-details.js.map +1 -0
- package/dist/linux-install-wizard.d.mts +66 -0
- package/dist/linux-install-wizard.d.ts +66 -0
- package/dist/linux-install-wizard.js +1093 -0
- package/dist/linux-install-wizard.js.map +1 -0
- package/dist/login.d.mts +37 -0
- package/dist/login.d.ts +37 -0
- package/dist/login.js +263 -0
- package/dist/login.js.map +1 -0
- package/dist/online-instance-list.d.mts +22 -0
- package/dist/online-instance-list.d.ts +22 -0
- package/dist/online-instance-list.js +289 -0
- package/dist/online-instance-list.js.map +1 -0
- package/dist/pending-installations.d.mts +15 -0
- package/dist/pending-installations.d.ts +15 -0
- package/dist/pending-installations.js +237 -0
- package/dist/pending-installations.js.map +1 -0
- package/dist/release-history-panel.d.mts +22 -0
- package/dist/release-history-panel.d.ts +22 -0
- package/dist/release-history-panel.js +102 -0
- package/dist/release-history-panel.js.map +1 -0
- package/dist/release-notes-card.d.mts +13 -0
- package/dist/release-notes-card.d.ts +13 -0
- package/dist/release-notes-card.js +25 -0
- package/dist/release-notes-card.js.map +1 -0
- package/dist/security-card.d.mts +73 -0
- package/dist/security-card.d.ts +73 -0
- package/dist/security-card.js +702 -0
- package/dist/security-card.js.map +1 -0
- package/dist/styles.css +1885 -191
- package/dist/support-bundle-collection-card.d.mts +20 -0
- package/dist/support-bundle-collection-card.d.ts +20 -0
- package/dist/support-bundle-collection-card.js +172 -0
- package/dist/support-bundle-collection-card.js.map +1 -0
- package/dist/support-bundles-card.d.mts +19 -0
- package/dist/support-bundles-card.d.ts +19 -0
- package/dist/support-bundles-card.js +308 -0
- package/dist/support-bundles-card.js.map +1 -0
- package/dist/support-card.d.mts +8 -0
- package/dist/support-card.d.ts +8 -0
- package/dist/support-card.js +307 -0
- package/dist/support-card.js.map +1 -0
- package/dist/team-selection.d.mts +23 -0
- package/dist/team-selection.d.ts +23 -0
- package/dist/team-selection.js +119 -0
- package/dist/team-selection.js.map +1 -0
- package/dist/team-settings-card-Dq1d9b5c.d.mts +14 -0
- package/dist/team-settings-card-Dq1d9b5c.d.ts +14 -0
- package/dist/team-settings-card.d.mts +2 -0
- package/dist/team-settings-card.d.ts +2 -0
- package/dist/team-settings-card.js +80 -0
- package/dist/team-settings-card.js.map +1 -0
- package/dist/team-settings.d.mts +25 -0
- package/dist/team-settings.d.ts +25 -0
- package/dist/team-settings.js +138 -0
- package/dist/team-settings.js.map +1 -0
- package/dist/top-nav-0mb1K_H0.d.mts +32 -0
- package/dist/top-nav-0mb1K_H0.d.ts +32 -0
- package/dist/top-nav-user-menu.d.mts +18 -0
- package/dist/top-nav-user-menu.d.ts +18 -0
- package/dist/top-nav-user-menu.js +175 -0
- package/dist/top-nav-user-menu.js.map +1 -0
- package/dist/top-nav.d.mts +3 -0
- package/dist/top-nav.d.ts +3 -0
- package/dist/top-nav.js +400 -0
- package/dist/top-nav.js.map +1 -0
- package/dist/update-layout.d.mts +12 -0
- package/dist/update-layout.d.ts +12 -0
- package/dist/update-layout.js +407 -0
- package/dist/update-layout.js.map +1 -0
- package/dist/updates-card-BbubBrVR.d.mts +18 -0
- package/dist/updates-card-BbubBrVR.d.ts +18 -0
- package/dist/updates-card.d.mts +2 -0
- package/dist/updates-card.d.ts +2 -0
- package/dist/updates-card.js +87 -0
- package/dist/updates-card.js.map +1 -0
- package/dist/upload-support-bundle-modal.d.mts +19 -0
- package/dist/upload-support-bundle-modal.d.ts +19 -0
- package/dist/upload-support-bundle-modal.js +145 -0
- package/dist/upload-support-bundle-modal.js.map +1 -0
- package/dist/user-settings-card.d.mts +8 -0
- package/dist/user-settings-card.d.ts +8 -0
- package/dist/user-settings-card.js +23 -0
- package/dist/user-settings-card.js.map +1 -0
- package/dist/user-settings.d.mts +47 -0
- package/dist/user-settings.d.ts +47 -0
- package/dist/user-settings.js +370 -0
- package/dist/user-settings.js.map +1 -0
- package/dist/utils/index.d.mts +70 -0
- package/dist/utils/index.d.ts +70 -0
- package/dist/utils/index.js +177 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +163 -3
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var buffer = require('buffer');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Enterprise Portal Components
|
|
@@ -10,7 +11,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
10
11
|
|
|
11
12
|
// package.json
|
|
12
13
|
var package_default = {
|
|
13
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.3"};
|
|
14
15
|
|
|
15
16
|
// src/tokens/index.ts
|
|
16
17
|
var baseTokens = {
|
|
@@ -124,109 +125,2293 @@ var Button = react.forwardRef(
|
|
|
124
125
|
}
|
|
125
126
|
);
|
|
126
127
|
Button.displayName = "Button";
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
...
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
128
|
+
|
|
129
|
+
// src/utils/api-client.ts
|
|
130
|
+
function isRedirectError(error) {
|
|
131
|
+
return typeof error === "object" && error !== null && "digest" in error && typeof error.digest === "string" && error.digest.startsWith("NEXT_REDIRECT");
|
|
132
|
+
}
|
|
133
|
+
async function authenticatedFetch(url, options = {}) {
|
|
134
|
+
const { token, ...fetchOptions } = options;
|
|
135
|
+
const headers = new Headers(fetchOptions.headers);
|
|
136
|
+
if (token) {
|
|
137
|
+
headers.set("authorization", `Bearer ${token}`);
|
|
138
|
+
}
|
|
139
|
+
const response = await fetch(url, {
|
|
140
|
+
...fetchOptions,
|
|
141
|
+
headers
|
|
142
|
+
});
|
|
143
|
+
if (response.status === 401) {
|
|
144
|
+
await handle401();
|
|
145
|
+
}
|
|
146
|
+
if (response.status === 502 || response.status === 503 || response.status === 504) {
|
|
147
|
+
await handleServerError(response.status);
|
|
148
|
+
}
|
|
149
|
+
return response;
|
|
150
|
+
}
|
|
151
|
+
async function handle401() {
|
|
152
|
+
const { redirect } = await import('next/navigation');
|
|
153
|
+
return redirect("/?expired=1");
|
|
154
|
+
}
|
|
155
|
+
async function handleServerError(statusCode) {
|
|
156
|
+
const { redirect } = await import('next/navigation');
|
|
157
|
+
let sourceUrl;
|
|
158
|
+
try {
|
|
159
|
+
const { headers } = await import('next/headers');
|
|
160
|
+
const headersList = await headers();
|
|
161
|
+
const referer = headersList.get("referer");
|
|
162
|
+
const host = headersList.get("host");
|
|
163
|
+
const pathname = headersList.get("x-invoke-path") || headersList.get("x-forwarded-path");
|
|
164
|
+
if (referer) {
|
|
165
|
+
sourceUrl = referer;
|
|
166
|
+
} else if (host && pathname) {
|
|
167
|
+
const protocol = headersList.get("x-forwarded-proto") || "https";
|
|
168
|
+
sourceUrl = `${protocol}://${host}${pathname}`;
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.debug("[portal-components] Could not determine source URL", error);
|
|
172
|
+
}
|
|
173
|
+
const params = new URLSearchParams({ code: String(statusCode) });
|
|
174
|
+
if (sourceUrl) {
|
|
175
|
+
params.set("source", sourceUrl);
|
|
176
|
+
}
|
|
177
|
+
return redirect(`/error?${params.toString()}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/actions/index.ts
|
|
181
|
+
var getApiOrigin = () => {
|
|
182
|
+
return (process.env.REPLICATED_APP_ORIGIN || "https://replicated.app").replace(/\/+$/, "");
|
|
183
|
+
};
|
|
184
|
+
var defineServerAction = (definition) => definition;
|
|
185
|
+
var initiateLogin = defineServerAction({
|
|
186
|
+
id: "auth/initiate-login",
|
|
187
|
+
description: "Begins the passwordless login flow by dispatching a magic link email.",
|
|
188
|
+
visibility: "customer",
|
|
189
|
+
tags: ["auth", "login", "session"],
|
|
190
|
+
async run(input) {
|
|
191
|
+
const endpoint = `${getApiOrigin()}/v3/login/magic-link`;
|
|
192
|
+
const appSlug = process.env.PORTAL_APP_SLUG;
|
|
193
|
+
if (!appSlug) {
|
|
194
|
+
throw new Error("PORTAL_APP_SLUG is not configured");
|
|
195
|
+
}
|
|
196
|
+
const portalOrigin = process.env.PORTAL_ORIGIN ?? "https://enterprise.replicated.com";
|
|
197
|
+
const redirectUri = `${portalOrigin.replace(/\/+$/, "")}/${appSlug}/login`;
|
|
198
|
+
const response = await fetch(endpoint, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: {
|
|
201
|
+
"content-type": "application/json"
|
|
202
|
+
},
|
|
203
|
+
body: JSON.stringify({
|
|
204
|
+
app_slug: appSlug,
|
|
205
|
+
email_address: input.email,
|
|
206
|
+
redirect_uri: redirectUri
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`Magic link request failed (${response.status} ${response.statusText})`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const data = await response.json();
|
|
215
|
+
if (data.saml_redirect_required && data.saml_customer_id) {
|
|
216
|
+
return {
|
|
217
|
+
status: "saml_redirect",
|
|
218
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
219
|
+
message: "SAML authentication required",
|
|
220
|
+
saml: {
|
|
221
|
+
redirectRequired: true,
|
|
222
|
+
customerId: data.saml_customer_id,
|
|
223
|
+
email: input.email,
|
|
224
|
+
appSlug
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
status: "ok",
|
|
230
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
231
|
+
message: `Magic link requested for ${input.email}`
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
var verifyMagicLink = defineServerAction({
|
|
236
|
+
id: "auth/verify-magic-link",
|
|
237
|
+
description: "Verifies the 12-digit code provided via email and returns a JWT.",
|
|
238
|
+
visibility: "customer",
|
|
239
|
+
tags: ["auth", "login", "verify"],
|
|
240
|
+
async run({ nonce }) {
|
|
241
|
+
const endpoint = `${getApiOrigin()}/v3/login/magic-link/verify`;
|
|
242
|
+
if (process.env.NODE_ENV !== "production") {
|
|
243
|
+
console.debug(
|
|
244
|
+
"[portal-components] verifying magic link via %s",
|
|
245
|
+
endpoint
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
const response = await fetch(endpoint, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: {
|
|
251
|
+
"content-type": "application/json"
|
|
252
|
+
},
|
|
253
|
+
body: JSON.stringify({ nonce })
|
|
254
|
+
});
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
if (response.status === 401) {
|
|
257
|
+
try {
|
|
258
|
+
const errorBody = await response.json();
|
|
259
|
+
if (errorBody?.is_expired === true) {
|
|
260
|
+
const error3 = {
|
|
261
|
+
code: "expired",
|
|
262
|
+
message: "Magic link has expired. A new link has been sent to your email.",
|
|
263
|
+
isExpired: true
|
|
264
|
+
};
|
|
265
|
+
throw error3;
|
|
266
|
+
}
|
|
267
|
+
} catch (parseError) {
|
|
268
|
+
if (parseError?.code === "expired") {
|
|
269
|
+
throw parseError;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const error2 = {
|
|
273
|
+
code: "invalid_code",
|
|
274
|
+
message: "Incorrect code, check your email and try again."
|
|
275
|
+
};
|
|
276
|
+
throw error2;
|
|
277
|
+
}
|
|
278
|
+
const error = {
|
|
279
|
+
code: "unknown",
|
|
280
|
+
message: `Magic link verification failed (${response.status} ${response.statusText})`
|
|
281
|
+
};
|
|
282
|
+
throw error;
|
|
283
|
+
}
|
|
284
|
+
const payload = await response.json();
|
|
285
|
+
const token = payload?.token ?? payload?.jwt ?? payload?.access_token;
|
|
286
|
+
if (typeof token !== "string") {
|
|
287
|
+
throw new Error("Magic link verification succeeded but no token returned");
|
|
288
|
+
}
|
|
289
|
+
return { token, raw: payload };
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
var fetchCustomBrandingImpl = async () => {
|
|
293
|
+
const appSlug = process.env.PORTAL_APP_SLUG;
|
|
294
|
+
if (!appSlug) {
|
|
295
|
+
throw new Error("PORTAL_APP_SLUG is not configured");
|
|
296
|
+
}
|
|
297
|
+
const url = `${getApiOrigin()}/v3/custom-branding?app_slug=${encodeURIComponent(
|
|
298
|
+
appSlug
|
|
299
|
+
)}`;
|
|
300
|
+
if (process.env.NODE_ENV !== "production") {
|
|
301
|
+
console.debug(
|
|
302
|
+
"[portal-components] fetching custom branding via %s",
|
|
303
|
+
url
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const response = await fetch(url, {
|
|
307
|
+
headers: {
|
|
308
|
+
accept: "application/json"
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Custom branding request failed (${response.status} ${response.statusText})`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const payload = await response.json();
|
|
317
|
+
const brandingData = payload?.branding_data;
|
|
318
|
+
if (typeof brandingData !== "string") {
|
|
319
|
+
throw new Error("Custom branding response missing branding_data string");
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
brandingData,
|
|
323
|
+
documentation: payload?.documentation ?? null
|
|
324
|
+
};
|
|
325
|
+
};
|
|
326
|
+
var fetchCustomBranding = react.cache(fetchCustomBrandingImpl);
|
|
327
|
+
var decodeJwtPayload = (token) => {
|
|
328
|
+
const parts = token.split(".");
|
|
329
|
+
if (parts.length !== 3) {
|
|
330
|
+
throw new Error("Invalid JWT received");
|
|
331
|
+
}
|
|
332
|
+
const payloadSegment = parts[1];
|
|
333
|
+
if (!payloadSegment) {
|
|
334
|
+
throw new Error("JWT payload segment missing");
|
|
335
|
+
}
|
|
336
|
+
const padded = payloadSegment.padEnd(
|
|
337
|
+
payloadSegment.length + (4 - payloadSegment.length % 4) % 4,
|
|
338
|
+
"="
|
|
339
|
+
);
|
|
340
|
+
const decoded = Buffer.from(padded, "base64").toString("utf-8");
|
|
341
|
+
return JSON.parse(decoded);
|
|
342
|
+
};
|
|
343
|
+
var getCustomerIdFromToken = (token) => {
|
|
344
|
+
const payload = decodeJwtPayload(token);
|
|
345
|
+
const customerId = payload?.customer_id || payload?.customerId;
|
|
346
|
+
if (typeof customerId !== "string" || !customerId.trim()) {
|
|
347
|
+
throw new Error("Unable to determine customer_id from session token");
|
|
348
|
+
}
|
|
349
|
+
return customerId.trim();
|
|
350
|
+
};
|
|
351
|
+
var resolveSupportBundlesEndpoint = () => {
|
|
352
|
+
const fallback = `${getApiOrigin()}/v3/supportbundles`;
|
|
353
|
+
const explicit = process.env.SUPPORT_BUNDLES_ENDPOINT;
|
|
354
|
+
if (!explicit) {
|
|
355
|
+
return new URL(fallback);
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
return new URL(explicit);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
console.warn(
|
|
361
|
+
`[portal-components] invalid SUPPORT_BUNDLES_ENDPOINT, using fallback`,
|
|
362
|
+
error
|
|
363
|
+
);
|
|
364
|
+
return new URL(fallback);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
var listSupportBundles = defineServerAction({
|
|
368
|
+
id: "support/list-bundles",
|
|
369
|
+
description: "Fetches support bundles associated with the customer found in the portal session JWT.",
|
|
370
|
+
visibility: "customer",
|
|
371
|
+
tags: ["support", "bundles"],
|
|
372
|
+
async run({ token }, context) {
|
|
373
|
+
if (!token || typeof token !== "string") {
|
|
374
|
+
throw new Error("Support bundle listing requires a session token");
|
|
375
|
+
}
|
|
376
|
+
const payload = decodeJwtPayload(token);
|
|
377
|
+
const customerId = payload?.customer_id;
|
|
378
|
+
if (typeof customerId !== "string" || !customerId.trim()) {
|
|
379
|
+
throw new Error("Unable to determine customer_id from session token");
|
|
380
|
+
}
|
|
381
|
+
const url = resolveSupportBundlesEndpoint();
|
|
382
|
+
url.searchParams.set("customer_id", customerId.trim());
|
|
383
|
+
if (process.env.NODE_ENV !== "production") {
|
|
384
|
+
console.debug("[portal-components] fetching support bundles via %s", url);
|
|
385
|
+
}
|
|
386
|
+
const response = await authenticatedFetch(url.toString(), {
|
|
387
|
+
token,
|
|
388
|
+
headers: {
|
|
389
|
+
accept: "application/json"
|
|
390
|
+
},
|
|
391
|
+
signal: context?.signal
|
|
392
|
+
});
|
|
393
|
+
if (context?.signal?.aborted) {
|
|
394
|
+
throw new Error("Support bundles request was aborted");
|
|
395
|
+
}
|
|
396
|
+
if (!response.ok) {
|
|
397
|
+
throw new Error(
|
|
398
|
+
`Support bundles request failed (${response.status} ${response.statusText})`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
const raw = await response.json();
|
|
402
|
+
const rawRecord = raw && typeof raw === "object" ? raw : void 0;
|
|
403
|
+
const parseInsights = (raw2) => {
|
|
404
|
+
if (!Array.isArray(raw2)) return void 0;
|
|
405
|
+
return raw2.filter((i) => i && typeof i === "object").map((i) => ({
|
|
406
|
+
level: String(i.level ?? ""),
|
|
407
|
+
primary: String(i.primary ?? ""),
|
|
408
|
+
key: typeof i.key === "string" ? i.key : void 0,
|
|
409
|
+
detail: typeof i.detail === "string" ? i.detail : void 0
|
|
410
|
+
}));
|
|
411
|
+
};
|
|
412
|
+
const bundles = Array.isArray(
|
|
413
|
+
rawRecord?.supportBundles
|
|
414
|
+
) ? (rawRecord?.supportBundles).map((item) => {
|
|
415
|
+
if (!item || typeof item !== "object") {
|
|
416
|
+
return {
|
|
417
|
+
id: "",
|
|
418
|
+
createdAt: void 0,
|
|
419
|
+
status: void 0,
|
|
420
|
+
size: void 0,
|
|
421
|
+
instanceId: void 0,
|
|
422
|
+
insights: void 0,
|
|
423
|
+
metadata: void 0
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
const record = item;
|
|
427
|
+
return {
|
|
428
|
+
id: String(record.id ?? ""),
|
|
429
|
+
createdAt: typeof record.createdAt === "string" ? record.createdAt : void 0,
|
|
430
|
+
status: typeof record.status === "string" ? record.status : void 0,
|
|
431
|
+
size: typeof record.size === "number" ? record.size : void 0,
|
|
432
|
+
instanceId: typeof record.instanceId === "string" ? record.instanceId : void 0,
|
|
433
|
+
insights: parseInsights(record.insights),
|
|
434
|
+
metadata: record
|
|
435
|
+
};
|
|
436
|
+
}) : Array.isArray(raw) ? raw.map((item) => {
|
|
437
|
+
if (!item || typeof item !== "object") {
|
|
438
|
+
return {
|
|
439
|
+
id: "",
|
|
440
|
+
createdAt: void 0,
|
|
441
|
+
status: void 0,
|
|
442
|
+
size: void 0,
|
|
443
|
+
instanceId: void 0,
|
|
444
|
+
insights: void 0,
|
|
445
|
+
metadata: void 0
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
const record = item;
|
|
449
|
+
return {
|
|
450
|
+
id: String(record.id ?? ""),
|
|
451
|
+
createdAt: typeof record.createdAt === "string" ? record.createdAt : void 0,
|
|
452
|
+
status: typeof record.status === "string" ? record.status : void 0,
|
|
453
|
+
size: typeof record.size === "number" ? record.size : void 0,
|
|
454
|
+
instanceId: typeof record.instanceId === "string" ? record.instanceId : void 0,
|
|
455
|
+
insights: parseInsights(record.insights),
|
|
456
|
+
metadata: record
|
|
457
|
+
};
|
|
458
|
+
}) : [];
|
|
459
|
+
const totalCount = (() => {
|
|
460
|
+
if (rawRecord) {
|
|
461
|
+
if (typeof rawRecord.totalCount === "number" && Number.isFinite(rawRecord.totalCount)) {
|
|
462
|
+
return rawRecord.totalCount;
|
|
463
|
+
}
|
|
464
|
+
if (Array.isArray(rawRecord.supportBundles)) {
|
|
465
|
+
return rawRecord.supportBundles.length;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (Array.isArray(raw)) {
|
|
469
|
+
return raw.length;
|
|
470
|
+
}
|
|
471
|
+
return bundles.length;
|
|
472
|
+
})();
|
|
473
|
+
return {
|
|
474
|
+
bundles,
|
|
475
|
+
totalCount,
|
|
476
|
+
raw
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
var downloadSupportBundle = defineServerAction({
|
|
481
|
+
id: "support/download-bundle",
|
|
482
|
+
description: "Gets a signed URL for downloading a support bundle.",
|
|
483
|
+
visibility: "customer",
|
|
484
|
+
tags: ["support", "bundles", "download"],
|
|
485
|
+
async run({ token, bundleId }, context) {
|
|
486
|
+
if (!token || typeof token !== "string") {
|
|
487
|
+
throw new Error("Support bundle download requires a session token");
|
|
488
|
+
}
|
|
489
|
+
if (!bundleId || typeof bundleId !== "string") {
|
|
490
|
+
throw new Error("Support bundle download requires a bundle ID");
|
|
491
|
+
}
|
|
492
|
+
const payload = decodeJwtPayload(token);
|
|
493
|
+
const customerId = payload?.customer_id;
|
|
494
|
+
if (typeof customerId !== "string" || !customerId.trim()) {
|
|
495
|
+
throw new Error("Unable to determine customer_id from session token");
|
|
496
|
+
}
|
|
497
|
+
const endpoint = `${getApiOrigin()}/v3/supportbundle/${encodeURIComponent(bundleId)}/download?customer_id=${encodeURIComponent(customerId.trim())}`;
|
|
498
|
+
if (process.env.NODE_ENV !== "production") {
|
|
499
|
+
console.debug("[portal-components] getting support bundle download URL via %s", endpoint);
|
|
500
|
+
}
|
|
501
|
+
const response = await authenticatedFetch(endpoint, {
|
|
502
|
+
method: "GET",
|
|
503
|
+
token,
|
|
504
|
+
headers: {
|
|
505
|
+
accept: "application/json"
|
|
506
|
+
},
|
|
507
|
+
signal: context?.signal
|
|
508
|
+
});
|
|
509
|
+
if (!response.ok) {
|
|
510
|
+
const errorText = await response.text().catch(() => "");
|
|
511
|
+
throw new Error(
|
|
512
|
+
`Support bundle download URL request failed (${response.status} ${response.statusText}): ${errorText}`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
const data = await response.json();
|
|
516
|
+
const signedUrl = data?.signedUrl;
|
|
517
|
+
if (typeof signedUrl !== "string" || !signedUrl) {
|
|
518
|
+
throw new Error("Support bundle download response missing signedUrl");
|
|
519
|
+
}
|
|
520
|
+
return { signedUrl };
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
var deleteSupportBundle = defineServerAction({
|
|
524
|
+
id: "support/delete-bundle",
|
|
525
|
+
description: "Deletes a support bundle.",
|
|
526
|
+
visibility: "customer",
|
|
527
|
+
tags: ["support", "bundles", "delete"],
|
|
528
|
+
async run({ token, bundleId }, context) {
|
|
529
|
+
if (!token || typeof token !== "string") {
|
|
530
|
+
throw new Error("Support bundle deletion requires a session token");
|
|
531
|
+
}
|
|
532
|
+
if (!bundleId || typeof bundleId !== "string") {
|
|
533
|
+
throw new Error("Support bundle deletion requires a bundle ID");
|
|
534
|
+
}
|
|
535
|
+
const payload = decodeJwtPayload(token);
|
|
536
|
+
const customerId = payload?.customer_id;
|
|
537
|
+
if (typeof customerId !== "string" || !customerId.trim()) {
|
|
538
|
+
throw new Error("Unable to determine customer_id from session token");
|
|
539
|
+
}
|
|
540
|
+
const endpoint = `${getApiOrigin()}/v3/supportbundle/${encodeURIComponent(bundleId)}?customer_id=${encodeURIComponent(customerId.trim())}`;
|
|
541
|
+
if (process.env.NODE_ENV !== "production") {
|
|
542
|
+
console.debug("[portal-components] deleting support bundle via %s", endpoint);
|
|
543
|
+
}
|
|
544
|
+
const response = await authenticatedFetch(endpoint, {
|
|
545
|
+
method: "DELETE",
|
|
546
|
+
token,
|
|
547
|
+
headers: {
|
|
548
|
+
accept: "application/json"
|
|
549
|
+
},
|
|
550
|
+
signal: context?.signal
|
|
551
|
+
});
|
|
552
|
+
if (!response.ok) {
|
|
553
|
+
const errorText = await response.text().catch(() => "");
|
|
554
|
+
if (response.status === 404) {
|
|
555
|
+
throw new Error("Support bundle not found");
|
|
556
|
+
}
|
|
557
|
+
throw new Error(
|
|
558
|
+
`Support bundle deletion failed (${response.status} ${response.statusText}): ${errorText}`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return { success: true };
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
var uploadSupportBundle = defineServerAction({
|
|
565
|
+
id: "support/upload-bundle",
|
|
566
|
+
description: "Uploads a support bundle to the server.",
|
|
567
|
+
visibility: "customer",
|
|
568
|
+
tags: ["support", "bundles", "upload"],
|
|
569
|
+
async run({ token, appId, fileContent, contentLength }, context) {
|
|
570
|
+
if (!token || typeof token !== "string") {
|
|
571
|
+
throw new Error("Support bundle upload requires a session token");
|
|
572
|
+
}
|
|
573
|
+
if (!appId || typeof appId !== "string") {
|
|
574
|
+
throw new Error("Support bundle upload requires an app ID");
|
|
575
|
+
}
|
|
576
|
+
if (!fileContent || !(fileContent instanceof ArrayBuffer)) {
|
|
577
|
+
throw new Error("Support bundle upload requires file content");
|
|
578
|
+
}
|
|
579
|
+
const endpoint = `${getApiOrigin()}/v3/supportbundle/upload/${encodeURIComponent(appId)}`;
|
|
580
|
+
if (process.env.NODE_ENV !== "production") {
|
|
581
|
+
console.debug("[portal-components] uploading support bundle via %s", endpoint);
|
|
582
|
+
}
|
|
583
|
+
const response = await authenticatedFetch(endpoint, {
|
|
584
|
+
method: "POST",
|
|
585
|
+
token,
|
|
586
|
+
headers: {
|
|
587
|
+
"content-type": "application/gzip",
|
|
588
|
+
"content-length": String(contentLength)
|
|
589
|
+
},
|
|
590
|
+
body: fileContent,
|
|
591
|
+
signal: context?.signal
|
|
592
|
+
});
|
|
593
|
+
if (!response.ok) {
|
|
594
|
+
const errorText = await response.text().catch(() => "");
|
|
595
|
+
throw new Error(
|
|
596
|
+
`Support bundle upload failed (${response.status} ${response.statusText}): ${errorText}`
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
const data = await response.json();
|
|
600
|
+
return {
|
|
601
|
+
bundleId: data?.bundleId ?? data?.bundle_id ?? "",
|
|
602
|
+
slug: data?.slug ?? ""
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
var getSupportBundleUploadUrl = (appId) => {
|
|
607
|
+
return `${getApiOrigin()}/v3/supportbundle/upload/${encodeURIComponent(appId)}`;
|
|
608
|
+
};
|
|
609
|
+
var listReleases = defineServerAction({
|
|
610
|
+
id: "releases/list",
|
|
611
|
+
description: "Lists available releases for the authenticated customer.",
|
|
612
|
+
visibility: "customer",
|
|
613
|
+
tags: ["releases"],
|
|
614
|
+
async run({ token }, context) {
|
|
615
|
+
if (!token || typeof token !== "string") {
|
|
616
|
+
throw new Error("List releases requires a session token");
|
|
617
|
+
}
|
|
618
|
+
const endpoint = `${getApiOrigin()}/v3/release-history`;
|
|
619
|
+
console.log("[portal-components] listReleases request", {
|
|
620
|
+
endpoint
|
|
621
|
+
});
|
|
622
|
+
const response = await authenticatedFetch(endpoint, {
|
|
623
|
+
method: "GET",
|
|
624
|
+
token,
|
|
625
|
+
headers: {
|
|
626
|
+
accept: "application/json"
|
|
627
|
+
},
|
|
628
|
+
signal: context?.signal
|
|
629
|
+
});
|
|
630
|
+
const bodyText = await response.text().catch((error) => {
|
|
631
|
+
console.warn("[portal-components] listReleases read error", error);
|
|
632
|
+
return null;
|
|
633
|
+
});
|
|
634
|
+
console.log("[portal-components] listReleases response", response.status, bodyText);
|
|
635
|
+
if (!response.ok) {
|
|
636
|
+
throw new Error(
|
|
637
|
+
`List releases request failed (${response.status} ${response.statusText})`
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
status: response.status,
|
|
642
|
+
body: bodyText
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
var asRecord = (value) => {
|
|
647
|
+
if (value && typeof value === "object") {
|
|
648
|
+
return value;
|
|
649
|
+
}
|
|
650
|
+
return void 0;
|
|
651
|
+
};
|
|
652
|
+
var getValue = (record, key) => record ? record[key] : void 0;
|
|
653
|
+
var getString = (record, key) => {
|
|
654
|
+
const value = getValue(record, key);
|
|
655
|
+
return typeof value === "string" ? value : void 0;
|
|
656
|
+
};
|
|
657
|
+
var getBoolean = (record, key) => {
|
|
658
|
+
const value = getValue(record, key);
|
|
659
|
+
if (typeof value === "boolean") {
|
|
660
|
+
return value;
|
|
661
|
+
}
|
|
662
|
+
if (typeof value === "number") {
|
|
663
|
+
return value === 1;
|
|
664
|
+
}
|
|
665
|
+
if (typeof value === "string") {
|
|
666
|
+
const normalized = value.trim().toLowerCase();
|
|
667
|
+
if (["true", "1", "yes"].includes(normalized)) {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
if (["false", "0", "no"].includes(normalized)) {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return void 0;
|
|
675
|
+
};
|
|
676
|
+
var toDisplayValue = (value) => {
|
|
677
|
+
if (value === null || value === void 0) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
if (typeof value === "string") {
|
|
681
|
+
return value;
|
|
682
|
+
}
|
|
683
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
684
|
+
return String(value);
|
|
685
|
+
}
|
|
686
|
+
try {
|
|
687
|
+
return JSON.stringify(value);
|
|
688
|
+
} catch {
|
|
689
|
+
return String(value);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
var normalizeStringArray = (value) => {
|
|
693
|
+
if (Array.isArray(value)) {
|
|
694
|
+
const normalized = value.map(
|
|
695
|
+
(item) => typeof item === "string" ? item.trim() : ""
|
|
696
|
+
).filter((item) => item.length > 0);
|
|
697
|
+
return normalized.length ? normalized : void 0;
|
|
698
|
+
}
|
|
699
|
+
if (typeof value === "string") {
|
|
700
|
+
const normalized = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
701
|
+
return normalized.length ? normalized : void 0;
|
|
702
|
+
}
|
|
703
|
+
return void 0;
|
|
704
|
+
};
|
|
705
|
+
var normalizeLicenseFields = (input) => {
|
|
706
|
+
if (!input) {
|
|
707
|
+
return [];
|
|
708
|
+
}
|
|
709
|
+
if (Array.isArray(input)) {
|
|
710
|
+
return input.map((field, index) => {
|
|
711
|
+
if (!field || typeof field !== "object") {
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
const candidate = field;
|
|
715
|
+
const key = typeof candidate.key === "string" && candidate.key.trim().length ? candidate.key.trim() : typeof candidate.name === "string" && candidate.name.trim().length ? candidate.name.trim() : typeof candidate.label === "string" && candidate.label.trim().length ? candidate.label.trim() : `field-${index}`;
|
|
716
|
+
const label = typeof candidate.label === "string" && candidate.label.trim().length ? candidate.label.trim() : typeof candidate.name === "string" && candidate.name.trim().length ? candidate.name.trim() : key;
|
|
717
|
+
let value = candidate.value ?? candidate.data ?? candidate.content;
|
|
718
|
+
if ((value === void 0 || value === null) && typeof candidate.text === "string") {
|
|
719
|
+
value = candidate.text;
|
|
720
|
+
}
|
|
721
|
+
if ((value === void 0 || value === null) && typeof candidate.defaultValue === "string") {
|
|
722
|
+
value = candidate.defaultValue;
|
|
723
|
+
}
|
|
724
|
+
const isSecret = Boolean(
|
|
725
|
+
candidate.isSecret ?? candidate.secret ?? candidate.masked
|
|
726
|
+
);
|
|
727
|
+
const resolved = toDisplayValue(value);
|
|
728
|
+
return {
|
|
729
|
+
key,
|
|
730
|
+
label,
|
|
731
|
+
value: resolved,
|
|
732
|
+
isSecret
|
|
733
|
+
};
|
|
734
|
+
}).filter((field) => Boolean(field));
|
|
735
|
+
}
|
|
736
|
+
if (typeof input === "object") {
|
|
737
|
+
return Object.entries(input).map(
|
|
738
|
+
([key, value]) => {
|
|
739
|
+
let resolvedValue = value;
|
|
740
|
+
let isSecret = false;
|
|
741
|
+
if (value && typeof value === "object") {
|
|
742
|
+
const obj = value;
|
|
743
|
+
if ("value" in obj) {
|
|
744
|
+
resolvedValue = obj.value;
|
|
745
|
+
}
|
|
746
|
+
isSecret = Boolean(obj.isSecret ?? obj.secret ?? obj.masked);
|
|
747
|
+
}
|
|
748
|
+
const normalized = toDisplayValue(resolvedValue);
|
|
749
|
+
return {
|
|
750
|
+
key,
|
|
751
|
+
label: key,
|
|
752
|
+
value: normalized,
|
|
753
|
+
isSecret
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
return [];
|
|
759
|
+
};
|
|
760
|
+
var extractChannelNames = (input) => {
|
|
761
|
+
if (!Array.isArray(input)) {
|
|
762
|
+
return void 0;
|
|
763
|
+
}
|
|
764
|
+
const names = input.map((item) => {
|
|
765
|
+
if (typeof item === "string") {
|
|
766
|
+
return item.trim();
|
|
767
|
+
}
|
|
768
|
+
const record = asRecord(item);
|
|
769
|
+
if (!record) {
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
return getString(record, "name") ?? getString(record, "channelName") ?? getString(record, "channel") ?? getString(record, "channelSlug") ?? getString(record, "slug") ?? void 0;
|
|
773
|
+
}).filter((name) => Boolean(name && name.length));
|
|
774
|
+
return names.length ? names : void 0;
|
|
775
|
+
};
|
|
776
|
+
var normalizeEntitlementFields = (fieldsInput, valuesInput) => {
|
|
777
|
+
const valuesMap = /* @__PURE__ */ new Map();
|
|
778
|
+
const assignValue = (key, value) => {
|
|
779
|
+
if (!key) {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
valuesMap.set(key, toDisplayValue(value));
|
|
783
|
+
};
|
|
784
|
+
if (Array.isArray(valuesInput)) {
|
|
785
|
+
valuesInput.forEach((item) => {
|
|
786
|
+
const record = asRecord(item);
|
|
787
|
+
if (!record) {
|
|
788
|
+
if (typeof item === "string") {
|
|
789
|
+
assignValue(item, item);
|
|
790
|
+
}
|
|
146
791
|
return;
|
|
147
792
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
793
|
+
const key = getString(record, "name") ?? getString(record, "field") ?? getString(record, "title") ?? getString(record, "label") ?? getString(record, "slug") ?? (() => {
|
|
794
|
+
const idValue = getValue(record, "id");
|
|
795
|
+
if (typeof idValue === "string" || typeof idValue === "number") {
|
|
796
|
+
return String(idValue);
|
|
797
|
+
}
|
|
798
|
+
return void 0;
|
|
799
|
+
})();
|
|
800
|
+
const value = getValue(record, "value") ?? getValue(record, "currentValue") ?? getValue(record, "entitlementValue") ?? getValue(record, "content") ?? getValue(record, "data") ?? getValue(record, "defaultVal") ?? getValue(record, "defaultValue");
|
|
801
|
+
assignValue(key, value);
|
|
802
|
+
});
|
|
803
|
+
} else if (valuesInput && typeof valuesInput === "object") {
|
|
804
|
+
Object.entries(valuesInput).forEach(
|
|
805
|
+
([key, value]) => assignValue(key, value)
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
const normalized = [];
|
|
809
|
+
if (Array.isArray(fieldsInput)) {
|
|
810
|
+
fieldsInput.forEach((item, index) => {
|
|
811
|
+
const record = asRecord(item);
|
|
812
|
+
if (!record) {
|
|
813
|
+
return;
|
|
153
814
|
}
|
|
815
|
+
const baseKey = getString(record, "name") ?? getString(record, "field") ?? getString(record, "slug") ?? `entitlement-${index}`;
|
|
816
|
+
const key = `entitlement-${baseKey}`;
|
|
817
|
+
const label = getString(record, "title") ?? getString(record, "label") ?? baseKey;
|
|
818
|
+
const defaultValue = getString(record, "defaultVal") ?? getString(record, "default") ?? getString(record, "defaultValue");
|
|
819
|
+
const value = valuesMap.get(baseKey) ?? valuesMap.get(label) ?? defaultValue ?? null;
|
|
820
|
+
const isSecret = Boolean(
|
|
821
|
+
getBoolean(record, "secret") ?? getBoolean(record, "isSecret") ?? getBoolean(record, "masked")
|
|
822
|
+
);
|
|
823
|
+
normalized.push({
|
|
824
|
+
key,
|
|
825
|
+
label,
|
|
826
|
+
value,
|
|
827
|
+
isSecret
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
valuesMap.forEach((value, key) => {
|
|
832
|
+
const normalizedKey = `entitlement-${key}`;
|
|
833
|
+
if (!normalized.some((field) => field.key === normalizedKey)) {
|
|
834
|
+
normalized.push({
|
|
835
|
+
key: normalizedKey,
|
|
836
|
+
label: key,
|
|
837
|
+
value
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
return normalized;
|
|
842
|
+
};
|
|
843
|
+
var normalizeLicensePayload = (payload) => {
|
|
844
|
+
const payloadRecord = asRecord(payload);
|
|
845
|
+
const rootRecord = asRecord(getValue(payloadRecord, "license")) ?? asRecord(getValue(payloadRecord, "data")) ?? payloadRecord ?? {};
|
|
846
|
+
const sourceRecord = asRecord(getValue(rootRecord, "metadata")) ?? rootRecord;
|
|
847
|
+
const customer = asRecord(getValue(rootRecord, "customer")) ?? asRecord(getValue(sourceRecord, "customer")) ?? asRecord(getValue(payloadRecord, "customer")) ?? {};
|
|
848
|
+
let releaseChannels = normalizeStringArray(
|
|
849
|
+
getValue(rootRecord, "releaseChannels") ?? getValue(sourceRecord, "releaseChannels") ?? getValue(sourceRecord, "channels") ?? getValue(rootRecord, "channels") ?? getValue(sourceRecord, "channel") ?? getValue(rootRecord, "channel")
|
|
850
|
+
) ?? void 0;
|
|
851
|
+
if (!releaseChannels) {
|
|
852
|
+
releaseChannels = extractChannelNames(getValue(rootRecord, "channels")) ?? extractChannelNames(getValue(sourceRecord, "channels")) ?? void 0;
|
|
853
|
+
}
|
|
854
|
+
let installMethods = normalizeStringArray(
|
|
855
|
+
getValue(rootRecord, "installMethods") ?? getValue(sourceRecord, "installMethods") ?? getValue(sourceRecord, "install_options") ?? getValue(rootRecord, "install_options") ?? getValue(sourceRecord, "installOptions")
|
|
856
|
+
) ?? void 0;
|
|
857
|
+
if (!installMethods || installMethods.length === 0) {
|
|
858
|
+
const resolved = [];
|
|
859
|
+
const flag = (key) => getBoolean(rootRecord, key) ?? getBoolean(sourceRecord, key) ?? false;
|
|
860
|
+
if (flag("isKotsInstallEnabled")) {
|
|
861
|
+
resolved.push("Replicated KOTS");
|
|
862
|
+
}
|
|
863
|
+
if (flag("isHelmInstallEnabled")) {
|
|
864
|
+
resolved.push("Helm");
|
|
865
|
+
}
|
|
866
|
+
if (flag("isHelmAirgapEnabled")) {
|
|
867
|
+
resolved.push("Helm Airgap");
|
|
868
|
+
}
|
|
869
|
+
if (flag("isEmbeddedClusterDownloadEnabled") || flag("isEmbeddedClusterMultiNodeEnabled")) {
|
|
870
|
+
resolved.push("Embedded Cluster");
|
|
871
|
+
}
|
|
872
|
+
if (flag("isKurlInstallEnabled")) {
|
|
873
|
+
resolved.push("kURL");
|
|
874
|
+
}
|
|
875
|
+
if (flag("isGitopsSupported")) {
|
|
876
|
+
resolved.push("GitOps");
|
|
877
|
+
}
|
|
878
|
+
if (resolved.length) {
|
|
879
|
+
installMethods = Array.from(new Set(resolved));
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
const expiresAtSource = getValue(sourceRecord, "expiresAt") ?? getValue(sourceRecord, "expireAt") ?? getValue(sourceRecord, "expire_at") ?? getValue(sourceRecord, "expiration") ?? getValue(sourceRecord, "expirationDate") ?? getValue(sourceRecord, "expires_on") ?? getValue(rootRecord, "expiresAt") ?? getValue(rootRecord, "expireAt") ?? getValue(rootRecord, "expire_at") ?? getValue(rootRecord, "expiration");
|
|
883
|
+
const expiresAt = typeof expiresAtSource === "string" && expiresAtSource.trim().length ? expiresAtSource : expiresAtSource === null ? null : void 0;
|
|
884
|
+
const baseFields = normalizeLicenseFields(
|
|
885
|
+
getValue(rootRecord, "additionalFields") ?? getValue(sourceRecord, "additionalFields") ?? getValue(sourceRecord, "fields") ?? getValue(rootRecord, "fields") ?? getValue(payloadRecord, "fields") ?? getValue(payloadRecord, "additional_fields")
|
|
886
|
+
);
|
|
887
|
+
const entitlementFields = normalizeEntitlementFields(
|
|
888
|
+
getValue(rootRecord, "entitlementFields") ?? getValue(sourceRecord, "entitlementFields"),
|
|
889
|
+
getValue(rootRecord, "entitlementValues") ?? getValue(sourceRecord, "entitlementValues")
|
|
890
|
+
);
|
|
891
|
+
const fields = [
|
|
892
|
+
...baseFields,
|
|
893
|
+
...entitlementFields.filter(
|
|
894
|
+
(field) => !baseFields.some((existing) => existing.key === field.key)
|
|
895
|
+
)
|
|
896
|
+
];
|
|
897
|
+
const statusFromSource = getString(sourceRecord, "status") ?? getString(sourceRecord, "state");
|
|
898
|
+
const statusLabelFromSource = getString(sourceRecord, "statusLabel") ?? getString(sourceRecord, "stateLabel");
|
|
899
|
+
const expiredFlag = getBoolean(sourceRecord, "isExpired") ?? getBoolean(rootRecord, "isExpired");
|
|
900
|
+
const derivedStatus = statusFromSource ?? (typeof expiredFlag === "boolean" ? expiredFlag ? "expired" : "active" : void 0);
|
|
901
|
+
const statusLabel = statusLabelFromSource ?? (derivedStatus ? derivedStatus.charAt(0).toUpperCase() + derivedStatus.slice(1) : void 0);
|
|
902
|
+
const licenseType = getString(sourceRecord, "licenseType") ?? getString(rootRecord, "licenseType");
|
|
903
|
+
const status = derivedStatus;
|
|
904
|
+
const license = {
|
|
905
|
+
id: getString(rootRecord, "id") ?? getString(sourceRecord, "id") ?? getString(sourceRecord, "licenseId") ?? getString(customer, "licenseId") ?? void 0,
|
|
906
|
+
status,
|
|
907
|
+
statusLabel,
|
|
908
|
+
environment: getString(sourceRecord, "environment") ?? getString(sourceRecord, "tier") ?? licenseType ?? void 0,
|
|
909
|
+
expiresAt: expiresAt ?? null,
|
|
910
|
+
releaseChannels: releaseChannels ?? [
|
|
911
|
+
getString(rootRecord, "channelName") ?? getString(rootRecord, "channel") ?? void 0
|
|
912
|
+
].filter((value) => Boolean(value)),
|
|
913
|
+
installMethods,
|
|
914
|
+
installNotes: getString(sourceRecord, "installNotes"),
|
|
915
|
+
customerName: getString(sourceRecord, "customerName") ?? getString(customer, "name") ?? void 0,
|
|
916
|
+
customerId: getString(sourceRecord, "customerId") ?? getString(customer, "id") ?? getString(rootRecord, "customerId") ?? void 0,
|
|
917
|
+
customerOrganization: getString(customer, "organization") ?? getString(sourceRecord, "customerOrganization") ?? getString(rootRecord, "customerOrganization") ?? void 0,
|
|
918
|
+
fields
|
|
919
|
+
};
|
|
920
|
+
return license;
|
|
921
|
+
};
|
|
922
|
+
var fetchLicenseDetails = defineServerAction({
|
|
923
|
+
id: "license/fetch-details",
|
|
924
|
+
description: "Fetches the authenticated user's enterprise license details.",
|
|
925
|
+
visibility: "customer",
|
|
926
|
+
tags: ["license", "entitlements"],
|
|
927
|
+
async run({ token }, context) {
|
|
928
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
929
|
+
throw new Error("fetchLicenseDetails requires a non-empty token");
|
|
930
|
+
}
|
|
931
|
+
const endpoint = `${getApiOrigin()}/v3/license`;
|
|
932
|
+
const response = await authenticatedFetch(endpoint, {
|
|
933
|
+
method: "GET",
|
|
934
|
+
token,
|
|
935
|
+
headers: {
|
|
936
|
+
accept: "application/json"
|
|
937
|
+
},
|
|
938
|
+
signal: context?.signal
|
|
939
|
+
});
|
|
940
|
+
if (!response.ok) {
|
|
941
|
+
throw new Error(
|
|
942
|
+
`License request failed (${response.status} ${response.statusText})`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
const payload = await response.json();
|
|
946
|
+
const license = normalizeLicensePayload(payload);
|
|
947
|
+
return {
|
|
948
|
+
license,
|
|
949
|
+
raw: payload ?? null
|
|
154
950
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
var getSecurityInfo = defineServerAction({
|
|
954
|
+
id: "security/get-info",
|
|
955
|
+
description: "Fetches CVE security scan results for a specific release",
|
|
956
|
+
visibility: "customer",
|
|
957
|
+
tags: ["security", "cve"],
|
|
958
|
+
async run({ token, installType, channelSequence, isAirgap = false }, context) {
|
|
959
|
+
if (!token || typeof token !== "string") {
|
|
960
|
+
throw new Error("Security info request requires a session token");
|
|
961
|
+
}
|
|
962
|
+
const customerId = getCustomerIdFromToken(token);
|
|
963
|
+
const params = new URLSearchParams({
|
|
964
|
+
customer_id: customerId,
|
|
965
|
+
install_type: installType,
|
|
966
|
+
channel_sequence: channelSequence.toString(),
|
|
967
|
+
is_airgap: isAirgap.toString()
|
|
968
|
+
});
|
|
969
|
+
const url = `${getApiOrigin()}/v3/security-info?${params.toString()}`;
|
|
970
|
+
if (process.env.NODE_ENV !== "production") {
|
|
971
|
+
console.debug("[portal-components] fetching security info via %s", url);
|
|
972
|
+
}
|
|
973
|
+
const response = await authenticatedFetch(url, {
|
|
974
|
+
token,
|
|
975
|
+
headers: { accept: "application/json" },
|
|
976
|
+
signal: context?.signal
|
|
977
|
+
});
|
|
978
|
+
if (!response.ok) {
|
|
979
|
+
throw new Error(
|
|
980
|
+
`Security info request failed (${response.status} ${response.statusText})`
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
const data = await response.json();
|
|
984
|
+
return data;
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
var getSecurityInfoDiff = defineServerAction({
|
|
988
|
+
id: "security/get-info-diff",
|
|
989
|
+
description: "Fetches CVE diff between two releases showing fixed and added vulnerabilities",
|
|
990
|
+
visibility: "customer",
|
|
991
|
+
tags: ["security", "cve", "diff"],
|
|
992
|
+
async run({ token, installType, fromChannelSequence, toChannelSequence, isAirgap = false }, context) {
|
|
993
|
+
if (!token || typeof token !== "string") {
|
|
994
|
+
throw new Error("Security info diff request requires a session token");
|
|
995
|
+
}
|
|
996
|
+
const customerId = getCustomerIdFromToken(token);
|
|
997
|
+
const params = new URLSearchParams({
|
|
998
|
+
customer_id: customerId,
|
|
999
|
+
install_type: installType,
|
|
1000
|
+
from_channel_sequence: fromChannelSequence.toString(),
|
|
1001
|
+
to_channel_sequence: toChannelSequence.toString(),
|
|
1002
|
+
is_airgap: isAirgap.toString()
|
|
1003
|
+
});
|
|
1004
|
+
const url = `${getApiOrigin()}/v3/security-info-diff?${params.toString()}`;
|
|
1005
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1006
|
+
console.debug("[portal-components] fetching security info diff via %s", url);
|
|
1007
|
+
}
|
|
1008
|
+
const response = await authenticatedFetch(url, {
|
|
1009
|
+
token,
|
|
1010
|
+
headers: { accept: "application/json" },
|
|
1011
|
+
signal: context?.signal
|
|
1012
|
+
});
|
|
1013
|
+
if (!response.ok) {
|
|
1014
|
+
throw new Error(
|
|
1015
|
+
`Security info diff request failed (${response.status} ${response.statusText})`
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
const data = await response.json();
|
|
1019
|
+
return data;
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
var getSecurityInfoSBOM = defineServerAction({
|
|
1023
|
+
id: "security/get-sbom",
|
|
1024
|
+
description: "Fetches Software Bill of Materials (SBOM) for a specific release",
|
|
1025
|
+
visibility: "customer",
|
|
1026
|
+
tags: ["security", "sbom"],
|
|
1027
|
+
async run({ token, installType, channelSequence, isAirgap = false, unifiedSbom = true }, context) {
|
|
1028
|
+
if (!token || typeof token !== "string") {
|
|
1029
|
+
throw new Error("Security SBOM request requires a session token");
|
|
1030
|
+
}
|
|
1031
|
+
const customerId = getCustomerIdFromToken(token);
|
|
1032
|
+
const params = new URLSearchParams({
|
|
1033
|
+
customer_id: customerId,
|
|
1034
|
+
install_type: installType,
|
|
1035
|
+
channel_sequence: channelSequence.toString(),
|
|
1036
|
+
is_airgap: isAirgap.toString(),
|
|
1037
|
+
unified_sbom: unifiedSbom.toString()
|
|
1038
|
+
});
|
|
1039
|
+
const url = `${getApiOrigin()}/v3/security-info-sbom?${params.toString()}`;
|
|
1040
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1041
|
+
console.debug("[portal-components] fetching security SBOM via %s", url);
|
|
1042
|
+
}
|
|
1043
|
+
const response = await authenticatedFetch(url, {
|
|
1044
|
+
token,
|
|
1045
|
+
headers: { accept: "application/json" },
|
|
1046
|
+
signal: context?.signal
|
|
1047
|
+
});
|
|
1048
|
+
if (response.status === 204) {
|
|
1049
|
+
return { sboms: {} };
|
|
1050
|
+
}
|
|
1051
|
+
if (!response.ok) {
|
|
1052
|
+
throw new Error(
|
|
1053
|
+
`Security SBOM request failed (${response.status} ${response.statusText})`
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
const data = await response.json();
|
|
1057
|
+
return data;
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
var fetchCurrentUser = defineServerAction({
|
|
1061
|
+
id: "user/fetch-current",
|
|
1062
|
+
description: "Fetches the current user's profile information",
|
|
1063
|
+
visibility: "customer",
|
|
1064
|
+
tags: ["user", "profile"],
|
|
1065
|
+
async run({ token }, context) {
|
|
1066
|
+
if (!token || typeof token !== "string") {
|
|
1067
|
+
throw new Error("Fetch current user requires a session token");
|
|
1068
|
+
}
|
|
1069
|
+
const endpoint = `${getApiOrigin()}/v3/user`;
|
|
1070
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1071
|
+
console.debug("[portal-components] fetching current user via %s", endpoint);
|
|
1072
|
+
}
|
|
1073
|
+
const response = await authenticatedFetch(endpoint, {
|
|
1074
|
+
method: "GET",
|
|
1075
|
+
token,
|
|
1076
|
+
headers: { accept: "application/json" },
|
|
1077
|
+
signal: context?.signal
|
|
1078
|
+
});
|
|
1079
|
+
if (!response.ok) {
|
|
1080
|
+
throw new Error(
|
|
1081
|
+
`Fetch current user request failed (${response.status} ${response.statusText})`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
const data = await response.json();
|
|
1085
|
+
return {
|
|
1086
|
+
user: {
|
|
1087
|
+
emailAddress: data.emailAddress || "",
|
|
1088
|
+
firstName: data.firstName || "",
|
|
1089
|
+
lastName: data.lastName || ""
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
var updateUser = defineServerAction({
|
|
1095
|
+
id: "user/update",
|
|
1096
|
+
description: "Updates the current user's first and/or last name",
|
|
1097
|
+
visibility: "customer",
|
|
1098
|
+
tags: ["user", "profile"],
|
|
1099
|
+
async run({ token, firstName, lastName }, context) {
|
|
1100
|
+
if (!token || typeof token !== "string") {
|
|
1101
|
+
throw new Error("Update user requires a session token");
|
|
1102
|
+
}
|
|
1103
|
+
if (!firstName && !lastName) {
|
|
1104
|
+
throw new Error("At least one of firstName or lastName must be provided");
|
|
1105
|
+
}
|
|
1106
|
+
const endpoint = `${getApiOrigin()}/v3/user`;
|
|
1107
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1108
|
+
console.debug("[portal-components] updating user via %s", endpoint);
|
|
1109
|
+
}
|
|
1110
|
+
const body = {};
|
|
1111
|
+
if (firstName !== void 0) body.firstName = firstName;
|
|
1112
|
+
if (lastName !== void 0) body.lastName = lastName;
|
|
1113
|
+
const response = await authenticatedFetch(endpoint, {
|
|
1114
|
+
method: "POST",
|
|
1115
|
+
token,
|
|
1116
|
+
headers: {
|
|
1117
|
+
"content-type": "application/json",
|
|
1118
|
+
accept: "application/json"
|
|
1119
|
+
},
|
|
1120
|
+
body: JSON.stringify(body),
|
|
1121
|
+
signal: context?.signal
|
|
1122
|
+
});
|
|
1123
|
+
if (!response.ok) {
|
|
1124
|
+
const errorText = await response.text().catch(() => "");
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`Update user request failed (${response.status} ${response.statusText}): ${errorText}`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
return { success: true };
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1132
|
+
var fetchNotifications = defineServerAction({
|
|
1133
|
+
id: "notifications/fetch",
|
|
1134
|
+
description: "Fetches notification preferences for a specific team",
|
|
1135
|
+
visibility: "customer",
|
|
1136
|
+
tags: ["notifications", "user"],
|
|
1137
|
+
async run({ token, customerId }, context) {
|
|
1138
|
+
if (!token || typeof token !== "string") {
|
|
1139
|
+
throw new Error("Fetch notifications requires a session token");
|
|
1140
|
+
}
|
|
1141
|
+
if (!customerId || typeof customerId !== "string") {
|
|
1142
|
+
throw new Error("Fetch notifications requires a customerId");
|
|
1143
|
+
}
|
|
1144
|
+
const endpoint = `${getApiOrigin()}/v3/notifications?customer_id=${encodeURIComponent(customerId)}`;
|
|
1145
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1146
|
+
console.debug("[portal-components] fetching notifications via %s", endpoint);
|
|
1147
|
+
}
|
|
1148
|
+
const response = await authenticatedFetch(endpoint, {
|
|
1149
|
+
method: "GET",
|
|
1150
|
+
token,
|
|
1151
|
+
headers: { accept: "application/json" },
|
|
1152
|
+
signal: context?.signal
|
|
1153
|
+
});
|
|
1154
|
+
if (!response.ok) {
|
|
1155
|
+
throw new Error(
|
|
1156
|
+
`Fetch notifications request failed (${response.status} ${response.statusText})`
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
const data = await response.json();
|
|
1160
|
+
return {
|
|
1161
|
+
notifications: data.notifications || []
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
var updateNotifications = defineServerAction({
|
|
1166
|
+
id: "notifications/update",
|
|
1167
|
+
description: "Updates notification preferences for a specific team",
|
|
1168
|
+
visibility: "customer",
|
|
1169
|
+
tags: ["notifications", "user"],
|
|
1170
|
+
async run({ token, customerId, notifications }, context) {
|
|
1171
|
+
if (!token || typeof token !== "string") {
|
|
1172
|
+
throw new Error("Update notifications requires a session token");
|
|
1173
|
+
}
|
|
1174
|
+
if (!customerId || typeof customerId !== "string") {
|
|
1175
|
+
throw new Error("Update notifications requires a customerId");
|
|
1176
|
+
}
|
|
1177
|
+
if (!Array.isArray(notifications)) {
|
|
1178
|
+
throw new Error("Update notifications requires a notifications array");
|
|
1179
|
+
}
|
|
1180
|
+
const endpoint = `${getApiOrigin()}/v3/notifications?customer_id=${encodeURIComponent(customerId)}`;
|
|
1181
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1182
|
+
console.debug("[portal-components] updating notifications via %s", endpoint);
|
|
1183
|
+
}
|
|
1184
|
+
const response = await authenticatedFetch(endpoint, {
|
|
1185
|
+
method: "PUT",
|
|
1186
|
+
token,
|
|
1187
|
+
headers: {
|
|
1188
|
+
"content-type": "application/json",
|
|
1189
|
+
accept: "application/json"
|
|
1190
|
+
},
|
|
1191
|
+
body: JSON.stringify({ notifications }),
|
|
1192
|
+
signal: context?.signal
|
|
1193
|
+
});
|
|
1194
|
+
if (!response.ok) {
|
|
1195
|
+
const errorText = await response.text().catch(() => "");
|
|
1196
|
+
throw new Error(
|
|
1197
|
+
`Update notifications request failed (${response.status} ${response.statusText}): ${errorText}`
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
const data = await response.json();
|
|
1201
|
+
return {
|
|
1202
|
+
notifications: data.notifications || []
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
var ShieldIcon = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1207
|
+
"svg",
|
|
1208
|
+
{
|
|
1209
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1210
|
+
viewBox: "0 0 24 24",
|
|
1211
|
+
fill: "none",
|
|
1212
|
+
stroke: "currentColor",
|
|
1213
|
+
strokeWidth: 2,
|
|
1214
|
+
strokeLinecap: "round",
|
|
1215
|
+
strokeLinejoin: "round",
|
|
1216
|
+
"aria-hidden": "true",
|
|
1217
|
+
...props,
|
|
1218
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" })
|
|
1219
|
+
}
|
|
1220
|
+
);
|
|
1221
|
+
var CalendarIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1222
|
+
"svg",
|
|
1223
|
+
{
|
|
1224
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1225
|
+
viewBox: "0 0 24 24",
|
|
1226
|
+
fill: "none",
|
|
1227
|
+
stroke: "currentColor",
|
|
1228
|
+
strokeWidth: 2,
|
|
1229
|
+
strokeLinecap: "round",
|
|
1230
|
+
strokeLinejoin: "round",
|
|
1231
|
+
"aria-hidden": "true",
|
|
1232
|
+
...props,
|
|
1233
|
+
children: [
|
|
1234
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2v4" }),
|
|
1235
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 2v4" }),
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: 18, height: 18, x: 3, y: 4, rx: 2 }),
|
|
1237
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 10h18" })
|
|
1238
|
+
]
|
|
1239
|
+
}
|
|
1240
|
+
);
|
|
1241
|
+
var DownloadIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1242
|
+
"svg",
|
|
1243
|
+
{
|
|
1244
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1245
|
+
viewBox: "0 0 24 24",
|
|
1246
|
+
fill: "none",
|
|
1247
|
+
stroke: "currentColor",
|
|
1248
|
+
strokeWidth: 2,
|
|
1249
|
+
strokeLinecap: "round",
|
|
1250
|
+
strokeLinejoin: "round",
|
|
1251
|
+
"aria-hidden": "true",
|
|
1252
|
+
...props,
|
|
1253
|
+
children: [
|
|
1254
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 17V3" }),
|
|
1255
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 11 6 6 6-6" }),
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 21H5" })
|
|
1257
|
+
]
|
|
1258
|
+
}
|
|
1259
|
+
);
|
|
1260
|
+
var BuildingIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1261
|
+
"svg",
|
|
1262
|
+
{
|
|
1263
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1264
|
+
viewBox: "0 0 24 24",
|
|
1265
|
+
fill: "none",
|
|
1266
|
+
stroke: "currentColor",
|
|
1267
|
+
strokeWidth: 2,
|
|
1268
|
+
strokeLinecap: "round",
|
|
1269
|
+
strokeLinejoin: "round",
|
|
1270
|
+
"aria-hidden": "true",
|
|
1271
|
+
...props,
|
|
1272
|
+
children: [
|
|
1273
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: 16, height: 20, x: 4, y: 2, rx: 2, ry: 2 }),
|
|
1274
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 22v-4h6v4" }),
|
|
1275
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 6h.01" }),
|
|
1276
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 6h.01" }),
|
|
1277
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 6h.01" }),
|
|
1278
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 10h.01" }),
|
|
1279
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 14h.01" }),
|
|
1280
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 10h.01" }),
|
|
1281
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 14h.01" }),
|
|
1282
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 10h.01" }),
|
|
1283
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 14h.01" })
|
|
1284
|
+
]
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
var CheckIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1288
|
+
"svg",
|
|
1289
|
+
{
|
|
1290
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1291
|
+
viewBox: "0 0 24 24",
|
|
1292
|
+
fill: "none",
|
|
1293
|
+
stroke: "currentColor",
|
|
1294
|
+
strokeWidth: 2,
|
|
1295
|
+
strokeLinecap: "round",
|
|
1296
|
+
strokeLinejoin: "round",
|
|
1297
|
+
"aria-hidden": "true",
|
|
1298
|
+
...props,
|
|
1299
|
+
children: [
|
|
1300
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21.8 10A10 10 0 1 1 17 3.33" }),
|
|
1301
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 11 3 3L22 4" })
|
|
1302
|
+
]
|
|
1303
|
+
}
|
|
1304
|
+
);
|
|
1305
|
+
var formatExpiration = (value) => {
|
|
1306
|
+
if (!value || value === "never") {
|
|
1307
|
+
return "Does not expire";
|
|
1308
|
+
}
|
|
1309
|
+
const date = new Date(value);
|
|
1310
|
+
if (Number.isNaN(date.getTime())) {
|
|
1311
|
+
return value;
|
|
1312
|
+
}
|
|
1313
|
+
return date.toLocaleDateString(void 0, {
|
|
1314
|
+
year: "numeric",
|
|
1315
|
+
month: "short",
|
|
1316
|
+
day: "numeric"
|
|
1317
|
+
});
|
|
1318
|
+
};
|
|
1319
|
+
var maskValue = (value, isSecret) => {
|
|
1320
|
+
if (isSecret) {
|
|
1321
|
+
return "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
1322
|
+
}
|
|
1323
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
1324
|
+
return value;
|
|
1325
|
+
}
|
|
1326
|
+
return "No value set";
|
|
1327
|
+
};
|
|
1328
|
+
var getFieldTextClass = (value) => {
|
|
1329
|
+
if (value === "does-not-expire") {
|
|
1330
|
+
return "text-gray-500";
|
|
1331
|
+
}
|
|
1332
|
+
return value && value.trim().length > 0 ? "text-gray-500" : "text-gray-300";
|
|
1333
|
+
};
|
|
1334
|
+
var InfoRow = ({
|
|
1335
|
+
icon,
|
|
1336
|
+
title,
|
|
1337
|
+
children
|
|
1338
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3", children: [
|
|
1339
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-gray-900", children: icon }),
|
|
1340
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1341
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-medium text-gray-900", children: title }),
|
|
1342
|
+
children
|
|
1343
|
+
] })
|
|
1344
|
+
] });
|
|
1345
|
+
var renderInstallOrChannel = (values) => {
|
|
1346
|
+
if (!values || values.length === 0) {
|
|
1347
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Not specified" });
|
|
1348
|
+
}
|
|
1349
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: values.join(", ") });
|
|
1350
|
+
};
|
|
1351
|
+
var buildPrimaryRows = (license) => {
|
|
1352
|
+
const rows = [];
|
|
1353
|
+
rows.push({
|
|
1354
|
+
key: "status",
|
|
1355
|
+
node: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1356
|
+
InfoRow,
|
|
158
1357
|
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
"w-full max-w-md rounded-3xl border border-white/15 bg-slate-950/80 p-10 shadow-[0_25px_70px_rgba(5,7,11,0.65)] backdrop-blur",
|
|
162
|
-
"text-white transition-shadow",
|
|
163
|
-
className
|
|
164
|
-
].filter(Boolean).join(" "),
|
|
165
|
-
onSubmit: handleSubmit,
|
|
166
|
-
...props,
|
|
1358
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(ShieldIcon, { className: "h-5 w-5" }),
|
|
1359
|
+
title: "License Status",
|
|
167
1360
|
children: [
|
|
168
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
169
|
-
|
|
170
|
-
/* @__PURE__ */ jsxRuntime.
|
|
171
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold uppercase tracking-[0.35em] text-white/65", children: "Enterprise Portal" }),
|
|
172
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mt-3 text-3xl font-semibold tracking-tight", children: title }),
|
|
173
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-white/70", children: description })
|
|
174
|
-
] })
|
|
1361
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center text-sm text-gray-600", children: [
|
|
1362
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "mr-1.5 h-4 w-4 text-green-500" }),
|
|
1363
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: license.statusLabel ?? (license.status ? license.status.charAt(0).toUpperCase() + license.status.slice(1) : "Unknown") })
|
|
175
1364
|
] }),
|
|
176
|
-
/* @__PURE__ */ jsxRuntime.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
1365
|
+
license.environment ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: license.environment }) : null
|
|
1366
|
+
]
|
|
1367
|
+
}
|
|
1368
|
+
)
|
|
1369
|
+
});
|
|
1370
|
+
rows.push({
|
|
1371
|
+
key: "expiration",
|
|
1372
|
+
node: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1373
|
+
InfoRow,
|
|
1374
|
+
{
|
|
1375
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { className: "h-5 w-5" }),
|
|
1376
|
+
title: "Expiration Date",
|
|
1377
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: formatExpiration(license.expiresAt) })
|
|
1378
|
+
}
|
|
1379
|
+
)
|
|
1380
|
+
});
|
|
1381
|
+
rows.push({
|
|
1382
|
+
key: "channels",
|
|
1383
|
+
node: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1384
|
+
InfoRow,
|
|
1385
|
+
{
|
|
1386
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(ShieldIcon, { className: "h-5 w-5" }),
|
|
1387
|
+
title: "Release Channel(s)",
|
|
1388
|
+
children: renderInstallOrChannel(license.releaseChannels)
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
});
|
|
1392
|
+
rows.push({
|
|
1393
|
+
key: "installs",
|
|
1394
|
+
node: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1395
|
+
InfoRow,
|
|
1396
|
+
{
|
|
1397
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, { className: "h-5 w-5" }),
|
|
1398
|
+
title: "Install Options",
|
|
1399
|
+
children: renderInstallOrChannel(license.installMethods)
|
|
1400
|
+
}
|
|
1401
|
+
)
|
|
1402
|
+
});
|
|
1403
|
+
rows.push({
|
|
1404
|
+
key: "customer",
|
|
1405
|
+
node: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1406
|
+
InfoRow,
|
|
1407
|
+
{
|
|
1408
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(BuildingIcon, { className: "h-5 w-5" }),
|
|
1409
|
+
title: "Customer Name",
|
|
1410
|
+
children: [
|
|
1411
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: license.customerName ?? "Unknown customer" }),
|
|
1412
|
+
license.customerId ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-400", children: [
|
|
1413
|
+
"Customer ID: ",
|
|
1414
|
+
license.customerId
|
|
1415
|
+
] }) : null
|
|
1416
|
+
]
|
|
1417
|
+
}
|
|
1418
|
+
)
|
|
1419
|
+
});
|
|
1420
|
+
return rows;
|
|
1421
|
+
};
|
|
1422
|
+
var renderFields = (fields) => {
|
|
1423
|
+
if (!fields.length) {
|
|
1424
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No additional fields available." });
|
|
1425
|
+
}
|
|
1426
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
1427
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: field.label }),
|
|
1428
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1429
|
+
"p",
|
|
1430
|
+
{
|
|
1431
|
+
className: `mt-1 break-words text-sm ${getFieldTextClass(
|
|
1432
|
+
field.value
|
|
1433
|
+
)}`,
|
|
1434
|
+
children: maskValue(field.value, field.isSecret)
|
|
1435
|
+
}
|
|
1436
|
+
)
|
|
1437
|
+
] }, field.key)) });
|
|
1438
|
+
};
|
|
1439
|
+
var LicenseDetails = async ({
|
|
1440
|
+
token,
|
|
1441
|
+
title = "License Details",
|
|
1442
|
+
description = "View your enterprise license details"
|
|
1443
|
+
}) => {
|
|
1444
|
+
if (typeof token !== "string" || token.trim().length === 0) {
|
|
1445
|
+
throw new Error("LicenseDetails component requires a non-empty token");
|
|
1446
|
+
}
|
|
1447
|
+
const response = await fetchLicenseDetails.run({ token });
|
|
1448
|
+
console.debug("[portal-components] license response", response.raw);
|
|
1449
|
+
const { license } = response;
|
|
1450
|
+
const rows = buildPrimaryRows(license);
|
|
1451
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-3xl border border-gray-100 bg-white p-8 shadow-[0_18px_45px_rgba(17,24,39,0.08)]", children: [
|
|
1452
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col border-b border-gray-100 pb-6", children: [
|
|
1453
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-900", children: title }),
|
|
1454
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-gray-600", children: description }) : null
|
|
1455
|
+
] }),
|
|
1456
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 space-y-6", children: [
|
|
1457
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-gray-100 bg-white p-6 sm:p-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: rows.map((row) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: row.node }, row.key)) }) }),
|
|
1458
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-gray-100 bg-white p-6 sm:p-8", children: [
|
|
1459
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mb-4 text-lg font-medium text-gray-900", children: "Additional License Fields" }),
|
|
1460
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: renderFields(license.fields ?? []) })
|
|
1461
|
+
] })
|
|
1462
|
+
] })
|
|
1463
|
+
] });
|
|
1464
|
+
};
|
|
1465
|
+
var defaultHiddenLabels = ["Download"];
|
|
1466
|
+
var defaultTopNavLinks = [
|
|
1467
|
+
{
|
|
1468
|
+
label: "Dashboard",
|
|
1469
|
+
href: "/",
|
|
1470
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1471
|
+
"svg",
|
|
1472
|
+
{
|
|
1473
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1474
|
+
viewBox: "0 0 24 24",
|
|
1475
|
+
className: "h-4 w-4",
|
|
1476
|
+
fill: "none",
|
|
1477
|
+
stroke: "currentColor",
|
|
1478
|
+
strokeWidth: "1.5",
|
|
1479
|
+
children: [
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 13h6V3H4z" }),
|
|
1481
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 21h6V3h-6z" })
|
|
1482
|
+
]
|
|
1483
|
+
}
|
|
1484
|
+
)
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
label: "Download",
|
|
1488
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1489
|
+
"svg",
|
|
1490
|
+
{
|
|
1491
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1492
|
+
viewBox: "0 0 24 24",
|
|
1493
|
+
className: "h-4 w-4",
|
|
1494
|
+
fill: "none",
|
|
1495
|
+
stroke: "currentColor",
|
|
1496
|
+
strokeWidth: "1.5",
|
|
1497
|
+
children: [
|
|
1498
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3v12" }),
|
|
1499
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 11 5 5 5-5" }),
|
|
1500
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 21h14" })
|
|
1501
|
+
]
|
|
1502
|
+
}
|
|
1503
|
+
)
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
label: "Install",
|
|
1507
|
+
href: "/install",
|
|
1508
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1509
|
+
"svg",
|
|
1510
|
+
{
|
|
1511
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1512
|
+
viewBox: "0 0 24 24",
|
|
1513
|
+
className: "h-4 w-4",
|
|
1514
|
+
fill: "none",
|
|
1515
|
+
stroke: "currentColor",
|
|
1516
|
+
strokeWidth: "1.5",
|
|
1517
|
+
children: [
|
|
1518
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14" }),
|
|
1519
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12h14" })
|
|
1520
|
+
]
|
|
1521
|
+
}
|
|
1522
|
+
)
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
label: "Update",
|
|
1526
|
+
href: "/update",
|
|
1527
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1528
|
+
"svg",
|
|
1529
|
+
{
|
|
1530
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1531
|
+
viewBox: "0 0 24 24",
|
|
1532
|
+
className: "h-4 w-4",
|
|
1533
|
+
fill: "none",
|
|
1534
|
+
stroke: "currentColor",
|
|
1535
|
+
strokeWidth: "1.5",
|
|
1536
|
+
children: [
|
|
1537
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4v6h6" }),
|
|
1538
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 20v-6h-6" }),
|
|
1539
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 10c1.5-4 6-6 10-4m6 4c-1.5 4-6 6-10 4" })
|
|
1540
|
+
]
|
|
1541
|
+
}
|
|
1542
|
+
)
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
label: "Release History",
|
|
1546
|
+
href: "/release-history",
|
|
1547
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1548
|
+
"svg",
|
|
1549
|
+
{
|
|
1550
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1551
|
+
viewBox: "0 0 24 24",
|
|
1552
|
+
className: "h-4 w-4",
|
|
1553
|
+
fill: "none",
|
|
1554
|
+
stroke: "currentColor",
|
|
1555
|
+
strokeWidth: "1.5",
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 8v4l3 2" }),
|
|
1558
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" })
|
|
1559
|
+
]
|
|
1560
|
+
}
|
|
1561
|
+
)
|
|
1562
|
+
},
|
|
1563
|
+
{
|
|
1564
|
+
label: "License",
|
|
1565
|
+
href: "/license",
|
|
1566
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1567
|
+
"svg",
|
|
1568
|
+
{
|
|
1569
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1570
|
+
viewBox: "0 0 24 24",
|
|
1571
|
+
className: "h-4 w-4",
|
|
1572
|
+
fill: "none",
|
|
1573
|
+
stroke: "currentColor",
|
|
1574
|
+
strokeWidth: "1.5",
|
|
1575
|
+
children: [
|
|
1576
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "14", height: "18", x: "5", y: "3", rx: "2" }),
|
|
1577
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 7h6" }),
|
|
1578
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 11h6" }),
|
|
1579
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 15h6" })
|
|
1580
|
+
]
|
|
1581
|
+
}
|
|
1582
|
+
)
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
label: "Support",
|
|
1586
|
+
href: "/support",
|
|
1587
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1588
|
+
"svg",
|
|
1589
|
+
{
|
|
1590
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1591
|
+
viewBox: "0 0 24 24",
|
|
1592
|
+
className: "h-4 w-4",
|
|
1593
|
+
fill: "none",
|
|
1594
|
+
stroke: "currentColor",
|
|
1595
|
+
strokeWidth: "1.5",
|
|
1596
|
+
children: [
|
|
1597
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 16a6 6 0 1 0-12 0v2h12Z" }),
|
|
1598
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "7", r: "4" })
|
|
1599
|
+
]
|
|
1600
|
+
}
|
|
1601
|
+
)
|
|
1602
|
+
}
|
|
1603
|
+
];
|
|
1604
|
+
var orderLinks = (links, order) => {
|
|
1605
|
+
if (!order || order.length === 0) {
|
|
1606
|
+
return links;
|
|
1607
|
+
}
|
|
1608
|
+
const orderMap = new Map(order.map((label, index) => [label, index]));
|
|
1609
|
+
return links.map((link, index) => ({
|
|
1610
|
+
link,
|
|
1611
|
+
originalIndex: index,
|
|
1612
|
+
orderIndex: orderMap.has(link.label) ? orderMap.get(link.label) : order.length + index
|
|
1613
|
+
})).sort((a, b) => {
|
|
1614
|
+
if (a.orderIndex === b.orderIndex) {
|
|
1615
|
+
return a.originalIndex - b.originalIndex;
|
|
1616
|
+
}
|
|
1617
|
+
return a.orderIndex - b.orderIndex;
|
|
1618
|
+
}).map((item) => item.link);
|
|
1619
|
+
};
|
|
1620
|
+
var TopNav = async ({
|
|
1621
|
+
links,
|
|
1622
|
+
hiddenLabels,
|
|
1623
|
+
additionalLinks,
|
|
1624
|
+
order,
|
|
1625
|
+
userMenuLabel,
|
|
1626
|
+
activeLabel,
|
|
1627
|
+
customerName,
|
|
1628
|
+
customers,
|
|
1629
|
+
currentCustomerId,
|
|
1630
|
+
onChangeTeam,
|
|
1631
|
+
userMenuChildren
|
|
1632
|
+
}) => {
|
|
1633
|
+
const displayLabel = userMenuLabel || (customerName ? `Team: ${customerName}` : "Team: Example");
|
|
1634
|
+
let logo;
|
|
1635
|
+
let brandTitle;
|
|
1636
|
+
let customColor1;
|
|
1637
|
+
let customColor2;
|
|
1638
|
+
const normalizeColor = (color) => {
|
|
1639
|
+
if (!color || typeof color !== "string") {
|
|
1640
|
+
return void 0;
|
|
1641
|
+
}
|
|
1642
|
+
const trimmed = color.trim();
|
|
1643
|
+
if (/^#?[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/.test(trimmed)) {
|
|
1644
|
+
return trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
|
|
1645
|
+
}
|
|
1646
|
+
return trimmed;
|
|
1647
|
+
};
|
|
1648
|
+
try {
|
|
1649
|
+
const branding = await fetchCustomBranding();
|
|
1650
|
+
if (branding.brandingData) {
|
|
1651
|
+
const decoded = buffer.Buffer.from(branding.brandingData, "base64").toString(
|
|
1652
|
+
"utf-8"
|
|
1653
|
+
);
|
|
1654
|
+
try {
|
|
1655
|
+
const parsed = JSON.parse(decoded);
|
|
1656
|
+
if (parsed?.logo && typeof parsed.logo === "string") {
|
|
1657
|
+
logo = parsed.logo;
|
|
1658
|
+
}
|
|
1659
|
+
if (parsed?.title && typeof parsed.title === "string") {
|
|
1660
|
+
const normalizedTitle = parsed.title.trim();
|
|
1661
|
+
if (normalizedTitle) {
|
|
1662
|
+
brandTitle = normalizedTitle;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
if (parsed?.customColor1 && typeof parsed.customColor1 === "string") {
|
|
1666
|
+
customColor1 = normalizeColor(parsed.customColor1);
|
|
1667
|
+
}
|
|
1668
|
+
if (parsed?.customColor2 && typeof parsed.customColor2 === "string") {
|
|
1669
|
+
customColor2 = normalizeColor(parsed.customColor2);
|
|
1670
|
+
}
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
console.debug(
|
|
1673
|
+
"[portal-components] unable to parse branding JSON",
|
|
1674
|
+
error
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
} else {
|
|
1678
|
+
console.debug("[portal-components] branding", branding);
|
|
1679
|
+
}
|
|
1680
|
+
} catch (error) {
|
|
1681
|
+
console.debug("[portal-components] branding fetch failed", error);
|
|
1682
|
+
}
|
|
1683
|
+
const baseLinks = links ?? defaultTopNavLinks;
|
|
1684
|
+
const computedHiddenLabels = hiddenLabels ? hiddenLabels : links ? void 0 : defaultHiddenLabels;
|
|
1685
|
+
const hiddenSet = computedHiddenLabels ? new Set(computedHiddenLabels) : null;
|
|
1686
|
+
let resolvedLinks = baseLinks.filter(
|
|
1687
|
+
(link) => !hiddenSet?.has(link.label)
|
|
1688
|
+
);
|
|
1689
|
+
if (additionalLinks?.length) {
|
|
1690
|
+
resolvedLinks = [...resolvedLinks, ...additionalLinks];
|
|
1691
|
+
}
|
|
1692
|
+
resolvedLinks = orderLinks(resolvedLinks, order);
|
|
1693
|
+
const gradientStart = customColor1 ?? "rgb(235, 102, 88)";
|
|
1694
|
+
const gradientEnd = customColor2 ?? customColor1 ?? "rgb(184, 83, 71)";
|
|
1695
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1696
|
+
"div",
|
|
1697
|
+
{
|
|
1698
|
+
className: "relative flex h-[165px] w-full items-start justify-center",
|
|
1699
|
+
style: {
|
|
1700
|
+
backgroundImage: `linear-gradient(to top, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0) 33%), linear-gradient(${gradientStart}, ${gradientEnd})`,
|
|
1701
|
+
backgroundRepeat: "no-repeat",
|
|
1702
|
+
backgroundSize: "100% 100%"
|
|
1703
|
+
},
|
|
1704
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mt-[30px] w-full max-w-[1248px] px-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[135px] flex-col justify-between space-y-4 rounded bg-[#ffffffe6] px-6 pt-6 pb-4 shadow-[0_10px_60px_rgba(16,16,16,0.35)]", children: [
|
|
1705
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1706
|
+
logo || brandTitle ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1707
|
+
logo ? (
|
|
1708
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
1709
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1710
|
+
"img",
|
|
1711
|
+
{
|
|
1712
|
+
src: logo,
|
|
1713
|
+
alt: "Portal logo",
|
|
1714
|
+
className: "object-contain",
|
|
1715
|
+
style: {
|
|
1716
|
+
maxWidth: "240px",
|
|
1717
|
+
maxHeight: "48px"
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
)
|
|
1721
|
+
) : null,
|
|
1722
|
+
brandTitle ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-lg font-semibold text-gray-900", children: brandTitle }) : null
|
|
1723
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
|
|
1724
|
+
/* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group relative", children: [
|
|
1725
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer items-center gap-2 rounded-lg bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 list-none", children: [
|
|
1726
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1727
|
+
"svg",
|
|
1728
|
+
{
|
|
1729
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1730
|
+
width: "16",
|
|
1731
|
+
height: "16",
|
|
1732
|
+
viewBox: "0 0 24 24",
|
|
1733
|
+
fill: "none",
|
|
1734
|
+
stroke: "currentColor",
|
|
1735
|
+
strokeWidth: "2",
|
|
1736
|
+
strokeLinecap: "round",
|
|
1737
|
+
strokeLinejoin: "round",
|
|
1738
|
+
className: "text-gray-500",
|
|
1739
|
+
children: [
|
|
1740
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }),
|
|
1741
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "7", r: "4" })
|
|
1742
|
+
]
|
|
1743
|
+
}
|
|
1744
|
+
),
|
|
1745
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: displayLabel }),
|
|
1746
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1747
|
+
"svg",
|
|
1748
|
+
{
|
|
1749
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1750
|
+
width: "16",
|
|
1751
|
+
height: "16",
|
|
1752
|
+
viewBox: "0 0 24 24",
|
|
1753
|
+
fill: "none",
|
|
1754
|
+
stroke: "currentColor",
|
|
1755
|
+
strokeWidth: "2",
|
|
1756
|
+
strokeLinecap: "round",
|
|
1757
|
+
strokeLinejoin: "round",
|
|
1758
|
+
className: "text-gray-500",
|
|
1759
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
|
|
1760
|
+
}
|
|
1761
|
+
)
|
|
1762
|
+
] }),
|
|
1763
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 mt-2 w-48 rounded-md border border-gray-200 bg-white py-2 text-sm text-gray-700 shadow-lg z-50", children: [
|
|
1764
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1765
|
+
"a",
|
|
1766
|
+
{
|
|
1767
|
+
href: "/user-settings",
|
|
1768
|
+
className: "block w-full px-4 py-2 text-left hover:bg-gray-100",
|
|
1769
|
+
children: "User settings"
|
|
1770
|
+
}
|
|
1771
|
+
),
|
|
1772
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1773
|
+
"a",
|
|
1774
|
+
{
|
|
1775
|
+
href: "/team-settings",
|
|
1776
|
+
className: "block w-full px-4 py-2 text-left hover:bg-gray-100",
|
|
1777
|
+
children: "Team settings"
|
|
1778
|
+
}
|
|
1779
|
+
),
|
|
1780
|
+
userMenuChildren,
|
|
1781
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1782
|
+
"a",
|
|
1783
|
+
{
|
|
1784
|
+
href: "/?expired=1",
|
|
1785
|
+
className: "block w-full px-4 py-2 text-left hover:bg-gray-100",
|
|
1786
|
+
children: "Logout"
|
|
1787
|
+
}
|
|
1788
|
+
)
|
|
1789
|
+
] })
|
|
1790
|
+
] })
|
|
1791
|
+
] }),
|
|
1792
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-3 border-b border-gray-200 pb-2 text-sm font-medium text-gray-500", children: resolvedLinks.map(({ label, icon, href }) => {
|
|
1793
|
+
const isActive = activeLabel === label;
|
|
1794
|
+
const className = `flex items-center gap-2 px-4 py-1 transition text-gray-500 ${isActive ? "underline underline-offset-8 decoration-2" : ""}`;
|
|
1795
|
+
if (href) {
|
|
1796
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("a", { href, className, children: [
|
|
1797
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: isActive ? "text-rose-600" : "text-gray-500", children: icon }),
|
|
1798
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
|
|
1799
|
+
] }, label);
|
|
1800
|
+
}
|
|
1801
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("button", { className, type: "button", children: [
|
|
1802
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: isActive ? "text-rose-600" : "text-gray-500", children: icon }),
|
|
1803
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
|
|
1804
|
+
] }, label);
|
|
1805
|
+
}) })
|
|
1806
|
+
] }) })
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
};
|
|
1810
|
+
var GlobeIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1811
|
+
"svg",
|
|
1812
|
+
{
|
|
1813
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1814
|
+
viewBox: "0 0 24 24",
|
|
1815
|
+
fill: "none",
|
|
1816
|
+
stroke: "currentColor",
|
|
1817
|
+
strokeWidth: 1.5,
|
|
1818
|
+
"aria-hidden": "true",
|
|
1819
|
+
...props,
|
|
1820
|
+
children: [
|
|
1821
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 12, cy: 12, r: 10 }),
|
|
1822
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 12h20" }),
|
|
1823
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10Z" })
|
|
1824
|
+
]
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
var AirGapIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1828
|
+
"svg",
|
|
1829
|
+
{
|
|
1830
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1831
|
+
viewBox: "0 0 24 24",
|
|
1832
|
+
fill: "none",
|
|
1833
|
+
stroke: "currentColor",
|
|
1834
|
+
strokeWidth: 1.5,
|
|
1835
|
+
"aria-hidden": "true",
|
|
1836
|
+
...props,
|
|
1837
|
+
children: [
|
|
1838
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m4 4 16 16" }),
|
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.5 4.5a8 8 0 0 1 9 0" }),
|
|
1840
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 7.5a8 8 0 0 0 0 9" }),
|
|
1841
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16.5 19.5a8 8 0 0 0 0-9" }),
|
|
1842
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 12a5 5 0 0 0 5 5" })
|
|
1843
|
+
]
|
|
1844
|
+
}
|
|
1845
|
+
);
|
|
1846
|
+
var baseCardClass = "flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]";
|
|
1847
|
+
var headingClass = "text-lg font-semibold text-gray-900";
|
|
1848
|
+
var contentClass = "mt-4 flex-1 space-y-3";
|
|
1849
|
+
var itemClass = "flex items-center gap-3 text-sm text-gray-600";
|
|
1850
|
+
var iconClass = "h-5 w-5 text-gray-500";
|
|
1851
|
+
var footerClass = "mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80";
|
|
1852
|
+
var badgeClass = "ml-2 inline-flex h-5 min-w-[20px] items-center justify-center rounded-full bg-blue-500 px-1.5 text-xs font-medium text-white";
|
|
1853
|
+
var Badge = ({ count }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: badgeClass, "aria-label": `${count} updates available`, children: count });
|
|
1854
|
+
var UpdatesCard = ({
|
|
1855
|
+
onlineActiveCount = 0,
|
|
1856
|
+
airgapCount = 0,
|
|
1857
|
+
onlineUpdates = 0,
|
|
1858
|
+
airgapUpdates = 0
|
|
1859
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: baseCardClass, "aria-labelledby": "updates-card-heading", children: [
|
|
1860
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "updates-card-heading", className: headingClass, children: "Updates" }) }),
|
|
1861
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: contentClass, children: [
|
|
1862
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass, children: [
|
|
1863
|
+
/* @__PURE__ */ jsxRuntime.jsx(GlobeIcon, { className: iconClass }),
|
|
1864
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1865
|
+
onlineActiveCount,
|
|
1866
|
+
" Active Online ",
|
|
1867
|
+
onlineActiveCount === 1 ? "instance" : "instances"
|
|
1868
|
+
] }),
|
|
1869
|
+
onlineUpdates > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { count: onlineUpdates })
|
|
1870
|
+
] }),
|
|
1871
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass, children: [
|
|
1872
|
+
/* @__PURE__ */ jsxRuntime.jsx(AirGapIcon, { className: iconClass }),
|
|
1873
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1874
|
+
airgapCount,
|
|
1875
|
+
" Air gap ",
|
|
1876
|
+
airgapCount === 1 ? "instance" : "instances"
|
|
1877
|
+
] }),
|
|
1878
|
+
airgapUpdates > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { count: airgapUpdates })
|
|
1879
|
+
] })
|
|
1880
|
+
] }),
|
|
1881
|
+
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: footerClass, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/update", children: "View updates \u2192" }) })
|
|
1882
|
+
] });
|
|
1883
|
+
UpdatesCard.displayName = "UpdatesCard";
|
|
1884
|
+
var UploadIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1885
|
+
"svg",
|
|
1886
|
+
{
|
|
1887
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1888
|
+
viewBox: "0 0 24 24",
|
|
1889
|
+
fill: "none",
|
|
1890
|
+
stroke: "currentColor",
|
|
1891
|
+
strokeWidth: 1.5,
|
|
1892
|
+
"aria-hidden": "true",
|
|
1893
|
+
...props,
|
|
1894
|
+
children: [
|
|
1895
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 16V3" }),
|
|
1896
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 7l4-4 4 4" }),
|
|
1897
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 21h14" })
|
|
1898
|
+
]
|
|
1899
|
+
}
|
|
1900
|
+
);
|
|
1901
|
+
var baseCardClass2 = "flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]";
|
|
1902
|
+
var headingClass2 = "text-lg font-semibold text-gray-900";
|
|
1903
|
+
var contentClass2 = "mt-4 flex-1 space-y-3";
|
|
1904
|
+
var itemClass2 = "flex items-center gap-3 text-sm text-gray-600";
|
|
1905
|
+
var iconClass2 = "h-5 w-5 text-gray-500";
|
|
1906
|
+
var footerClass2 = "mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80";
|
|
1907
|
+
var SupportCard = async () => {
|
|
1908
|
+
let totalCount = null;
|
|
1909
|
+
try {
|
|
1910
|
+
const headersModule = await import('next/headers');
|
|
1911
|
+
const store = await headersModule.cookies();
|
|
1912
|
+
const session = store.get("portal_session");
|
|
1913
|
+
const token = session?.value;
|
|
1914
|
+
if (token) {
|
|
1915
|
+
const result = await listSupportBundles.run({ token });
|
|
1916
|
+
totalCount = result.totalCount;
|
|
1917
|
+
} else {
|
|
1918
|
+
console.debug("[portal-components] no portal_session token for support bundles");
|
|
1919
|
+
}
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
if (isRedirectError(error)) {
|
|
1922
|
+
throw error;
|
|
1923
|
+
}
|
|
1924
|
+
console.error("[portal-components] support bundles fetch failed", error);
|
|
1925
|
+
}
|
|
1926
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: baseCardClass2, "aria-labelledby": "support-card-heading", children: [
|
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "support-card-heading", className: headingClass2, children: "Support" }) }),
|
|
1928
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: contentClass2, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass2, children: [
|
|
1929
|
+
/* @__PURE__ */ jsxRuntime.jsx(UploadIcon, { className: iconClass2 }),
|
|
1930
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1931
|
+
"Support bundles uploaded (",
|
|
1932
|
+
totalCount ?? 0,
|
|
1933
|
+
")"
|
|
1934
|
+
] })
|
|
1935
|
+
] }) }),
|
|
1936
|
+
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: footerClass2, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/support", className: "inline-flex items-center gap-1", children: "View support guide \u2192" }) })
|
|
1937
|
+
] });
|
|
1938
|
+
};
|
|
1939
|
+
SupportCard.displayName = "SupportCard";
|
|
1940
|
+
var NOTIFICATION_DESCRIPTIONS = {
|
|
1941
|
+
"new-version": "New version available"
|
|
1942
|
+
};
|
|
1943
|
+
var EmailNotificationsSection = ({
|
|
1944
|
+
teamName,
|
|
1945
|
+
notifications,
|
|
1946
|
+
isLoading,
|
|
1947
|
+
onToggle
|
|
1948
|
+
}) => {
|
|
1949
|
+
const allNotificationTypes = Object.keys(NOTIFICATION_DESCRIPTIONS);
|
|
1950
|
+
const mergedNotifications = allNotificationTypes.map((type) => {
|
|
1951
|
+
const existing = notifications.find((n) => n.type === type);
|
|
1952
|
+
return {
|
|
1953
|
+
type,
|
|
1954
|
+
enabled: existing ? existing.enabled : type === "new-version"
|
|
1955
|
+
// Default new-version to true
|
|
1956
|
+
};
|
|
1957
|
+
});
|
|
1958
|
+
if (isLoading) {
|
|
1959
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-6 shadow-sm", children: [
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg font-semibold text-gray-900", children: [
|
|
1961
|
+
"Email Notifications for ",
|
|
1962
|
+
teamName
|
|
1963
|
+
] }),
|
|
1964
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Choose which email notifications you want to receive for this team." }),
|
|
1965
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6 flex justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Loading notifications..." }) })
|
|
1966
|
+
] });
|
|
1967
|
+
}
|
|
1968
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-6 shadow-sm", children: [
|
|
1969
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg font-semibold text-gray-900", children: [
|
|
1970
|
+
"Email Notifications for ",
|
|
1971
|
+
teamName
|
|
1972
|
+
] }),
|
|
1973
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Choose which email notifications you want to receive for this team." }),
|
|
1974
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 overflow-hidden rounded-lg border border-gray-200", children: [
|
|
1975
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between bg-gray-50 px-4 py-2", children: [
|
|
1976
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase text-gray-600", children: "Description" }),
|
|
1977
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium uppercase text-gray-600", children: "Enabled" })
|
|
1978
|
+
] }),
|
|
1979
|
+
mergedNotifications.map((notification) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1980
|
+
"div",
|
|
1981
|
+
{
|
|
1982
|
+
className: "flex items-center justify-between border-t border-gray-200 px-4 py-3",
|
|
1983
|
+
children: [
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-900", children: NOTIFICATION_DESCRIPTIONS[notification.type] }),
|
|
185
1985
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
186
1986
|
"input",
|
|
187
1987
|
{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
placeholder,
|
|
193
|
-
value: email,
|
|
194
|
-
onChange: (event) => setEmail(event.target.value),
|
|
195
|
-
className: "w-full rounded-2xl border border-white/15 bg-white/5 px-5 py-4 text-base text-white placeholder:text-white/40 focus:border-white/40 focus:outline-none focus:ring-2 focus:ring-white/25",
|
|
196
|
-
disabled,
|
|
197
|
-
required: true
|
|
198
|
-
}
|
|
199
|
-
),
|
|
200
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
201
|
-
Button,
|
|
202
|
-
{
|
|
203
|
-
type: "submit",
|
|
204
|
-
size: "lg",
|
|
205
|
-
className: "w-full justify-center",
|
|
206
|
-
disabled,
|
|
207
|
-
isLoading: disabled,
|
|
208
|
-
children: ctaLabel
|
|
1988
|
+
type: "checkbox",
|
|
1989
|
+
checked: notification.enabled,
|
|
1990
|
+
onChange: () => onToggle?.(notification.type, !notification.enabled),
|
|
1991
|
+
className: "portal-checkbox"
|
|
209
1992
|
}
|
|
210
1993
|
)
|
|
211
|
-
]
|
|
212
|
-
|
|
1994
|
+
]
|
|
1995
|
+
},
|
|
1996
|
+
notification.type
|
|
1997
|
+
))
|
|
1998
|
+
] }),
|
|
1999
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-3 text-xs text-gray-500", children: [
|
|
2000
|
+
"These notification preferences are specific to the ",
|
|
2001
|
+
teamName,
|
|
2002
|
+
" team. Switch teams to manage notifications for other teams."
|
|
2003
|
+
] })
|
|
2004
|
+
] });
|
|
2005
|
+
};
|
|
2006
|
+
var TeamsSection = ({
|
|
2007
|
+
teams,
|
|
2008
|
+
currentCustomer,
|
|
2009
|
+
isLoading,
|
|
2010
|
+
onTeamSwitch,
|
|
2011
|
+
primaryColor
|
|
2012
|
+
}) => {
|
|
2013
|
+
const groupedTeams = react.useMemo(() => {
|
|
2014
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2015
|
+
for (const team of teams) {
|
|
2016
|
+
const existing = groups.get(team.appId);
|
|
2017
|
+
if (existing) {
|
|
2018
|
+
existing.teams.push(team);
|
|
2019
|
+
} else {
|
|
2020
|
+
groups.set(team.appId, {
|
|
2021
|
+
appName: team.appName,
|
|
2022
|
+
teams: [team]
|
|
2023
|
+
});
|
|
213
2024
|
}
|
|
214
|
-
|
|
2025
|
+
}
|
|
2026
|
+
return groups;
|
|
2027
|
+
}, [teams]);
|
|
2028
|
+
if (isLoading) {
|
|
2029
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-6 shadow-sm", children: [
|
|
2030
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Teams" }),
|
|
2031
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Teams associate your email address with any additional licenses your account has access to." }),
|
|
2032
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Loading teams..." }) })
|
|
2033
|
+
] });
|
|
2034
|
+
}
|
|
2035
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-6 shadow-sm", children: [
|
|
2036
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Teams" }),
|
|
2037
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Teams associate your email address with any additional licenses your account has access to." }),
|
|
2038
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6 space-y-6", children: Array.from(groupedTeams.values()).map((appGroup) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
2039
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-medium text-gray-900", children: appGroup.appName }),
|
|
2040
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: appGroup.teams.map((team) => {
|
|
2041
|
+
const isCurrentTeam = currentCustomer?.id === team.id;
|
|
2042
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2043
|
+
"button",
|
|
2044
|
+
{
|
|
2045
|
+
type: "button",
|
|
2046
|
+
onClick: () => !isCurrentTeam && onTeamSwitch?.(team),
|
|
2047
|
+
disabled: isCurrentTeam,
|
|
2048
|
+
className: `flex w-full items-center justify-between rounded-lg border p-4 text-left transition ${isCurrentTeam ? "cursor-default border-gray-300 bg-gray-50" : "cursor-pointer border-gray-200 hover:border-indigo-500"}`,
|
|
2049
|
+
style: !isCurrentTeam && primaryColor ? { "--hover-border": primaryColor } : void 0,
|
|
2050
|
+
children: [
|
|
2051
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2052
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2053
|
+
"svg",
|
|
2054
|
+
{
|
|
2055
|
+
className: "h-4 w-4",
|
|
2056
|
+
style: { color: primaryColor || "#6366f1" },
|
|
2057
|
+
fill: "none",
|
|
2058
|
+
viewBox: "0 0 24 24",
|
|
2059
|
+
stroke: "currentColor",
|
|
2060
|
+
strokeWidth: 2,
|
|
2061
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2062
|
+
"path",
|
|
2063
|
+
{
|
|
2064
|
+
strokeLinecap: "round",
|
|
2065
|
+
strokeLinejoin: "round",
|
|
2066
|
+
d: "M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
|
|
2067
|
+
}
|
|
2068
|
+
)
|
|
2069
|
+
}
|
|
2070
|
+
),
|
|
2071
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2072
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: team.name }),
|
|
2073
|
+
isCurrentTeam && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: "Current Team" })
|
|
2074
|
+
] })
|
|
2075
|
+
] }),
|
|
2076
|
+
!isCurrentTeam && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2077
|
+
"svg",
|
|
2078
|
+
{
|
|
2079
|
+
className: "h-4 w-4",
|
|
2080
|
+
style: { color: primaryColor || "#6366f1" },
|
|
2081
|
+
fill: "none",
|
|
2082
|
+
viewBox: "0 0 24 24",
|
|
2083
|
+
stroke: "currentColor",
|
|
2084
|
+
strokeWidth: 2,
|
|
2085
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2086
|
+
"path",
|
|
2087
|
+
{
|
|
2088
|
+
strokeLinecap: "round",
|
|
2089
|
+
strokeLinejoin: "round",
|
|
2090
|
+
d: "M9 5l7 7-7 7"
|
|
2091
|
+
}
|
|
2092
|
+
)
|
|
2093
|
+
}
|
|
2094
|
+
)
|
|
2095
|
+
]
|
|
2096
|
+
},
|
|
2097
|
+
team.id
|
|
2098
|
+
);
|
|
2099
|
+
}) })
|
|
2100
|
+
] }, appGroup.appName)) })
|
|
2101
|
+
] });
|
|
2102
|
+
};
|
|
2103
|
+
var ProfileSection = ({
|
|
2104
|
+
user,
|
|
2105
|
+
isLoading,
|
|
2106
|
+
isUpdating,
|
|
2107
|
+
error,
|
|
2108
|
+
updateError,
|
|
2109
|
+
onSave,
|
|
2110
|
+
primaryColor
|
|
2111
|
+
}) => {
|
|
2112
|
+
const [isEditing, setIsEditing] = react.useState(false);
|
|
2113
|
+
const [firstName, setFirstName] = react.useState(user?.firstName || "");
|
|
2114
|
+
const [lastName, setLastName] = react.useState(user?.lastName || "");
|
|
2115
|
+
const [inputError, setInputError] = react.useState(null);
|
|
2116
|
+
const resetForm = () => {
|
|
2117
|
+
setFirstName(user?.firstName || "");
|
|
2118
|
+
setLastName(user?.lastName || "");
|
|
2119
|
+
setInputError(null);
|
|
2120
|
+
};
|
|
2121
|
+
const handleSave = async () => {
|
|
2122
|
+
if (!firstName && !lastName) {
|
|
2123
|
+
setInputError("Please enter a first name or last name");
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
if (firstName === user?.firstName && lastName === user?.lastName) {
|
|
2127
|
+
setIsEditing(false);
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
try {
|
|
2131
|
+
await onSave?.({ firstName, lastName });
|
|
2132
|
+
setIsEditing(false);
|
|
2133
|
+
} catch (err) {
|
|
2134
|
+
console.error("Error updating user information:", err);
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
const handleCancel = () => {
|
|
2138
|
+
setIsEditing(false);
|
|
2139
|
+
resetForm();
|
|
2140
|
+
};
|
|
2141
|
+
const handleEdit = () => {
|
|
2142
|
+
resetForm();
|
|
2143
|
+
setIsEditing(true);
|
|
2144
|
+
};
|
|
2145
|
+
const buttonStyle = primaryColor ? { backgroundColor: primaryColor, borderColor: primaryColor } : void 0;
|
|
2146
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-gray-200 bg-white p-6 shadow-sm", children: [
|
|
2147
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
2148
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2149
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Profile Information" }),
|
|
2150
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Your account information." }),
|
|
2151
|
+
(error || updateError) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-red-600", children: error?.message || updateError?.message || "Failed to update profile" }),
|
|
2152
|
+
inputError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-red-600", children: inputError })
|
|
2153
|
+
] }),
|
|
2154
|
+
isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
2155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2156
|
+
"button",
|
|
2157
|
+
{
|
|
2158
|
+
type: "button",
|
|
2159
|
+
onClick: handleCancel,
|
|
2160
|
+
disabled: isUpdating,
|
|
2161
|
+
className: "inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50 disabled:opacity-50",
|
|
2162
|
+
children: "Cancel"
|
|
2163
|
+
}
|
|
2164
|
+
),
|
|
2165
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2166
|
+
"button",
|
|
2167
|
+
{
|
|
2168
|
+
type: "button",
|
|
2169
|
+
onClick: handleSave,
|
|
2170
|
+
disabled: isUpdating,
|
|
2171
|
+
style: buttonStyle,
|
|
2172
|
+
className: "inline-flex items-center rounded-md bg-indigo-500 px-3 py-1.5 text-sm font-medium text-white shadow-sm transition hover:bg-indigo-600 disabled:opacity-50",
|
|
2173
|
+
children: isUpdating ? "Saving..." : "Save"
|
|
2174
|
+
}
|
|
2175
|
+
)
|
|
2176
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2177
|
+
"button",
|
|
2178
|
+
{
|
|
2179
|
+
type: "button",
|
|
2180
|
+
onClick: handleEdit,
|
|
2181
|
+
style: buttonStyle,
|
|
2182
|
+
className: "inline-flex items-center rounded-md bg-indigo-500 px-3 py-1.5 text-sm font-medium text-white shadow-sm transition hover:bg-indigo-600",
|
|
2183
|
+
children: "Edit"
|
|
2184
|
+
}
|
|
2185
|
+
)
|
|
2186
|
+
] }),
|
|
2187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 flex gap-8", children: [
|
|
2188
|
+
isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
|
|
2189
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2190
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-600", children: "First Name" }),
|
|
2191
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2192
|
+
"input",
|
|
2193
|
+
{
|
|
2194
|
+
type: "text",
|
|
2195
|
+
value: firstName,
|
|
2196
|
+
onChange: (e) => {
|
|
2197
|
+
setInputError(null);
|
|
2198
|
+
setFirstName(e.target.value);
|
|
2199
|
+
},
|
|
2200
|
+
disabled: isUpdating,
|
|
2201
|
+
placeholder: "First Name",
|
|
2202
|
+
className: "portal-input mt-1 block w-48"
|
|
2203
|
+
}
|
|
2204
|
+
)
|
|
2205
|
+
] }),
|
|
2206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2207
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-600", children: "Last Name" }),
|
|
2208
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2209
|
+
"input",
|
|
2210
|
+
{
|
|
2211
|
+
type: "text",
|
|
2212
|
+
value: lastName,
|
|
2213
|
+
onChange: (e) => {
|
|
2214
|
+
setInputError(null);
|
|
2215
|
+
setLastName(e.target.value);
|
|
2216
|
+
},
|
|
2217
|
+
disabled: isUpdating,
|
|
2218
|
+
placeholder: "Last Name",
|
|
2219
|
+
className: "portal-input mt-1 block w-48"
|
|
2220
|
+
}
|
|
2221
|
+
)
|
|
2222
|
+
] })
|
|
2223
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
2224
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-600", children: "Full Name (optional)" }),
|
|
2225
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-900", children: user?.firstName || user?.lastName ? `${user.firstName || ""} ${user.lastName || ""}`.trim() : "\u2014" })
|
|
2226
|
+
] }),
|
|
2227
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
2228
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "block text-sm font-medium text-gray-600", children: "Email" }),
|
|
2229
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: isLoading ? "Loading..." : user?.emailAddress || "" })
|
|
2230
|
+
] })
|
|
2231
|
+
] })
|
|
2232
|
+
] });
|
|
2233
|
+
};
|
|
2234
|
+
var UserSettings = ({
|
|
2235
|
+
user,
|
|
2236
|
+
isUserLoading = false,
|
|
2237
|
+
userError,
|
|
2238
|
+
isUpdating = false,
|
|
2239
|
+
updateError,
|
|
2240
|
+
onUpdateUser,
|
|
2241
|
+
teams = [],
|
|
2242
|
+
currentCustomer,
|
|
2243
|
+
isTeamsLoading = false,
|
|
2244
|
+
onTeamSwitch,
|
|
2245
|
+
notifications = [],
|
|
2246
|
+
isNotificationsLoading = false,
|
|
2247
|
+
onToggleNotification,
|
|
2248
|
+
primaryColor
|
|
2249
|
+
}) => {
|
|
2250
|
+
if (userError) {
|
|
2251
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-red-600", children: [
|
|
2252
|
+
"Failed to load user settings. ",
|
|
2253
|
+
userError?.message,
|
|
2254
|
+
" Please try again later."
|
|
2255
|
+
] }) });
|
|
2256
|
+
}
|
|
2257
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-6", children: [
|
|
2258
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold text-gray-900", children: "User Settings" }) }),
|
|
2259
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
2260
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2261
|
+
ProfileSection,
|
|
2262
|
+
{
|
|
2263
|
+
user,
|
|
2264
|
+
isLoading: isUserLoading,
|
|
2265
|
+
isUpdating,
|
|
2266
|
+
error: userError,
|
|
2267
|
+
updateError,
|
|
2268
|
+
onSave: onUpdateUser,
|
|
2269
|
+
primaryColor
|
|
2270
|
+
}
|
|
2271
|
+
),
|
|
2272
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2273
|
+
TeamsSection,
|
|
2274
|
+
{
|
|
2275
|
+
teams,
|
|
2276
|
+
currentCustomer,
|
|
2277
|
+
isLoading: isTeamsLoading,
|
|
2278
|
+
onTeamSwitch,
|
|
2279
|
+
primaryColor
|
|
2280
|
+
}
|
|
2281
|
+
),
|
|
2282
|
+
currentCustomer && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2283
|
+
EmailNotificationsSection,
|
|
2284
|
+
{
|
|
2285
|
+
teamName: currentCustomer.name,
|
|
2286
|
+
notifications,
|
|
2287
|
+
isLoading: isNotificationsLoading,
|
|
2288
|
+
onToggle: onToggleNotification
|
|
2289
|
+
}
|
|
2290
|
+
)
|
|
2291
|
+
] })
|
|
2292
|
+
] });
|
|
2293
|
+
};
|
|
2294
|
+
UserSettings.displayName = "UserSettings";
|
|
2295
|
+
var baseCardClass3 = "flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]";
|
|
2296
|
+
var headingClass3 = "text-lg font-semibold text-gray-900";
|
|
2297
|
+
var bodySpacerClass = "mt-4 flex-1";
|
|
2298
|
+
var footerClass3 = "mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80";
|
|
2299
|
+
var UserSettingsCard = () => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: baseCardClass3, "aria-labelledby": "user-settings-card-heading", children: [
|
|
2300
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "user-settings-card-heading", className: headingClass3, children: "User Settings" }) }),
|
|
2301
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: bodySpacerClass }),
|
|
2302
|
+
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: footerClass3, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/user-settings", children: "View user settings \u2192" }) })
|
|
2303
|
+
] });
|
|
2304
|
+
UserSettingsCard.displayName = "UserSettingsCard";
|
|
2305
|
+
var UsersIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2306
|
+
"svg",
|
|
2307
|
+
{
|
|
2308
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2309
|
+
viewBox: "0 0 24 24",
|
|
2310
|
+
fill: "none",
|
|
2311
|
+
stroke: "currentColor",
|
|
2312
|
+
strokeWidth: 1.5,
|
|
2313
|
+
"aria-hidden": "true",
|
|
2314
|
+
...props,
|
|
2315
|
+
children: [
|
|
2316
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
2317
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 10, cy: 8, r: 4 }),
|
|
2318
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 21v-2a4 4 0 0 0-3-3.87" }),
|
|
2319
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 3a4 4 0 0 1 0 8" })
|
|
2320
|
+
]
|
|
215
2321
|
}
|
|
216
2322
|
);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
2323
|
+
var KeyIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2324
|
+
"svg",
|
|
2325
|
+
{
|
|
2326
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2327
|
+
viewBox: "0 0 24 24",
|
|
2328
|
+
fill: "none",
|
|
2329
|
+
stroke: "currentColor",
|
|
2330
|
+
strokeWidth: 1.5,
|
|
2331
|
+
"aria-hidden": "true",
|
|
2332
|
+
...props,
|
|
2333
|
+
children: [
|
|
2334
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: 7, cy: 15, r: 4 }),
|
|
2335
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m10.85 12.15 4.3-4.3a2 2 0 0 1 2.83 0l.47.47a2 2 0 0 1 0 2.83l-4.3 4.3" }),
|
|
2336
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 11l1.5 1.5" })
|
|
2337
|
+
]
|
|
2338
|
+
}
|
|
2339
|
+
);
|
|
2340
|
+
var baseCardClass4 = "flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]";
|
|
2341
|
+
var headingClass4 = "text-lg font-semibold text-gray-900";
|
|
2342
|
+
var contentClass3 = "mt-4 flex-1 space-y-3";
|
|
2343
|
+
var itemClass3 = "flex items-center gap-3 text-sm text-gray-600";
|
|
2344
|
+
var iconClass3 = "h-5 w-5 text-gray-500";
|
|
2345
|
+
var footerClass4 = "mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80";
|
|
2346
|
+
var TeamSettingsCard = ({
|
|
2347
|
+
userCount = 0,
|
|
2348
|
+
serviceAccountCount = 0
|
|
2349
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: baseCardClass4, "aria-labelledby": "team-settings-card-heading", children: [
|
|
2350
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "team-settings-card-heading", className: headingClass4, children: "Team Settings" }) }),
|
|
2351
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: contentClass3, children: [
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass3, children: [
|
|
2353
|
+
/* @__PURE__ */ jsxRuntime.jsx(UsersIcon, { className: iconClass3 }),
|
|
2354
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2355
|
+
userCount,
|
|
2356
|
+
" Team ",
|
|
2357
|
+
userCount === 1 ? "Member" : "Members"
|
|
2358
|
+
] })
|
|
2359
|
+
] }),
|
|
2360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass3, children: [
|
|
2361
|
+
/* @__PURE__ */ jsxRuntime.jsx(KeyIcon, { className: iconClass3 }),
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2363
|
+
serviceAccountCount,
|
|
2364
|
+
" Service ",
|
|
2365
|
+
serviceAccountCount === 1 ? "Account" : "Accounts"
|
|
2366
|
+
] })
|
|
2367
|
+
] })
|
|
2368
|
+
] }),
|
|
2369
|
+
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: footerClass4, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/team-settings", children: "View team settings \u2192" }) })
|
|
2370
|
+
] });
|
|
2371
|
+
TeamSettingsCard.displayName = "TeamSettingsCard";
|
|
2372
|
+
var UpdateLayout = ({ children }) => {
|
|
2373
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-white", children: [
|
|
2374
|
+
/* @__PURE__ */ jsxRuntime.jsx(TopNav, { activeLabel: "Updates" }),
|
|
2375
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-8", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[1248px]", children }) })
|
|
2376
|
+
] });
|
|
2377
|
+
};
|
|
2378
|
+
UpdateLayout.displayName = "UpdateLayout";
|
|
221
2379
|
|
|
222
2380
|
// src/index.ts
|
|
223
2381
|
var portalComponentsVersion = package_default.version;
|
|
224
2382
|
|
|
225
2383
|
exports.Button = Button;
|
|
226
|
-
exports.
|
|
2384
|
+
exports.LicenseDetails = LicenseDetails;
|
|
2385
|
+
exports.SupportCard = SupportCard;
|
|
2386
|
+
exports.TeamSettingsCard = TeamSettingsCard;
|
|
2387
|
+
exports.TopNav = TopNav;
|
|
2388
|
+
exports.UpdateLayout = UpdateLayout;
|
|
2389
|
+
exports.UpdatesCard = UpdatesCard;
|
|
2390
|
+
exports.UserSettings = UserSettings;
|
|
2391
|
+
exports.UserSettingsCard = UserSettingsCard;
|
|
227
2392
|
exports.createPortalTheme = createPortalTheme;
|
|
2393
|
+
exports.decodeJwtPayload = decodeJwtPayload;
|
|
2394
|
+
exports.defaultTopNavLinks = defaultTopNavLinks;
|
|
228
2395
|
exports.defineServerAction = defineServerAction;
|
|
2396
|
+
exports.deleteSupportBundle = deleteSupportBundle;
|
|
2397
|
+
exports.downloadSupportBundle = downloadSupportBundle;
|
|
2398
|
+
exports.fetchCurrentUser = fetchCurrentUser;
|
|
2399
|
+
exports.fetchCustomBranding = fetchCustomBranding;
|
|
2400
|
+
exports.fetchLicenseDetails = fetchLicenseDetails;
|
|
2401
|
+
exports.fetchNotifications = fetchNotifications;
|
|
2402
|
+
exports.getCustomerIdFromToken = getCustomerIdFromToken;
|
|
2403
|
+
exports.getSecurityInfo = getSecurityInfo;
|
|
2404
|
+
exports.getSecurityInfoDiff = getSecurityInfoDiff;
|
|
2405
|
+
exports.getSecurityInfoSBOM = getSecurityInfoSBOM;
|
|
2406
|
+
exports.getSupportBundleUploadUrl = getSupportBundleUploadUrl;
|
|
2407
|
+
exports.initiateLogin = initiateLogin;
|
|
2408
|
+
exports.listReleases = listReleases;
|
|
2409
|
+
exports.listSupportBundles = listSupportBundles;
|
|
229
2410
|
exports.portalComponentsVersion = portalComponentsVersion;
|
|
230
2411
|
exports.portalThemeTokens = portalThemeTokens;
|
|
2412
|
+
exports.updateNotifications = updateNotifications;
|
|
2413
|
+
exports.updateUser = updateUser;
|
|
2414
|
+
exports.uploadSupportBundle = uploadSupportBundle;
|
|
2415
|
+
exports.verifyMagicLink = verifyMagicLink;
|
|
231
2416
|
//# sourceMappingURL=index.js.map
|
|
232
2417
|
//# sourceMappingURL=index.js.map
|