@burdenoff/fe-libs 2026.1021.14 → 2026.1022.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin-overview/AdminOverviewActionsContext.d.ts +11 -0
- package/dist/admin-overview/AdminOverviewActionsContext.js +17 -0
- package/dist/admin-overview/AdminOverviewPage.d.ts +4 -0
- package/dist/admin-overview/AdminOverviewPage.js +524 -0
- package/dist/admin-overview/buildHierarchyGraph.d.ts +36 -0
- package/dist/admin-overview/buildHierarchyGraph.js +172 -0
- package/dist/admin-overview/index.d.ts +10 -0
- package/dist/admin-overview/nodes/OrganizationNode.d.ts +9 -0
- package/dist/admin-overview/nodes/OrganizationNode.js +85 -0
- package/dist/admin-overview/nodes/ProjectNode.d.ts +9 -0
- package/dist/admin-overview/nodes/ProjectNode.js +69 -0
- package/dist/admin-overview/nodes/TenantNode.d.ts +9 -0
- package/dist/admin-overview/nodes/TenantNode.js +78 -0
- package/dist/admin-overview/nodes/WorkspaceNode.d.ts +9 -0
- package/dist/admin-overview/nodes/WorkspaceNode.js +136 -0
- package/dist/admin-overview/nodes/nodeStyles.d.ts +7 -0
- package/dist/admin-overview/nodes/nodeStyles.js +10 -0
- package/dist/admin-overview/operations.d.ts +45 -0
- package/dist/admin-overview/operations.js +42 -0
- package/dist/admin-overview.d.ts +2 -0
- package/dist/admin-overview.js +3 -0
- package/dist/chrome/GlobalSearch.js +9 -9
- package/dist/chrome/HeaderThemeSwitcher.js +7 -7
- package/dist/chrome.js +44 -44
- package/dist/platform-pages/AcceptShareRoute.d.ts +33 -0
- package/dist/platform-pages/AcceptShareRoute.js +72 -0
- package/dist/platform-pages/AffiliatesPage.d.ts +16 -0
- package/dist/platform-pages/AffiliatesPage.js +583 -0
- package/dist/platform-pages/AppearanceSettingsPage.d.ts +14 -0
- package/dist/platform-pages/AppearanceSettingsPage.js +14 -0
- package/dist/platform-pages/index.d.ts +20 -0
- package/dist/platform-pages.d.ts +2 -0
- package/dist/platform-pages.js +4 -0
- package/dist/shared/config/shellRoutes.js +7 -0
- package/dist/shared/feature-flags/FeatureFlagProvider.d.ts +10 -0
- package/dist/shared/feature-flags/FeatureFlagProvider.js +4 -1
- package/dist/shared/feature-flags/index.d.ts +2 -2
- package/dist/shared/feature-flags/useFeatureFlag.d.ts +26 -1
- package/dist/shared/feature-flags/useFeatureFlag.js +25 -12
- package/dist/shared/hooks/shell/useGlobalSearch.d.ts +11 -2
- package/dist/shared/hooks/shell/useGlobalSearch.js +54 -23
- package/dist/shared/hooks/usePushDeviceRegistration.js +1 -1
- package/dist/shared/providers/AppShellProvider.js +6 -6
- package/dist/shared-feature-flags.js +4 -4
- package/dist/shared-hooks.js +25 -25
- package/dist/shared-native.js +15 -15
- package/dist/shared-providers-shell.js +12 -12
- package/dist/shared.js +94 -94
- package/dist/shell-native/push-optin.js +4 -4
- package/package.json +16 -3
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { MarkerType as e } from "@xyflow/react";
|
|
2
|
+
//#region src/admin-overview/buildHierarchyGraph.ts
|
|
3
|
+
var t = 260, n = 260, r = 220, i = 240, a = 60, o = 140, s = 60, c = -260, l = 0, u = 260, d = 520, f = 120, p = "__ungrouped__";
|
|
4
|
+
function m(e) {
|
|
5
|
+
let { organizations: m, workspaces: _, tenants: v, projectsByWorkspace: y, loadingProjectsFor: b, selectedId: x } = e, S = /* @__PURE__ */ new Map();
|
|
6
|
+
for (let e of _) {
|
|
7
|
+
let t = e.organizationId ?? p, n = S.get(t);
|
|
8
|
+
n ? n.push(e) : S.set(t, [e]);
|
|
9
|
+
}
|
|
10
|
+
let C = S.has(p) ? [...m, {
|
|
11
|
+
id: p,
|
|
12
|
+
name: "Unassigned Workspaces",
|
|
13
|
+
slug: null,
|
|
14
|
+
tenantId: null
|
|
15
|
+
}] : m;
|
|
16
|
+
function w(e) {
|
|
17
|
+
let t = y[e.id];
|
|
18
|
+
return !t || t.length === 0 ? n : Math.max(n, r);
|
|
19
|
+
}
|
|
20
|
+
function T(e) {
|
|
21
|
+
let n = S.get(e) ?? [];
|
|
22
|
+
if (n.length === 0) return t;
|
|
23
|
+
let r = n.reduce((e, t) => e + w(t), 0) + a * (n.length - 1);
|
|
24
|
+
return Math.max(t, r);
|
|
25
|
+
}
|
|
26
|
+
let E = /* @__PURE__ */ new Set(), D = /* @__PURE__ */ new Set();
|
|
27
|
+
if (x) {
|
|
28
|
+
let [e, t] = x.split(":");
|
|
29
|
+
if (E.add(x), e === "org") (S.get(t) ?? []).forEach((e) => {
|
|
30
|
+
E.add(h("ws", e.id)), D.add(`e-org-ws-${t}-${e.id}`), (y[e.id] ?? []).forEach((t) => {
|
|
31
|
+
E.add(h("proj", t.id)), D.add(`e-ws-proj-${e.id}-${t.id}`);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
else if (e === "ws") {
|
|
35
|
+
let e = _.find((e) => e.id === t);
|
|
36
|
+
e && (e.organizationId && (E.add(h("org", e.organizationId)), D.add(`e-org-ws-${e.organizationId}-${e.id}`)), e.tenantId && (E.add(h("tenant", e.tenantId)), D.add(`e-tenant-ws-${e.tenantId}-${e.id}`)), (y[e.id] ?? []).forEach((t) => {
|
|
37
|
+
E.add(h("proj", t.id)), D.add(`e-ws-proj-${e.id}-${t.id}`);
|
|
38
|
+
}));
|
|
39
|
+
} else if (e === "tenant") for (let e of _) e.tenantId === t && (E.add(h("ws", e.id)), D.add(`e-tenant-ws-${t}-${e.id}`));
|
|
40
|
+
else if (e === "proj") {
|
|
41
|
+
let e = Object.values(y).flat().find((e) => !!e && e.id === t);
|
|
42
|
+
e && (E.add(h("ws", e.workspaceId)), D.add(`e-ws-proj-${e.workspaceId}-${e.id}`));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let O = [], k = [], A = 0;
|
|
46
|
+
C.forEach((e) => {
|
|
47
|
+
let i = T(e.id), s = A + i / 2, c = e.id === p;
|
|
48
|
+
if (!c) {
|
|
49
|
+
let n = s - t / 2;
|
|
50
|
+
O.push({
|
|
51
|
+
id: h("org", e.id),
|
|
52
|
+
type: "organization",
|
|
53
|
+
position: {
|
|
54
|
+
x: n,
|
|
55
|
+
y: l
|
|
56
|
+
},
|
|
57
|
+
data: {
|
|
58
|
+
kind: "organization",
|
|
59
|
+
entity: e,
|
|
60
|
+
workspaceCount: (S.get(e.id) ?? []).length,
|
|
61
|
+
isHighlighted: E.has(h("org", e.id))
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
let m = S.get(e.id) ?? [], _ = s - (m.reduce((e, t) => e + w(t), 0) + a * Math.max(0, m.length - 1)) / 2;
|
|
66
|
+
m.forEach((t) => {
|
|
67
|
+
let i = w(t), o = _ + i / 2, s = o - n / 2, l = y[t.id], p = E.has(h("ws", t.id));
|
|
68
|
+
if (O.push({
|
|
69
|
+
id: h("ws", t.id),
|
|
70
|
+
type: "workspace",
|
|
71
|
+
position: {
|
|
72
|
+
x: s,
|
|
73
|
+
y: u
|
|
74
|
+
},
|
|
75
|
+
data: {
|
|
76
|
+
kind: "workspace",
|
|
77
|
+
entity: t,
|
|
78
|
+
projectCount: l ? l.length : null,
|
|
79
|
+
projectsLoading: b.has(t.id),
|
|
80
|
+
isHighlighted: p
|
|
81
|
+
}
|
|
82
|
+
}), c || k.push(g({
|
|
83
|
+
id: `e-org-ws-${e.id}-${t.id}`,
|
|
84
|
+
source: h("org", e.id),
|
|
85
|
+
target: h("ws", t.id),
|
|
86
|
+
highlighted: D.has(`e-org-ws-${e.id}-${t.id}`),
|
|
87
|
+
variant: "solid"
|
|
88
|
+
})), l && l.length > 0) {
|
|
89
|
+
let e = o - r / 2;
|
|
90
|
+
l.forEach((n, r) => {
|
|
91
|
+
O.push({
|
|
92
|
+
id: h("proj", n.id),
|
|
93
|
+
type: "project",
|
|
94
|
+
position: {
|
|
95
|
+
x: e,
|
|
96
|
+
y: d + r * f
|
|
97
|
+
},
|
|
98
|
+
data: {
|
|
99
|
+
kind: "project",
|
|
100
|
+
entity: n,
|
|
101
|
+
isHighlighted: E.has(h("proj", n.id))
|
|
102
|
+
}
|
|
103
|
+
}), k.push(g({
|
|
104
|
+
id: `e-ws-proj-${t.id}-${n.id}`,
|
|
105
|
+
source: h("ws", t.id),
|
|
106
|
+
target: h("proj", n.id),
|
|
107
|
+
highlighted: D.has(`e-ws-proj-${t.id}-${n.id}`),
|
|
108
|
+
variant: "solid"
|
|
109
|
+
}));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
_ += i + a;
|
|
113
|
+
}), A += i + o;
|
|
114
|
+
});
|
|
115
|
+
let j = Math.max(0, A - o), M = v.length > 0 ? v.length * i + s * Math.max(0, v.length - 1) : 0, N = j > 0 ? j / 2 - M / 2 : -M / 2;
|
|
116
|
+
return v.forEach((e, t) => {
|
|
117
|
+
let n = _.filter((t) => t.tenantId === e.id);
|
|
118
|
+
O.push({
|
|
119
|
+
id: h("tenant", e.id),
|
|
120
|
+
type: "tenant",
|
|
121
|
+
position: {
|
|
122
|
+
x: N + t * 300,
|
|
123
|
+
y: c
|
|
124
|
+
},
|
|
125
|
+
data: {
|
|
126
|
+
kind: "tenant",
|
|
127
|
+
entity: e,
|
|
128
|
+
workspaceCount: n.length,
|
|
129
|
+
isHighlighted: E.has(h("tenant", e.id))
|
|
130
|
+
}
|
|
131
|
+
}), n.forEach((t) => {
|
|
132
|
+
k.push(g({
|
|
133
|
+
id: `e-tenant-ws-${e.id}-${t.id}`,
|
|
134
|
+
source: h("tenant", e.id),
|
|
135
|
+
target: h("ws", t.id),
|
|
136
|
+
highlighted: D.has(`e-tenant-ws-${e.id}-${t.id}`),
|
|
137
|
+
variant: "dashed"
|
|
138
|
+
}));
|
|
139
|
+
});
|
|
140
|
+
}), {
|
|
141
|
+
nodes: O,
|
|
142
|
+
edges: k
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function h(e, t) {
|
|
146
|
+
return `${e}:${t}`;
|
|
147
|
+
}
|
|
148
|
+
function g(t) {
|
|
149
|
+
let { id: n, source: r, target: i, highlighted: a, variant: o } = t, s = a ? "var(--color-action-primary-bg)" : "var(--color-border-default)";
|
|
150
|
+
return {
|
|
151
|
+
id: n,
|
|
152
|
+
source: r,
|
|
153
|
+
target: i,
|
|
154
|
+
type: "smoothstep",
|
|
155
|
+
animated: a,
|
|
156
|
+
style: {
|
|
157
|
+
stroke: s,
|
|
158
|
+
strokeWidth: a ? 2.5 : 1.5,
|
|
159
|
+
strokeDasharray: o === "dashed" ? "5 5" : void 0,
|
|
160
|
+
opacity: a ? 1 : o === "dashed" ? .7 : .9,
|
|
161
|
+
transition: "stroke 150ms ease, stroke-width 150ms ease, opacity 150ms ease"
|
|
162
|
+
},
|
|
163
|
+
markerEnd: {
|
|
164
|
+
type: e.ArrowClosed,
|
|
165
|
+
color: s,
|
|
166
|
+
width: 18,
|
|
167
|
+
height: 18
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
172
|
+
export { m as buildHierarchyGraph };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @burdenoff/fe-libs/admin-overview
|
|
3
|
+
*
|
|
4
|
+
* The account hierarchy graph (Organization → Workspace → Project, with Tenant
|
|
5
|
+
* chips) that app shells mount at `/admin/overview`, inside
|
|
6
|
+
* `<GatewayRoute gateway="global">`. It renders with React Flow, so the shell
|
|
7
|
+
* must install the optional `@xyflow/react` peer.
|
|
8
|
+
*/
|
|
9
|
+
export { AdminOverviewPage, type AdminOverviewPageProps } from './AdminOverviewPage';
|
|
10
|
+
export { buildHierarchyGraph, type HierarchyNodeData } from './buildHierarchyGraph';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeProps } from '@xyflow/react';
|
|
2
|
+
import { HierarchyNodeData } from '../buildHierarchyGraph';
|
|
3
|
+
type Props = NodeProps & {
|
|
4
|
+
data: Extract<HierarchyNodeData, {
|
|
5
|
+
kind: 'organization';
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export declare function OrganizationNode({ data }: Props): import('react/jsx-runtime').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useShellNavigate as e } from "../../shared/utils/appHelpers.js";
|
|
2
|
+
import "../../shared-utils.js";
|
|
3
|
+
import { MANAGE_BUTTON_CLASS as t, NODE_CARD_CLASS_BASE as n, nodeBorderColor as r, nodeBoxShadow as i } from "./nodeStyles.js";
|
|
4
|
+
import { Building as a, Settings as o } from "lucide-react";
|
|
5
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
|
+
import { Handle as l, Position as u } from "@xyflow/react";
|
|
7
|
+
//#region src/admin-overview/nodes/OrganizationNode.tsx
|
|
8
|
+
function d({ data: d }) {
|
|
9
|
+
let f = e(), { entity: p, workspaceCount: m, isHighlighted: h } = d;
|
|
10
|
+
return /* @__PURE__ */ c("div", {
|
|
11
|
+
className: `${n} min-w-[240px]`,
|
|
12
|
+
style: {
|
|
13
|
+
background: "var(--color-bg-surface)",
|
|
14
|
+
borderColor: r(h),
|
|
15
|
+
color: "var(--color-text-primary)",
|
|
16
|
+
boxShadow: i(h)
|
|
17
|
+
},
|
|
18
|
+
"data-testid": `admin-overview-org-${p.id}`,
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ s(l, {
|
|
21
|
+
type: "source",
|
|
22
|
+
position: u.Bottom,
|
|
23
|
+
style: {
|
|
24
|
+
background: "var(--color-action-primary-bg)",
|
|
25
|
+
width: 8,
|
|
26
|
+
height: 8
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
/* @__PURE__ */ c("div", {
|
|
30
|
+
className: "flex items-center justify-between px-3 py-2 border-b",
|
|
31
|
+
style: { borderColor: "var(--color-border-default)" },
|
|
32
|
+
children: [/* @__PURE__ */ c("div", {
|
|
33
|
+
className: "flex items-center gap-2",
|
|
34
|
+
children: [/* @__PURE__ */ s(a, {
|
|
35
|
+
size: 16,
|
|
36
|
+
style: { color: "var(--color-action-primary-bg)" }
|
|
37
|
+
}), /* @__PURE__ */ s("span", {
|
|
38
|
+
className: "text-[11px] font-semibold uppercase tracking-wide",
|
|
39
|
+
style: { color: "var(--color-text-secondary)" },
|
|
40
|
+
children: "Organization"
|
|
41
|
+
})]
|
|
42
|
+
}), /* @__PURE__ */ s("button", {
|
|
43
|
+
type: "button",
|
|
44
|
+
onClick: (e) => {
|
|
45
|
+
e.stopPropagation(), f(`/organizations/${p.id}`);
|
|
46
|
+
},
|
|
47
|
+
className: t,
|
|
48
|
+
style: { color: "var(--color-action-primary-bg)" },
|
|
49
|
+
title: "Manage organization",
|
|
50
|
+
"aria-label": `Manage organization ${p.name}`,
|
|
51
|
+
children: /* @__PURE__ */ s(o, { size: 14 })
|
|
52
|
+
})]
|
|
53
|
+
}),
|
|
54
|
+
/* @__PURE__ */ c("div", {
|
|
55
|
+
className: "px-3 py-2",
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ s("div", {
|
|
58
|
+
className: "font-semibold text-sm truncate",
|
|
59
|
+
title: p.name,
|
|
60
|
+
children: p.name
|
|
61
|
+
}),
|
|
62
|
+
p.slug ? /* @__PURE__ */ s("div", {
|
|
63
|
+
className: "text-xs truncate",
|
|
64
|
+
style: { color: "var(--color-text-secondary)" },
|
|
65
|
+
children: p.slug
|
|
66
|
+
}) : null,
|
|
67
|
+
/* @__PURE__ */ c("div", {
|
|
68
|
+
className: "text-xs mt-1 inline-flex items-center gap-1 px-1.5 py-0.5 rounded",
|
|
69
|
+
style: {
|
|
70
|
+
background: "var(--color-bg-subtle, transparent)",
|
|
71
|
+
color: "var(--color-text-secondary)"
|
|
72
|
+
},
|
|
73
|
+
children: [
|
|
74
|
+
m,
|
|
75
|
+
" workspace",
|
|
76
|
+
m === 1 ? "" : "s"
|
|
77
|
+
]
|
|
78
|
+
})
|
|
79
|
+
]
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { d as OrganizationNode };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeProps } from '@xyflow/react';
|
|
2
|
+
import { HierarchyNodeData } from '../buildHierarchyGraph';
|
|
3
|
+
type Props = NodeProps & {
|
|
4
|
+
data: Extract<HierarchyNodeData, {
|
|
5
|
+
kind: 'project';
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export declare function ProjectNode({ data }: Props): import('react/jsx-runtime').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useShellNavigate as e } from "../../shared/utils/appHelpers.js";
|
|
2
|
+
import "../../shared-utils.js";
|
|
3
|
+
import { MANAGE_BUTTON_CLASS as t, NODE_CARD_CLASS_BASE as n, nodeBorderColor as r, nodeBoxShadow as i } from "./nodeStyles.js";
|
|
4
|
+
import { Package as a, Settings as o } from "lucide-react";
|
|
5
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
|
+
import { Handle as l, Position as u } from "@xyflow/react";
|
|
7
|
+
//#region src/admin-overview/nodes/ProjectNode.tsx
|
|
8
|
+
function d({ data: d }) {
|
|
9
|
+
let f = e(), { entity: p, isHighlighted: m } = d;
|
|
10
|
+
return /* @__PURE__ */ c("div", {
|
|
11
|
+
className: `${n} min-w-[200px]`,
|
|
12
|
+
style: {
|
|
13
|
+
background: "var(--color-bg-surface)",
|
|
14
|
+
borderColor: r(m),
|
|
15
|
+
color: "var(--color-text-primary)",
|
|
16
|
+
boxShadow: i(m)
|
|
17
|
+
},
|
|
18
|
+
"data-testid": `admin-overview-project-${p.id}`,
|
|
19
|
+
children: [/* @__PURE__ */ s(l, {
|
|
20
|
+
type: "target",
|
|
21
|
+
position: u.Top,
|
|
22
|
+
style: {
|
|
23
|
+
background: "var(--color-action-primary-bg)",
|
|
24
|
+
width: 8,
|
|
25
|
+
height: 8
|
|
26
|
+
}
|
|
27
|
+
}), /* @__PURE__ */ c("div", {
|
|
28
|
+
className: "flex items-center justify-between px-3 py-2",
|
|
29
|
+
children: [/* @__PURE__ */ c("div", {
|
|
30
|
+
className: "flex items-center gap-2 min-w-0",
|
|
31
|
+
children: [/* @__PURE__ */ s(a, {
|
|
32
|
+
size: 14,
|
|
33
|
+
style: { color: "var(--color-action-primary-bg)" }
|
|
34
|
+
}), /* @__PURE__ */ c("div", {
|
|
35
|
+
className: "min-w-0",
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ s("div", {
|
|
38
|
+
className: "text-[10px] font-semibold uppercase tracking-wide",
|
|
39
|
+
style: { color: "var(--color-text-secondary)" },
|
|
40
|
+
children: "Project"
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ s("div", {
|
|
43
|
+
className: "text-sm font-medium truncate",
|
|
44
|
+
title: p.name,
|
|
45
|
+
children: p.name
|
|
46
|
+
}),
|
|
47
|
+
p.key ? /* @__PURE__ */ c("div", {
|
|
48
|
+
className: "text-[11px] truncate",
|
|
49
|
+
style: { color: "var(--color-text-secondary)" },
|
|
50
|
+
children: [p.key, p.archived ? " · archived" : ""]
|
|
51
|
+
}) : null
|
|
52
|
+
]
|
|
53
|
+
})]
|
|
54
|
+
}), /* @__PURE__ */ s("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: (e) => {
|
|
57
|
+
e.stopPropagation(), f(`/workspaces/${p.workspaceId}/projects`);
|
|
58
|
+
},
|
|
59
|
+
className: t,
|
|
60
|
+
style: { color: "var(--color-action-primary-bg)" },
|
|
61
|
+
title: "Manage project",
|
|
62
|
+
"aria-label": `Manage project ${p.name}`,
|
|
63
|
+
children: /* @__PURE__ */ s(o, { size: 12 })
|
|
64
|
+
})]
|
|
65
|
+
})]
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { d as ProjectNode };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeProps } from '@xyflow/react';
|
|
2
|
+
import { HierarchyNodeData } from '../buildHierarchyGraph';
|
|
3
|
+
type Props = NodeProps & {
|
|
4
|
+
data: Extract<HierarchyNodeData, {
|
|
5
|
+
kind: 'tenant';
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export declare function TenantNode({ data }: Props): import('react/jsx-runtime').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useShellNavigate as e } from "../../shared/utils/appHelpers.js";
|
|
2
|
+
import "../../shared-utils.js";
|
|
3
|
+
import { MANAGE_BUTTON_CLASS as t, NODE_CARD_CLASS_BASE as n, nodeBorderColor as r, nodeBoxShadow as i } from "./nodeStyles.js";
|
|
4
|
+
import { Building2 as a, Settings as o } from "lucide-react";
|
|
5
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
|
+
import { Handle as l, Position as u } from "@xyflow/react";
|
|
7
|
+
//#region src/admin-overview/nodes/TenantNode.tsx
|
|
8
|
+
function d({ data: d }) {
|
|
9
|
+
let f = e(), { entity: p, workspaceCount: m, isHighlighted: h } = d;
|
|
10
|
+
return /* @__PURE__ */ c("div", {
|
|
11
|
+
className: `${n} min-w-[220px]`,
|
|
12
|
+
style: {
|
|
13
|
+
background: "var(--color-bg-subtle, var(--color-bg-surface))",
|
|
14
|
+
borderColor: r(h),
|
|
15
|
+
borderStyle: "dashed",
|
|
16
|
+
color: "var(--color-text-primary)",
|
|
17
|
+
boxShadow: i(h)
|
|
18
|
+
},
|
|
19
|
+
"data-testid": `admin-overview-tenant-${p.id}`,
|
|
20
|
+
children: [/* @__PURE__ */ s(l, {
|
|
21
|
+
type: "source",
|
|
22
|
+
position: u.Bottom,
|
|
23
|
+
style: {
|
|
24
|
+
background: "var(--color-action-primary-bg)",
|
|
25
|
+
width: 8,
|
|
26
|
+
height: 8
|
|
27
|
+
}
|
|
28
|
+
}), /* @__PURE__ */ c("div", {
|
|
29
|
+
className: "flex items-center justify-between px-3 py-2",
|
|
30
|
+
children: [/* @__PURE__ */ c("div", {
|
|
31
|
+
className: "flex items-center gap-2 min-w-0",
|
|
32
|
+
children: [/* @__PURE__ */ s(a, {
|
|
33
|
+
size: 14,
|
|
34
|
+
style: { color: "var(--color-action-primary-bg)" }
|
|
35
|
+
}), /* @__PURE__ */ c("div", {
|
|
36
|
+
className: "min-w-0",
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ s("div", {
|
|
39
|
+
className: "text-[10px] font-semibold uppercase tracking-wide",
|
|
40
|
+
style: { color: "var(--color-text-secondary)" },
|
|
41
|
+
children: "Tenant"
|
|
42
|
+
}),
|
|
43
|
+
/* @__PURE__ */ s("div", {
|
|
44
|
+
className: "text-sm font-medium truncate",
|
|
45
|
+
title: p.name,
|
|
46
|
+
children: p.name
|
|
47
|
+
}),
|
|
48
|
+
/* @__PURE__ */ c("div", {
|
|
49
|
+
className: "text-[11px] mt-0.5 flex items-center gap-1.5",
|
|
50
|
+
style: { color: "var(--color-text-secondary)" },
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ s("span", {
|
|
53
|
+
className: "px-1 py-0.5 rounded text-[9px] font-medium uppercase tracking-wide",
|
|
54
|
+
style: { border: "1px solid var(--color-border-default)" },
|
|
55
|
+
children: p.type ?? "shared"
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ s("span", { children: "·" }),
|
|
58
|
+
/* @__PURE__ */ c("span", { children: [m, " ws"] })
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
})]
|
|
63
|
+
}), /* @__PURE__ */ s("button", {
|
|
64
|
+
type: "button",
|
|
65
|
+
onClick: (e) => {
|
|
66
|
+
e.stopPropagation(), f(`/organizations?tenantId=${p.id}`);
|
|
67
|
+
},
|
|
68
|
+
className: t,
|
|
69
|
+
style: { color: "var(--color-action-primary-bg)" },
|
|
70
|
+
title: "View tenant organizations",
|
|
71
|
+
"aria-label": `View organizations for tenant ${p.name}`,
|
|
72
|
+
children: /* @__PURE__ */ s(o, { size: 14 })
|
|
73
|
+
})]
|
|
74
|
+
})]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { d as TenantNode };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeProps } from '@xyflow/react';
|
|
2
|
+
import { HierarchyNodeData } from '../buildHierarchyGraph';
|
|
3
|
+
type Props = NodeProps & {
|
|
4
|
+
data: Extract<HierarchyNodeData, {
|
|
5
|
+
kind: 'workspace';
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export declare function WorkspaceNode({ data }: Props): import('react/jsx-runtime').JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useAdminOverviewActions as e } from "../AdminOverviewActionsContext.js";
|
|
2
|
+
import { MANAGE_BUTTON_CLASS as t, NODE_CARD_CLASS_BASE as n, nodeBorderColor as r, nodeBoxShadow as i } from "./nodeStyles.js";
|
|
3
|
+
import { LayoutGrid as a, Loader2 as o, Package as s, Settings as c } from "lucide-react";
|
|
4
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
|
+
import { Handle as d, Position as f } from "@xyflow/react";
|
|
6
|
+
//#region src/admin-overview/nodes/WorkspaceNode.tsx
|
|
7
|
+
function p(e) {
|
|
8
|
+
if (!e) return "var(--color-text-secondary)";
|
|
9
|
+
let t = e.toLowerCase();
|
|
10
|
+
return t === "active" ? "var(--color-status-success-text)" : t === "suspended" || t === "inactive" ? "var(--color-status-warning-text)" : "var(--color-text-secondary)";
|
|
11
|
+
}
|
|
12
|
+
function m({ data: m }) {
|
|
13
|
+
let { onLoadProjects: h, onManageWorkspace: g } = e(), { entity: _, projectCount: v, projectsLoading: y, isHighlighted: b } = m;
|
|
14
|
+
return /* @__PURE__ */ u("div", {
|
|
15
|
+
className: `${n} min-w-[240px]`,
|
|
16
|
+
style: {
|
|
17
|
+
background: "var(--color-bg-surface)",
|
|
18
|
+
borderColor: r(b),
|
|
19
|
+
color: "var(--color-text-primary)",
|
|
20
|
+
boxShadow: i(b)
|
|
21
|
+
},
|
|
22
|
+
"data-testid": `admin-overview-workspace-${_.id}`,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ l(d, {
|
|
25
|
+
type: "target",
|
|
26
|
+
position: f.Top,
|
|
27
|
+
style: {
|
|
28
|
+
background: "var(--color-action-primary-bg)",
|
|
29
|
+
width: 8,
|
|
30
|
+
height: 8
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
33
|
+
/* @__PURE__ */ l(d, {
|
|
34
|
+
type: "source",
|
|
35
|
+
position: f.Bottom,
|
|
36
|
+
style: {
|
|
37
|
+
background: "var(--color-action-primary-bg)",
|
|
38
|
+
width: 8,
|
|
39
|
+
height: 8
|
|
40
|
+
}
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ u("div", {
|
|
43
|
+
className: "flex items-center justify-between px-3 py-2 border-b",
|
|
44
|
+
style: { borderColor: "var(--color-border-default)" },
|
|
45
|
+
children: [/* @__PURE__ */ u("div", {
|
|
46
|
+
className: "flex items-center gap-2",
|
|
47
|
+
children: [/* @__PURE__ */ l(a, {
|
|
48
|
+
size: 16,
|
|
49
|
+
style: { color: "var(--color-action-primary-bg)" }
|
|
50
|
+
}), /* @__PURE__ */ l("span", {
|
|
51
|
+
className: "text-[11px] font-semibold uppercase tracking-wide",
|
|
52
|
+
style: { color: "var(--color-text-secondary)" },
|
|
53
|
+
children: "Workspace"
|
|
54
|
+
})]
|
|
55
|
+
}), /* @__PURE__ */ l("button", {
|
|
56
|
+
type: "button",
|
|
57
|
+
onClick: (e) => {
|
|
58
|
+
e.stopPropagation(), g(_.id);
|
|
59
|
+
},
|
|
60
|
+
className: t,
|
|
61
|
+
style: { color: "var(--color-action-primary-bg)" },
|
|
62
|
+
title: "Manage workspace",
|
|
63
|
+
"aria-label": `Manage workspace ${_.name}`,
|
|
64
|
+
children: /* @__PURE__ */ l(c, { size: 14 })
|
|
65
|
+
})]
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ u("div", {
|
|
68
|
+
className: "px-3 py-2",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ l("div", {
|
|
71
|
+
className: "font-semibold text-sm truncate",
|
|
72
|
+
title: _.name,
|
|
73
|
+
children: _.name
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ u("div", {
|
|
76
|
+
className: "text-xs flex items-center gap-2 mt-1",
|
|
77
|
+
style: { color: "var(--color-text-secondary)" },
|
|
78
|
+
children: [
|
|
79
|
+
_.type ? /* @__PURE__ */ l("span", {
|
|
80
|
+
className: "px-1.5 py-0.5 rounded text-[10px] font-medium uppercase tracking-wide",
|
|
81
|
+
style: {
|
|
82
|
+
background: "var(--color-bg-subtle, transparent)",
|
|
83
|
+
border: "1px solid var(--color-border-default)"
|
|
84
|
+
},
|
|
85
|
+
children: _.type
|
|
86
|
+
}) : null,
|
|
87
|
+
_.status ? /* @__PURE__ */ u("span", {
|
|
88
|
+
className: "flex items-center gap-1",
|
|
89
|
+
style: { color: p(_.status) },
|
|
90
|
+
children: [/* @__PURE__ */ l("span", {
|
|
91
|
+
className: "inline-block size-1.5 rounded-full",
|
|
92
|
+
style: { background: p(_.status) }
|
|
93
|
+
}), _.status]
|
|
94
|
+
}) : null,
|
|
95
|
+
typeof _.memberCount == "number" ? /* @__PURE__ */ u("span", { children: [
|
|
96
|
+
"· ",
|
|
97
|
+
_.memberCount,
|
|
98
|
+
" members"
|
|
99
|
+
] }) : null
|
|
100
|
+
]
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ u("div", {
|
|
103
|
+
className: "mt-2 flex items-center justify-between gap-2 pt-2 border-t",
|
|
104
|
+
style: { borderColor: "var(--color-border-default)" },
|
|
105
|
+
children: [/* @__PURE__ */ u("div", {
|
|
106
|
+
className: "flex items-center gap-1 text-xs",
|
|
107
|
+
style: { color: "var(--color-text-secondary)" },
|
|
108
|
+
children: [/* @__PURE__ */ l(s, { size: 12 }), /* @__PURE__ */ l("span", { children: v === null ? "Projects not loaded" : `${v} project${v === 1 ? "" : "s"}` })]
|
|
109
|
+
}), /* @__PURE__ */ l("button", {
|
|
110
|
+
type: "button",
|
|
111
|
+
onClick: (e) => {
|
|
112
|
+
e.stopPropagation(), h(_.id);
|
|
113
|
+
},
|
|
114
|
+
disabled: y,
|
|
115
|
+
className: "text-xs px-2 py-1 rounded-md border cursor-pointer transition-all duration-150 disabled:opacity-50 disabled:cursor-not-allowed hover:bg-[color:var(--color-action-primary-bg)]/10",
|
|
116
|
+
style: {
|
|
117
|
+
borderColor: "var(--color-action-primary-bg)",
|
|
118
|
+
color: "var(--color-action-primary-bg)"
|
|
119
|
+
},
|
|
120
|
+
title: "Load projects for this workspace",
|
|
121
|
+
children: y ? /* @__PURE__ */ u("span", {
|
|
122
|
+
className: "flex items-center gap-1",
|
|
123
|
+
children: [/* @__PURE__ */ l(o, {
|
|
124
|
+
size: 12,
|
|
125
|
+
className: "animate-spin"
|
|
126
|
+
}), "Loading"]
|
|
127
|
+
}) : v === null ? "Load projects" : "Reload"
|
|
128
|
+
})]
|
|
129
|
+
})
|
|
130
|
+
]
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { m as WorkspaceNode };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared style helpers for Admin Overview custom nodes.
|
|
3
|
+
*/
|
|
4
|
+
export declare const MANAGE_BUTTON_CLASS: string;
|
|
5
|
+
export declare const NODE_CARD_CLASS_BASE: string;
|
|
6
|
+
export declare function nodeBorderColor(highlighted: boolean): string;
|
|
7
|
+
export declare function nodeBoxShadow(highlighted: boolean): string | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/admin-overview/nodes/nodeStyles.ts
|
|
2
|
+
var e = "p-1.5 rounded-md cursor-pointer transition-all duration-150 hover:bg-[color:var(--color-action-primary-bg)]/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--color-action-primary-bg)]/40", t = "rounded-xl border shadow-sm transition-all duration-150 hover:shadow-md";
|
|
3
|
+
function n(e) {
|
|
4
|
+
return e ? "var(--color-action-primary-bg)" : "var(--color-border-default)";
|
|
5
|
+
}
|
|
6
|
+
function r(e) {
|
|
7
|
+
return e ? "0 0 0 2px var(--color-action-primary-bg), var(--shadow-elevation-2)" : void 0;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { e as MANAGE_BUTTON_CLASS, t as NODE_CARD_CLASS_BASE, n as nodeBorderColor, r as nodeBoxShadow };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL operations for the Admin Overview page.
|
|
3
|
+
*
|
|
4
|
+
* Global gateway operations (orgs / workspaces / tenants) are executed via
|
|
5
|
+
* Apollo `useQuery` under <GatewayRoute gateway="global">.
|
|
6
|
+
*
|
|
7
|
+
* The project query targets the WORKSPACE gateway and is executed via a raw
|
|
8
|
+
* fetch (workspace-scoped token is issued on demand) — see AdminOverviewPage.
|
|
9
|
+
*/
|
|
10
|
+
export declare const GET_ADMIN_OVERVIEW_CONTEXT: import('graphql').DocumentNode;
|
|
11
|
+
/**
|
|
12
|
+
* Raw GraphQL document string for the workspace-gateway project fetch.
|
|
13
|
+
* Kept as a string (not gql) because we execute it via `fetch`, not Apollo.
|
|
14
|
+
*/
|
|
15
|
+
export declare const GET_MY_PROJECTS_DOC = "\n query AdminOverviewGetMyProjects($pagination: PaginationInput) {\n myProjects(pagination: $pagination) {\n items {\n id\n name\n key\n workspaceId\n status\n archived\n }\n total\n hasMore\n }\n }\n";
|
|
16
|
+
export interface OrganizationSummary {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
slug: string | null;
|
|
20
|
+
tenantId: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface WorkspaceSummary {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
type: string | null;
|
|
26
|
+
status: string | null;
|
|
27
|
+
tenantId: string | null;
|
|
28
|
+
organizationId: string | null;
|
|
29
|
+
memberCount: number | null;
|
|
30
|
+
}
|
|
31
|
+
export interface TenantSummary {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
slug: string | null;
|
|
35
|
+
status: string | null;
|
|
36
|
+
type: string | null;
|
|
37
|
+
}
|
|
38
|
+
export interface ProjectSummary {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
key: string | null;
|
|
42
|
+
workspaceId: string;
|
|
43
|
+
status: string | null;
|
|
44
|
+
archived: boolean | null;
|
|
45
|
+
}
|