@burdenoff/fe-libs 2026.1021.14 → 2026.1021.15

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.
Files changed (48) hide show
  1. package/dist/admin-overview/AdminOverviewActionsContext.d.ts +11 -0
  2. package/dist/admin-overview/AdminOverviewActionsContext.js +17 -0
  3. package/dist/admin-overview/AdminOverviewPage.d.ts +4 -0
  4. package/dist/admin-overview/AdminOverviewPage.js +524 -0
  5. package/dist/admin-overview/buildHierarchyGraph.d.ts +36 -0
  6. package/dist/admin-overview/buildHierarchyGraph.js +172 -0
  7. package/dist/admin-overview/index.d.ts +10 -0
  8. package/dist/admin-overview/nodes/OrganizationNode.d.ts +9 -0
  9. package/dist/admin-overview/nodes/OrganizationNode.js +85 -0
  10. package/dist/admin-overview/nodes/ProjectNode.d.ts +9 -0
  11. package/dist/admin-overview/nodes/ProjectNode.js +69 -0
  12. package/dist/admin-overview/nodes/TenantNode.d.ts +9 -0
  13. package/dist/admin-overview/nodes/TenantNode.js +78 -0
  14. package/dist/admin-overview/nodes/WorkspaceNode.d.ts +9 -0
  15. package/dist/admin-overview/nodes/WorkspaceNode.js +136 -0
  16. package/dist/admin-overview/nodes/nodeStyles.d.ts +7 -0
  17. package/dist/admin-overview/nodes/nodeStyles.js +10 -0
  18. package/dist/admin-overview/operations.d.ts +45 -0
  19. package/dist/admin-overview/operations.js +42 -0
  20. package/dist/admin-overview.d.ts +2 -0
  21. package/dist/admin-overview.js +3 -0
  22. package/dist/chrome/GlobalSearch.js +9 -9
  23. package/dist/chrome/HeaderThemeSwitcher.js +7 -7
  24. package/dist/chrome.js +44 -44
  25. package/dist/platform-pages/AcceptShareRoute.d.ts +33 -0
  26. package/dist/platform-pages/AcceptShareRoute.js +72 -0
  27. package/dist/platform-pages/AffiliatesPage.d.ts +16 -0
  28. package/dist/platform-pages/AffiliatesPage.js +583 -0
  29. package/dist/platform-pages/AppearanceSettingsPage.d.ts +14 -0
  30. package/dist/platform-pages/AppearanceSettingsPage.js +14 -0
  31. package/dist/platform-pages/index.d.ts +20 -0
  32. package/dist/platform-pages.d.ts +2 -0
  33. package/dist/platform-pages.js +4 -0
  34. package/dist/shared/config/shellRoutes.js +7 -0
  35. package/dist/shared/feature-flags/FeatureFlagProvider.d.ts +10 -0
  36. package/dist/shared/feature-flags/FeatureFlagProvider.js +4 -1
  37. package/dist/shared/feature-flags/index.d.ts +2 -2
  38. package/dist/shared/feature-flags/useFeatureFlag.d.ts +26 -1
  39. package/dist/shared/feature-flags/useFeatureFlag.js +25 -12
  40. package/dist/shared/hooks/usePushDeviceRegistration.js +1 -1
  41. package/dist/shared/providers/AppShellProvider.js +6 -6
  42. package/dist/shared-feature-flags.js +4 -4
  43. package/dist/shared-hooks.js +25 -25
  44. package/dist/shared-native.js +15 -15
  45. package/dist/shared-providers-shell.js +12 -12
  46. package/dist/shared.js +94 -94
  47. package/dist/shell-native/push-optin.js +4 -4
  48. package/package.json +16 -3
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ interface AdminOverviewActions {
3
+ onLoadProjects: (workspaceId: string) => void;
4
+ onManageWorkspace: (workspaceId: string) => void;
5
+ }
6
+ export declare function AdminOverviewActionsProvider({ actions, children, }: {
7
+ actions: AdminOverviewActions;
8
+ children: ReactNode;
9
+ }): import('react/jsx-runtime').JSX.Element;
10
+ export declare function useAdminOverviewActions(): AdminOverviewActions;
11
+ export {};
@@ -0,0 +1,17 @@
1
+ import { createContext as e, use as t } from "react";
2
+ import { jsx as n } from "react/jsx-runtime";
3
+ //#region src/admin-overview/AdminOverviewActionsContext.tsx
4
+ var r = e(null);
5
+ function i({ actions: e, children: t }) {
6
+ return /* @__PURE__ */ n(r.Provider, {
7
+ value: e,
8
+ children: t
9
+ });
10
+ }
11
+ function a() {
12
+ let e = t(r);
13
+ if (!e) throw Error("useAdminOverviewActions must be used inside AdminOverviewActionsProvider");
14
+ return e;
15
+ }
16
+ //#endregion
17
+ export { i as AdminOverviewActionsProvider, a as useAdminOverviewActions };
@@ -0,0 +1,4 @@
1
+ export interface AdminOverviewPageProps {
2
+ authToken: string;
3
+ }
4
+ export declare function AdminOverviewPage(props: AdminOverviewPageProps): import('react/jsx-runtime').JSX.Element;
@@ -0,0 +1,524 @@
1
+ import { graphqlFetch as e } from "../shared/graphql/fetch.js";
2
+ import { useI18n as t } from "../shared/providers/shell/I18nProvider.js";
3
+ import { useShellNavigate as n } from "../shared/utils/appHelpers.js";
4
+ import "../shared-utils.js";
5
+ import { GET_ADMIN_OVERVIEW_CONTEXT as r, GET_MY_PROJECTS_DOC as i } from "./operations.js";
6
+ import { buildHierarchyGraph as a } from "./buildHierarchyGraph.js";
7
+ import { AdminOverviewActionsProvider as o } from "./AdminOverviewActionsContext.js";
8
+ import { OrganizationNode as s } from "./nodes/OrganizationNode.js";
9
+ import { WorkspaceNode as c } from "./nodes/WorkspaceNode.js";
10
+ import { TenantNode as l } from "./nodes/TenantNode.js";
11
+ import { ProjectNode as u } from "./nodes/ProjectNode.js";
12
+ import { impactFeedback as d, notificationFeedback as ee, selectionFeedback as te } from "../shell-native/feedback.js";
13
+ import { showNativeToast as ne } from "../shell-native/toast.js";
14
+ import "../shell-native.js";
15
+ import { useCallback as f, useEffect as p, useMemo as m, useReducer as re, useRef as ie, useState as h } from "react";
16
+ import { AlertCircle as g, Building as _, Building2 as v, Download as y, Layers as b, LayoutGrid as x, Network as S, Package as C, RefreshCcw as w } from "lucide-react";
17
+ import { Fragment as ae, jsx as T, jsxs as E } from "react/jsx-runtime";
18
+ import { useQuery as D } from "@apollo/client/react";
19
+ import { Background as O, BackgroundVariant as k, Controls as A, MiniMap as j, Panel as M, ReactFlow as N, ReactFlowProvider as P, applyEdgeChanges as F, applyNodeChanges as I, useReactFlow as L } from "@xyflow/react";
20
+ import "@xyflow/react/dist/style.css";
21
+ //#region src/admin-overview/AdminOverviewPage.tsx
22
+ var R = {
23
+ organization: s,
24
+ workspace: c,
25
+ tenant: l,
26
+ project: u
27
+ }, z = {
28
+ byWorkspace: {},
29
+ loadingFor: /* @__PURE__ */ new Set(),
30
+ error: null
31
+ };
32
+ function B(e, t) {
33
+ switch (t.type) {
34
+ case "loadStart": {
35
+ let n = new Set(e.loadingFor);
36
+ return n.add(t.workspaceId), {
37
+ ...e,
38
+ loadingFor: n,
39
+ error: null
40
+ };
41
+ }
42
+ case "loadSuccess": {
43
+ let n = new Set(e.loadingFor);
44
+ return n.delete(t.workspaceId), {
45
+ ...e,
46
+ loadingFor: n,
47
+ byWorkspace: {
48
+ ...e.byWorkspace,
49
+ [t.workspaceId]: t.projects
50
+ }
51
+ };
52
+ }
53
+ case "loadFailure": {
54
+ let n = new Set(e.loadingFor);
55
+ return n.delete(t.workspaceId), {
56
+ ...e,
57
+ loadingFor: n,
58
+ error: t.error
59
+ };
60
+ }
61
+ case "reset": return {
62
+ byWorkspace: {},
63
+ loadingFor: /* @__PURE__ */ new Set(),
64
+ error: null
65
+ };
66
+ default: return e;
67
+ }
68
+ }
69
+ function V(e) {
70
+ return /* @__PURE__ */ T(P, { children: /* @__PURE__ */ T(H, { ...e }) });
71
+ }
72
+ function H({ authToken: o }) {
73
+ let s = n(), { fitView: c } = L(), { t: l } = t(), u = f((e, t) => {
74
+ let n = l(e);
75
+ return n === e ? t : n;
76
+ }, [l]), g = D(r, {
77
+ variables: {
78
+ limit: 100,
79
+ offset: 0
80
+ },
81
+ fetchPolicy: "cache-and-network"
82
+ }), _ = m(() => !!(g.data?.myOrganizations?.hasMore || g.data?.myWorkspaces?.hasMore || g.data?.myTenants?.hasMore), [g.data]), [v, y] = re(B, z), { byWorkspace: b, loadingFor: x, error: S } = v, [C, w] = h(null), O = m(() => g.data?.myOrganizations?.items ?? [], [g.data]), k = m(() => g.data?.myWorkspaces?.items ?? [], [g.data]), A = m(() => g.data?.myTenants?.items ?? [], [g.data]), j = ie({}), M = f(async (t) => {
83
+ y({
84
+ type: "loadStart",
85
+ workspaceId: t
86
+ });
87
+ try {
88
+ let n = k.find((e) => e.id === t);
89
+ if (!n) throw Error("Workspace not found in current context");
90
+ let r = n.organizationId ?? n.tenantId;
91
+ if (!r) throw Error("Workspace is missing organization/tenant context and cannot be scoped");
92
+ let a = j.current[t];
93
+ if (!a) {
94
+ let n = await e({
95
+ gateway: "workspace",
96
+ query: "mutation AdminOverviewIssueWorkspaceToken($input: IssueWorkspaceTokenInput!) {\n issueWorkspaceToken(input: $input) { success token }\n }",
97
+ variables: { input: {
98
+ organizationId: r,
99
+ workspaceId: t
100
+ } },
101
+ authToken: o
102
+ });
103
+ if (n.errors && n.errors.length > 0) throw Error(`Token issue failed: ${n.errors.map((e) => e.message).join("; ")}`);
104
+ let i = n.data?.issueWorkspaceToken;
105
+ if (!i?.success || !i.token) throw Error("Could not issue workspace token");
106
+ a = i.token, j.current[t] = a;
107
+ }
108
+ let s = await e({
109
+ gateway: "workspace",
110
+ query: i,
111
+ variables: { pagination: { limit: 100 } },
112
+ authToken: o,
113
+ workspaceToken: a,
114
+ workspaceId: t,
115
+ organizationId: r
116
+ });
117
+ if (s.errors && s.errors.length > 0) throw s.errors.some((e) => e.extensions?.code === "TOKEN_EXPIRED") && delete j.current[t], Error(s.errors.map((e) => e.message).join("; "));
118
+ y({
119
+ type: "loadSuccess",
120
+ workspaceId: t,
121
+ projects: s.data?.myProjects?.items ?? []
122
+ });
123
+ } catch (e) {
124
+ y({
125
+ type: "loadFailure",
126
+ workspaceId: t,
127
+ error: `Failed to load projects: ${e instanceof Error ? e.message : String(e)}`
128
+ }), ee("error"), ne(u("adminOverviewPage.errorLoadProjects", "Failed to load projects"), "long");
129
+ }
130
+ }, [
131
+ o,
132
+ k,
133
+ u
134
+ ]), N = f((e) => {
135
+ d("light"), s(`/workspaces/${e}`);
136
+ }, [s]), P = f(() => {
137
+ d("light"), g.refetch(), y({ type: "reset" }), w(null), j.current = {};
138
+ }, [g]), R = f(() => {
139
+ d("medium"), k.forEach((e) => {
140
+ !b[e.id] && !x.has(e.id) && M(e.id);
141
+ });
142
+ }, [
143
+ k,
144
+ b,
145
+ x,
146
+ M
147
+ ]), V = f((e, t) => {
148
+ te(), w(t.id);
149
+ }, []), { nodes: H, edges: W } = m(() => a({
150
+ organizations: O,
151
+ workspaces: k,
152
+ tenants: A,
153
+ projectsByWorkspace: b,
154
+ loadingProjectsFor: x,
155
+ selectedId: C
156
+ }), [
157
+ O,
158
+ k,
159
+ A,
160
+ b,
161
+ x,
162
+ C
163
+ ]), G = m(() => ({
164
+ onLoadProjects: M,
165
+ onManageWorkspace: N
166
+ }), [M, N]), [K, q] = h(H), [Y, X] = h(W);
167
+ p(() => {
168
+ queueMicrotask(() => q(H));
169
+ }, [H]), p(() => {
170
+ queueMicrotask(() => X(W));
171
+ }, [W]);
172
+ let ce = f((e) => q((t) => I(e, t)), []), le = f((e) => X((t) => F(e, t)), []), ue = Object.keys(b).length, Z = H.length;
173
+ p(() => {
174
+ if (Z === 0) return;
175
+ let e = 0, t = window.requestAnimationFrame(() => {
176
+ e = window.requestAnimationFrame(() => {
177
+ c({
178
+ padding: .2,
179
+ duration: 500,
180
+ includeHiddenNodes: !1
181
+ });
182
+ });
183
+ }), n = window.setTimeout(() => {
184
+ c({
185
+ padding: .2,
186
+ duration: 500,
187
+ includeHiddenNodes: !1
188
+ });
189
+ }, 250);
190
+ return () => {
191
+ window.cancelAnimationFrame(t), e && window.cancelAnimationFrame(e), window.clearTimeout(n);
192
+ };
193
+ }, [
194
+ c,
195
+ Z,
196
+ ue
197
+ ]);
198
+ let Q = g.loading && !g.data, $ = g.error?.message || S, de = m(() => Object.values(b).reduce((e, t) => e + (t?.length ?? 0), 0), [b]), fe = !Q && O.length === 0 && k.length === 0 && A.length === 0, pe = f(() => w(null), []);
199
+ return /* @__PURE__ */ T("div", {
200
+ className: "flex flex-col",
201
+ style: {
202
+ height: "clamp(640px, calc(100dvh - 11rem), 980px)",
203
+ background: "var(--color-bg-page, var(--color-bg-surface))"
204
+ },
205
+ "data-testid": "admin-overview-page",
206
+ children: Q ? /* @__PURE__ */ T("div", {
207
+ className: "flex flex-1 items-center justify-center",
208
+ children: /* @__PURE__ */ T(J, {})
209
+ }) : /* @__PURE__ */ E(ae, { children: [
210
+ /* @__PURE__ */ T(oe, {
211
+ organizationsCount: O.length,
212
+ workspacesCount: k.length,
213
+ tenantsCount: A.length,
214
+ totalProjects: de,
215
+ onLoadAllProjects: R,
216
+ onRefresh: P
217
+ }),
218
+ $ ? /* @__PURE__ */ T(U, { message: $ }) : null,
219
+ _ ? /* @__PURE__ */ T(U, { message: u("adminOverviewPage.truncatedWarning", "Some lists are truncated (more than 100 items). Not all organizations, workspaces or tenants are shown.") }) : null,
220
+ /* @__PURE__ */ T(se, {
221
+ nodes: K,
222
+ edges: Y,
223
+ onNodesChange: ce,
224
+ onEdgesChange: le,
225
+ onNodeClick: V,
226
+ onPaneClick: pe,
227
+ selectedId: C,
228
+ actions: G,
229
+ isInitialLoading: Q,
230
+ isEmpty: fe
231
+ })
232
+ ] })
233
+ });
234
+ }
235
+ function oe({ organizationsCount: e, workspacesCount: n, tenantsCount: r, totalProjects: i, onLoadAllProjects: a, onRefresh: o }) {
236
+ let { t: s } = t(), c = (e, t) => {
237
+ let n = s(e);
238
+ return n === e ? t : n;
239
+ };
240
+ return /* @__PURE__ */ E("header", {
241
+ className: "flex items-center justify-between px-6 py-4 border-b shrink-0",
242
+ style: {
243
+ borderColor: "var(--color-border-default)",
244
+ background: "var(--color-bg-surface)"
245
+ },
246
+ children: [/* @__PURE__ */ E("div", {
247
+ className: "flex items-center gap-3",
248
+ children: [/* @__PURE__ */ T("div", {
249
+ className: "p-2 rounded-lg",
250
+ style: {
251
+ background: "var(--color-bg-subtle, var(--color-bg-surface))",
252
+ color: "var(--color-action-primary-bg)"
253
+ },
254
+ children: /* @__PURE__ */ T(S, { size: 20 })
255
+ }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("h1", {
256
+ className: "text-lg font-semibold",
257
+ style: { color: "var(--color-text-primary)" },
258
+ children: c("adminOverviewPage.title", "Administration Overview")
259
+ }), /* @__PURE__ */ T("p", {
260
+ className: "text-xs",
261
+ style: { color: "var(--color-text-secondary)" },
262
+ children: c("adminOverviewPage.subtitle", "Organization → Workspace → Project hierarchy, with tenant placement")
263
+ })] })]
264
+ }), /* @__PURE__ */ E("div", {
265
+ className: "flex items-center gap-4",
266
+ children: [
267
+ /* @__PURE__ */ T(W, {
268
+ organizations: e,
269
+ workspaces: n,
270
+ tenants: r,
271
+ projects: i
272
+ }),
273
+ /* @__PURE__ */ E("button", {
274
+ type: "button",
275
+ onClick: a,
276
+ disabled: n === 0,
277
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md border text-sm cursor-pointer transition-all duration-150 hover:bg-[color:var(--color-action-primary-bg)]/10 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap",
278
+ style: {
279
+ borderColor: "var(--color-action-primary-bg)",
280
+ color: "var(--color-action-primary-bg)",
281
+ background: "transparent"
282
+ },
283
+ "data-testid": "admin-overview-load-all-projects",
284
+ title: c("adminOverviewPage.loadAllProjectsTooltip", "Load projects for every workspace"),
285
+ children: [/* @__PURE__ */ T(y, { size: 14 }), c("adminOverviewPage.loadAllProjects", "Load all projects")]
286
+ }),
287
+ /* @__PURE__ */ E("button", {
288
+ type: "button",
289
+ onClick: o,
290
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md border text-sm cursor-pointer transition-all duration-150 hover:bg-action-ghost-bgHover whitespace-nowrap",
291
+ style: {
292
+ borderColor: "var(--color-border-default)",
293
+ color: "var(--color-text-primary)",
294
+ background: "var(--color-bg-surface)"
295
+ },
296
+ "data-testid": "admin-overview-refresh",
297
+ children: [/* @__PURE__ */ T(w, { size: 14 }), c("adminOverviewPage.refresh", "Refresh")]
298
+ })
299
+ ]
300
+ })]
301
+ });
302
+ }
303
+ function U({ message: e }) {
304
+ return /* @__PURE__ */ E("div", {
305
+ className: "flex items-center gap-2 px-6 py-2 border-b text-sm",
306
+ style: {
307
+ borderColor: "var(--color-border-default)",
308
+ background: "var(--color-bg-surface)",
309
+ color: "var(--color-status-error-text)"
310
+ },
311
+ "data-testid": "admin-overview-error",
312
+ children: [/* @__PURE__ */ T(g, { size: 14 }), /* @__PURE__ */ T("span", { children: e })]
313
+ });
314
+ }
315
+ function se({ nodes: e, edges: t, onNodesChange: n, onEdgesChange: r, onNodeClick: i, onPaneClick: a, selectedId: s, actions: c, isInitialLoading: l, isEmpty: u }) {
316
+ return /* @__PURE__ */ E("div", {
317
+ className: "flex-1 min-h-0 relative",
318
+ children: [l ? /* @__PURE__ */ T(J, {}) : u ? /* @__PURE__ */ T(Y, {}) : null, /* @__PURE__ */ T(o, {
319
+ actions: c,
320
+ children: /* @__PURE__ */ E(N, {
321
+ nodes: e,
322
+ edges: t,
323
+ onNodesChange: n,
324
+ onEdgesChange: r,
325
+ nodeTypes: R,
326
+ fitView: !0,
327
+ fitViewOptions: { padding: .25 },
328
+ minZoom: .15,
329
+ maxZoom: 1.5,
330
+ onNodeClick: i,
331
+ onPaneClick: a,
332
+ proOptions: { hideAttribution: !0 },
333
+ defaultEdgeOptions: { type: "smoothstep" },
334
+ children: [
335
+ /* @__PURE__ */ T(O, {
336
+ variant: k.Dots,
337
+ gap: 20,
338
+ size: 1,
339
+ color: "var(--color-border-default)"
340
+ }),
341
+ /* @__PURE__ */ T(A, { style: {
342
+ background: "var(--color-bg-surface)",
343
+ border: "1px solid var(--color-border-default)",
344
+ borderRadius: 8,
345
+ overflow: "hidden"
346
+ } }),
347
+ /* @__PURE__ */ T(j, {
348
+ pannable: !0,
349
+ zoomable: !0,
350
+ style: {
351
+ background: "var(--color-bg-surface)",
352
+ border: "1px solid var(--color-border-default)",
353
+ borderRadius: 8
354
+ },
355
+ nodeColor: (e) => {
356
+ switch (e.data?.kind) {
357
+ case "organization": return "var(--color-action-primary-bg)";
358
+ case "workspace": return "var(--color-status-success-bg)";
359
+ case "tenant": return "var(--color-status-warning-bg)";
360
+ case "project": return "var(--color-text-secondary)";
361
+ default: return "var(--color-border-default)";
362
+ }
363
+ }
364
+ }),
365
+ /* @__PURE__ */ T(M, {
366
+ position: "top-left",
367
+ children: /* @__PURE__ */ T(K, {})
368
+ }),
369
+ s ? /* @__PURE__ */ T(M, {
370
+ position: "bottom-center",
371
+ children: /* @__PURE__ */ T("div", {
372
+ className: "px-3 py-1.5 rounded-full border text-xs shadow-sm",
373
+ style: {
374
+ background: "var(--color-bg-surface)",
375
+ borderColor: "var(--color-border-default)",
376
+ color: "var(--color-text-secondary)"
377
+ },
378
+ children: "Click the background to clear selection"
379
+ })
380
+ }) : null
381
+ ]
382
+ })
383
+ })]
384
+ });
385
+ }
386
+ function W({ organizations: e, workspaces: n, tenants: r, projects: i }) {
387
+ let { t: a } = t(), o = (e, t) => {
388
+ let n = a(e);
389
+ return n === e ? t : n;
390
+ };
391
+ return /* @__PURE__ */ E("div", {
392
+ className: "flex items-center gap-2 text-xs",
393
+ children: [
394
+ /* @__PURE__ */ T(G, {
395
+ icon: /* @__PURE__ */ T(_, { size: 12 }),
396
+ label: `${e} ${o("adminOverviewPage.statsOrgs", "orgs")}`
397
+ }),
398
+ /* @__PURE__ */ T(G, {
399
+ icon: /* @__PURE__ */ T(x, { size: 12 }),
400
+ label: `${n} ${o("adminOverviewPage.statsWorkspaces", "workspaces")}`
401
+ }),
402
+ /* @__PURE__ */ T(G, {
403
+ icon: /* @__PURE__ */ T(v, { size: 12 }),
404
+ label: `${r} ${o("adminOverviewPage.statsTenants", "tenants")}`
405
+ }),
406
+ i > 0 ? /* @__PURE__ */ T(G, {
407
+ icon: /* @__PURE__ */ T(C, { size: 12 }),
408
+ label: `${i} ${o("adminOverviewPage.statsProjects", "projects")}`
409
+ }) : null
410
+ ]
411
+ });
412
+ }
413
+ function G({ icon: e, label: t }) {
414
+ return /* @__PURE__ */ E("span", {
415
+ className: "inline-flex items-center gap-1 px-2 py-1 rounded-md border whitespace-nowrap",
416
+ style: {
417
+ borderColor: "var(--color-border-default)",
418
+ background: "var(--color-bg-surface)",
419
+ color: "var(--color-text-secondary)"
420
+ },
421
+ children: [e, t]
422
+ });
423
+ }
424
+ function K() {
425
+ let { t: e } = t(), n = (t, n) => {
426
+ let r = e(t);
427
+ return r === t ? n : r;
428
+ };
429
+ return /* @__PURE__ */ E("div", {
430
+ className: "p-3 rounded-lg border shadow-sm text-xs",
431
+ style: {
432
+ background: "var(--color-bg-surface)",
433
+ borderColor: "var(--color-border-default)",
434
+ color: "var(--color-text-secondary)"
435
+ },
436
+ "data-testid": "admin-overview-legend",
437
+ children: [
438
+ /* @__PURE__ */ E("div", {
439
+ className: "flex items-center gap-1.5 mb-2",
440
+ style: { color: "var(--color-text-primary)" },
441
+ children: [/* @__PURE__ */ T(b, { size: 12 }), /* @__PURE__ */ T("span", {
442
+ className: "font-semibold",
443
+ children: n("adminOverviewPage.legend", "Legend")
444
+ })]
445
+ }),
446
+ /* @__PURE__ */ T(q, {
447
+ icon: /* @__PURE__ */ T(_, { size: 11 }),
448
+ label: n("adminOverviewPage.legendOrganization", "Organization")
449
+ }),
450
+ /* @__PURE__ */ T(q, {
451
+ icon: /* @__PURE__ */ T(x, { size: 11 }),
452
+ label: n("adminOverviewPage.legendWorkspace", "Workspace")
453
+ }),
454
+ /* @__PURE__ */ T(q, {
455
+ icon: /* @__PURE__ */ T(C, { size: 11 }),
456
+ label: n("adminOverviewPage.legendProject", "Project")
457
+ }),
458
+ /* @__PURE__ */ T(q, {
459
+ icon: /* @__PURE__ */ T(v, { size: 11 }),
460
+ label: n("adminOverviewPage.legendTenant", "Tenant (dashed link)")
461
+ }),
462
+ /* @__PURE__ */ T("div", {
463
+ className: "mt-2 pt-2 border-t text-[10px] leading-tight",
464
+ style: { borderColor: "var(--color-border-default)" },
465
+ children: n("adminOverviewPage.legendHint", "Click any node to highlight its connections.")
466
+ })
467
+ ]
468
+ });
469
+ }
470
+ function q({ icon: e, label: t }) {
471
+ return /* @__PURE__ */ E("div", {
472
+ className: "flex items-center gap-1.5 py-0.5",
473
+ children: [/* @__PURE__ */ T("span", {
474
+ style: { color: "var(--color-action-primary-bg)" },
475
+ children: e
476
+ }), /* @__PURE__ */ T("span", { children: t })]
477
+ });
478
+ }
479
+ function J() {
480
+ let { t: e } = t();
481
+ return /* @__PURE__ */ T("div", {
482
+ className: "absolute inset-0 flex items-center justify-center text-sm pointer-events-none z-10",
483
+ style: { color: "var(--color-text-secondary)" },
484
+ children: /* @__PURE__ */ E("div", {
485
+ className: "flex items-center gap-2",
486
+ children: [/* @__PURE__ */ T("div", {
487
+ className: "animate-spin rounded-full size-4 border-2 border-t-transparent",
488
+ style: {
489
+ borderColor: "var(--color-action-primary-bg)",
490
+ borderTopColor: "transparent"
491
+ }
492
+ }), ((t, n) => {
493
+ let r = e(t);
494
+ return r === t ? n : r;
495
+ })("adminOverviewPage.loadingHierarchy", "Loading hierarchy…")]
496
+ })
497
+ });
498
+ }
499
+ function Y() {
500
+ let { t: e } = t(), n = (t, n) => {
501
+ let r = e(t);
502
+ return r === t ? n : r;
503
+ };
504
+ return /* @__PURE__ */ T("div", {
505
+ className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10",
506
+ style: { color: "var(--color-text-secondary)" },
507
+ children: /* @__PURE__ */ E("div", {
508
+ className: "flex flex-col items-center gap-2 text-center max-w-sm",
509
+ children: [
510
+ /* @__PURE__ */ T(S, { size: 32 }),
511
+ /* @__PURE__ */ T("div", {
512
+ className: "text-base font-medium",
513
+ children: n("adminOverviewPage.emptyTitle", "No resources found")
514
+ }),
515
+ /* @__PURE__ */ T("div", {
516
+ className: "text-xs",
517
+ children: n("adminOverviewPage.emptyDescription", "You don't have access to any organizations, workspaces, or tenants yet.")
518
+ })
519
+ ]
520
+ })
521
+ });
522
+ }
523
+ //#endregion
524
+ export { V as AdminOverviewPage };
@@ -0,0 +1,36 @@
1
+ import { Edge, Node } from '@xyflow/react';
2
+ import { OrganizationSummary, ProjectSummary, TenantSummary, WorkspaceSummary } from './operations';
3
+ export type HierarchyNodeData = {
4
+ kind: 'organization';
5
+ entity: OrganizationSummary;
6
+ workspaceCount: number;
7
+ isHighlighted: boolean;
8
+ } | {
9
+ kind: 'workspace';
10
+ entity: WorkspaceSummary;
11
+ projectCount: number | null;
12
+ projectsLoading: boolean;
13
+ isHighlighted: boolean;
14
+ } | {
15
+ kind: 'tenant';
16
+ entity: TenantSummary;
17
+ workspaceCount: number;
18
+ isHighlighted: boolean;
19
+ } | {
20
+ kind: 'project';
21
+ entity: ProjectSummary;
22
+ isHighlighted: boolean;
23
+ };
24
+ export interface BuildGraphInput {
25
+ organizations: OrganizationSummary[];
26
+ workspaces: WorkspaceSummary[];
27
+ tenants: TenantSummary[];
28
+ projectsByWorkspace: Record<string, ProjectSummary[] | undefined>;
29
+ loadingProjectsFor: Set<string>;
30
+ selectedId: string | null;
31
+ }
32
+ export interface BuildGraphResult {
33
+ nodes: Node<HierarchyNodeData>[];
34
+ edges: Edge[];
35
+ }
36
+ export declare function buildHierarchyGraph(input: BuildGraphInput): BuildGraphResult;