@burdenoff/microfe-organization 2026.624.1 → 2026.625.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/organization-management/AdminOrganizationRoot.js +4 -4
- package/dist/organization-management/AdminOrganizationRoot.js.map +1 -1
- package/dist/organization-management/UserOrganizationRoot.js +4 -4
- package/dist/organization-management/UserOrganizationRoot.js.map +1 -1
- package/dist/organization-management/modules/members/components/BulkInviteForm.js +155 -174
- package/dist/organization-management/modules/members/components/BulkInviteForm.js.map +1 -1
- package/dist/organization-management/modules/members/components/PendingInvitesList.js +78 -101
- package/dist/organization-management/modules/members/components/PendingInvitesList.js.map +1 -1
- package/dist/organization-management/modules/members/pages/InviteMemberPage.js +58 -52
- package/dist/organization-management/modules/members/pages/InviteMemberPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js +42 -40
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js +71 -69
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MembersListPage.js +233 -204
- package/dist/organization-management/modules/members/pages/MembersListPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js +38 -37
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js +134 -132
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js +39 -37
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js +164 -167
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js +49 -47
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +258 -230
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js +43 -50
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js +40 -38
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js +230 -299
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js +47 -45
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +117 -74
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/EmptyState.js +1 -1
- package/dist/organization-management/shared/components/feedback/EmptyState.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/ErrorState.js +1 -1
- package/dist/organization-management/shared/components/feedback/ErrorState.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/LoadingState.js +1 -1
- package/dist/organization-management/shared/components/feedback/LoadingState.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,24 +8,25 @@ import { LoadingState as a } from "../../../shared/components/feedback/LoadingSt
|
|
|
8
8
|
import { ErrorState as te } from "../../../shared/components/feedback/ErrorState.js";
|
|
9
9
|
import { EmptyState as o } from "../../../shared/components/feedback/EmptyState.js";
|
|
10
10
|
import { useDebouncedValue as s } from "../../../shared/hooks/useDebouncedValue.js";
|
|
11
|
-
import { useConfirmDialog as
|
|
12
|
-
import { PERMISSIONS as
|
|
13
|
-
import { isNative as
|
|
14
|
-
import { useDeleteWorkspace as
|
|
15
|
-
import { WorkspaceStatusBadge as
|
|
16
|
-
import { useEffect as
|
|
17
|
-
import { Briefcase as
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
11
|
+
import { useConfirmDialog as ne } from "../../../shared/components/dialog/ConfirmDialog.js";
|
|
12
|
+
import { PERMISSIONS as c } from "../../../constants/permissions.js";
|
|
13
|
+
import { isNative as l, nativeConfirm as re, nativeImpact as ie, nativeNotify as u, nativeToast as d } from "../../../../utils/nativeBridge.js";
|
|
14
|
+
import { useDeleteWorkspace as f, useWorkspaces as p } from "../hooks/useWorkspaces.js";
|
|
15
|
+
import { WorkspaceStatusBadge as m } from "../components/WorkspaceStatusBadge.js";
|
|
16
|
+
import { useEffect as ae, useMemo as h, useState as g } from "react";
|
|
17
|
+
import { Briefcase as oe, Eye as _, Plus as se, RefreshCw as ce, SquarePen as v, Trash2 as y } from "lucide-react";
|
|
18
|
+
import { GlassCard as b } from "@burdenoff/fe-libs/ui";
|
|
19
|
+
import { usePermissions as x } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
20
|
+
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
20
21
|
//#region src/organization-management/modules/workspaces/pages/WorkspacesListPage.tsx
|
|
21
22
|
function T(e) {
|
|
22
23
|
return new Date(e).toLocaleDateString();
|
|
23
24
|
}
|
|
24
25
|
function E({ mode: E = "my" } = {}) {
|
|
25
|
-
let D = r(), { navigate: O, basePath: k = "/organizations" } = e(), { hasPermission: A, isLoading:
|
|
26
|
+
let D = r(), { navigate: O, basePath: k = "/organizations" } = e(), { hasPermission: A, isLoading: le } = x(), [j, ue] = g(""), M = s(j, 300), [N, P] = g({}), [F, I] = g(/* @__PURE__ */ new Set()), { openConfirmDialog: L, ConfirmDialog: R } = ne(), z = E === "admin" ? "all" : "my", { workspaces: B, loading: V, error: H, refetch: U } = p({
|
|
26
27
|
...N,
|
|
27
28
|
search: M || void 0
|
|
28
|
-
}, z === "my" ? 100 : 20, 0, z), W =
|
|
29
|
+
}, z === "my" ? 100 : 20, 0, z), W = h(() => {
|
|
29
30
|
if (z !== "my") return B;
|
|
30
31
|
let e = M.trim().toLowerCase();
|
|
31
32
|
return B.filter((t) => {
|
|
@@ -37,31 +38,31 @@ function E({ mode: E = "my" } = {}) {
|
|
|
37
38
|
z,
|
|
38
39
|
M,
|
|
39
40
|
N.status
|
|
40
|
-
]), { deleteWorkspace:
|
|
41
|
-
|
|
41
|
+
]), { deleteWorkspace: de, loading: G } = f();
|
|
42
|
+
ae(() => {
|
|
42
43
|
I((e) => {
|
|
43
44
|
let t = new Set(W.map((e) => e.id)), n = new Set([...e].filter((e) => t.has(e)));
|
|
44
45
|
return n.size === e.size ? e : n;
|
|
45
46
|
});
|
|
46
47
|
}, [W]);
|
|
47
|
-
let
|
|
48
|
+
let K = h(() => W.filter((e) => F.has(e.id)), [F, W]), q = W.length > 0 && W.every((e) => F.has(e.id)), J = W.some((e) => F.has(e.id)) && !q, Y = async (e) => {
|
|
48
49
|
try {
|
|
49
50
|
let n = (await Promise.allSettled(e.map(async (e) => {
|
|
50
|
-
let t = await
|
|
51
|
+
let t = await de(e);
|
|
51
52
|
if (t.errors?.length) throw Error(t.errors[0]?.message ?? D("workspaces.suspend.failed", "Failed to suspend workspace"));
|
|
52
53
|
}))).find((e) => e.status === "rejected");
|
|
53
54
|
if (n?.status === "rejected") throw n.reason;
|
|
54
55
|
I(/* @__PURE__ */ new Set()), await U();
|
|
55
56
|
let r = e.length === 1 ? D("workspaces.suspend.successSingle", "Workspace suspended successfully") : `${e.length} ${D("workspaces.suspend.successMany", "workspaces suspended successfully")}`;
|
|
56
|
-
t.success(r),
|
|
57
|
+
t.success(r), u("success"), l() && d(r);
|
|
57
58
|
} catch (e) {
|
|
58
59
|
let n = e instanceof Error ? e.message : D("workspaces.suspend.failed", "Failed to suspend workspace");
|
|
59
|
-
t.error(n),
|
|
60
|
+
t.error(n), u("error"), l() && d(n);
|
|
60
61
|
}
|
|
61
|
-
},
|
|
62
|
-
|
|
62
|
+
}, X = (e, t) => {
|
|
63
|
+
ie("medium");
|
|
63
64
|
let n = D("workspaces.suspend.title", "Suspend workspace"), r = `${D("workspaces.suspend.prefix", "Suspend")} ${t}? ${D("workspaces.suspend.suffix", "Workspace members will lose access until it is reactivated.")}`;
|
|
64
|
-
|
|
65
|
+
re({
|
|
65
66
|
title: n,
|
|
66
67
|
message: r,
|
|
67
68
|
okButtonTitle: D("workspaces.suspend.confirm", "Suspend")
|
|
@@ -72,18 +73,18 @@ function E({ mode: E = "my" } = {}) {
|
|
|
72
73
|
confirmText: D("workspaces.suspend.confirm", "Suspend"),
|
|
73
74
|
variant: "warning",
|
|
74
75
|
onConfirm: () => {
|
|
75
|
-
|
|
76
|
+
Y([e]);
|
|
76
77
|
}
|
|
77
|
-
}) : t &&
|
|
78
|
+
}) : t && Y([e]);
|
|
78
79
|
});
|
|
79
|
-
},
|
|
80
|
-
|
|
80
|
+
}, Z = () => {
|
|
81
|
+
K.length !== 0 && L({
|
|
81
82
|
title: D("workspaces.suspend.bulkTitle", "Suspend selected workspaces"),
|
|
82
|
-
description: `${D("workspaces.suspend.prefix", "Suspend")} ${
|
|
83
|
-
confirmText: `${D("workspaces.suspend.confirm", "Suspend")} ${
|
|
83
|
+
description: `${D("workspaces.suspend.prefix", "Suspend")} ${K.length} ${D(K.length === 1 ? "workspaces.suspend.bulkSuffixSingle" : "workspaces.suspend.bulkSuffixMany", K.length === 1 ? "selected workspace?" : "selected workspaces?")}`,
|
|
84
|
+
confirmText: `${D("workspaces.suspend.confirm", "Suspend")} ${K.length}`,
|
|
84
85
|
variant: "warning",
|
|
85
86
|
onConfirm: () => {
|
|
86
|
-
|
|
87
|
+
Y(K.map((e) => e.id));
|
|
87
88
|
}
|
|
88
89
|
});
|
|
89
90
|
}, Q = (e, t) => {
|
|
@@ -99,10 +100,10 @@ function E({ mode: E = "my" } = {}) {
|
|
|
99
100
|
}), n;
|
|
100
101
|
});
|
|
101
102
|
};
|
|
102
|
-
return
|
|
103
|
+
return le ? /* @__PURE__ */ C("div", {
|
|
103
104
|
className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
|
|
104
105
|
children: /* @__PURE__ */ C(a, { message: D("common.loadingPermissions", "Loading permissions...") })
|
|
105
|
-
}) : A(
|
|
106
|
+
}) : A(c.WORKSPACE_LIST) ? V ? /* @__PURE__ */ C("div", {
|
|
106
107
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
107
108
|
children: /* @__PURE__ */ C(a, { message: D("workspaces.list.loading", "Loading workspaces...") })
|
|
108
109
|
}) : H ? /* @__PURE__ */ C("div", {
|
|
@@ -117,7 +118,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
117
118
|
}
|
|
118
119
|
})
|
|
119
120
|
}) : /* @__PURE__ */ w("div", {
|
|
120
|
-
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-
|
|
121
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200",
|
|
121
122
|
children: [/* @__PURE__ */ w("div", {
|
|
122
123
|
className: "mx-auto flex w-full max-w-7xl flex-col gap-6",
|
|
123
124
|
children: [
|
|
@@ -132,11 +133,11 @@ function E({ mode: E = "my" } = {}) {
|
|
|
132
133
|
className: "max-w-2xl text-[var(--color-text-secondary)]",
|
|
133
134
|
children: D("workspaces.list.subtitle", "Manage organization workspaces, review their status, and open the workspace detail flow.")
|
|
134
135
|
})]
|
|
135
|
-
}), A(
|
|
136
|
+
}), A(c.WORKSPACE_CREATE) && /* @__PURE__ */ w("button", {
|
|
136
137
|
type: "button",
|
|
137
138
|
onClick: () => O(`${k}/workspaces/new`),
|
|
138
139
|
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90",
|
|
139
|
-
children: [/* @__PURE__ */ C(
|
|
140
|
+
children: [/* @__PURE__ */ C(se, {
|
|
140
141
|
size: 18,
|
|
141
142
|
"aria-hidden": "true"
|
|
142
143
|
}), /* @__PURE__ */ C("span", {
|
|
@@ -145,14 +146,53 @@ function E({ mode: E = "my" } = {}) {
|
|
|
145
146
|
})]
|
|
146
147
|
})]
|
|
147
148
|
}),
|
|
148
|
-
/* @__PURE__ */ w("div", {
|
|
149
|
-
className: "
|
|
149
|
+
B.length > 0 ? /* @__PURE__ */ w("div", {
|
|
150
|
+
className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ w(b, {
|
|
153
|
+
treatment: "metric",
|
|
154
|
+
className: "p-4",
|
|
155
|
+
children: [/* @__PURE__ */ C("p", {
|
|
156
|
+
className: "text-sm text-text-secondary",
|
|
157
|
+
children: D("workspaces.list.title", "Workspaces")
|
|
158
|
+
}), /* @__PURE__ */ C("p", {
|
|
159
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
160
|
+
children: B.length
|
|
161
|
+
})]
|
|
162
|
+
}),
|
|
163
|
+
/* @__PURE__ */ w(b, {
|
|
164
|
+
treatment: "metric",
|
|
165
|
+
className: "p-4",
|
|
166
|
+
children: [/* @__PURE__ */ C("p", {
|
|
167
|
+
className: "text-sm text-text-secondary",
|
|
168
|
+
children: D("workspaces.status.active", "Active")
|
|
169
|
+
}), /* @__PURE__ */ C("p", {
|
|
170
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
171
|
+
children: B.filter((e) => e.status === n.ACTIVE).length
|
|
172
|
+
})]
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ w(b, {
|
|
175
|
+
treatment: "metric",
|
|
176
|
+
className: "col-span-2 p-4 sm:col-span-1",
|
|
177
|
+
children: [/* @__PURE__ */ C("p", {
|
|
178
|
+
className: "text-sm text-text-secondary",
|
|
179
|
+
children: D("workspaces.list.members", "Members")
|
|
180
|
+
}), /* @__PURE__ */ C("p", {
|
|
181
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
182
|
+
children: B.reduce((e, t) => e + (t.memberCount ?? 0), 0)
|
|
183
|
+
})]
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
}) : null,
|
|
187
|
+
/* @__PURE__ */ w(b, {
|
|
188
|
+
treatment: "plain",
|
|
189
|
+
className: "border-border-seam p-4",
|
|
150
190
|
children: [/* @__PURE__ */ w("div", {
|
|
151
191
|
className: "flex flex-col gap-3 lg:flex-row lg:items-center",
|
|
152
192
|
children: [
|
|
153
193
|
/* @__PURE__ */ C(ee, {
|
|
154
194
|
value: j,
|
|
155
|
-
onChange:
|
|
195
|
+
onChange: ue,
|
|
156
196
|
placeholder: D("workspaces.list.searchPlaceholder", "Search workspaces..."),
|
|
157
197
|
label: D("workspaces.list.searchLabel", "Search workspaces"),
|
|
158
198
|
inputId: "workspaces-search",
|
|
@@ -169,7 +209,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
169
209
|
...N,
|
|
170
210
|
status: e.target.value ? e.target.value : void 0
|
|
171
211
|
}),
|
|
172
|
-
className: "bg-transparent text-[var(--color-text-primary)] focus:outline-none",
|
|
212
|
+
className: "bg-transparent text-[var(--color-text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
173
213
|
"aria-label": D("workspaces.list.filterByStatus", "Filter by workspace status"),
|
|
174
214
|
children: [
|
|
175
215
|
/* @__PURE__ */ C("option", {
|
|
@@ -199,7 +239,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
199
239
|
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
|
|
200
240
|
"aria-label": D("workspaces.list.refresh", "Refresh workspaces"),
|
|
201
241
|
title: D("workspaces.list.refresh", "Refresh workspaces"),
|
|
202
|
-
children: /* @__PURE__ */ C(
|
|
242
|
+
children: /* @__PURE__ */ C(ce, {
|
|
203
243
|
size: 18,
|
|
204
244
|
"aria-hidden": "true"
|
|
205
245
|
})
|
|
@@ -212,8 +252,8 @@ function E({ mode: E = "my" } = {}) {
|
|
|
212
252
|
children: [/* @__PURE__ */ w("label", {
|
|
213
253
|
className: "flex items-center gap-2 text-sm text-[var(--color-text-primary)]",
|
|
214
254
|
children: [/* @__PURE__ */ C(i, {
|
|
215
|
-
checked:
|
|
216
|
-
indeterminate:
|
|
255
|
+
checked: q,
|
|
256
|
+
indeterminate: J,
|
|
217
257
|
onChange: $,
|
|
218
258
|
ariaLabel: D("workspaces.list.selectAll", "Select all workspaces")
|
|
219
259
|
}), /* @__PURE__ */ C("span", { children: D("common.selectAllVisible", "Select all visible") })]
|
|
@@ -232,20 +272,20 @@ function E({ mode: E = "my" } = {}) {
|
|
|
232
272
|
" ",
|
|
233
273
|
D("common.selected", "selected")
|
|
234
274
|
]
|
|
235
|
-
}), A(
|
|
275
|
+
}), A(c.WORKSPACE_DELETE) && /* @__PURE__ */ w("button", {
|
|
236
276
|
type: "button",
|
|
237
|
-
onClick:
|
|
238
|
-
disabled:
|
|
277
|
+
onClick: Z,
|
|
278
|
+
disabled: K.length === 0 || G,
|
|
239
279
|
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
240
280
|
children: [
|
|
241
|
-
/* @__PURE__ */ C(
|
|
281
|
+
/* @__PURE__ */ C(y, {
|
|
242
282
|
size: 16,
|
|
243
283
|
"aria-hidden": "true"
|
|
244
284
|
}),
|
|
245
285
|
/* @__PURE__ */ C("span", { children: D("workspaces.list.suspendSelected", "Suspend Selected") }),
|
|
246
|
-
|
|
286
|
+
K.length > 0 ? /* @__PURE__ */ w("span", { children: [
|
|
247
287
|
"(",
|
|
248
|
-
|
|
288
|
+
K.length,
|
|
249
289
|
")"
|
|
250
290
|
] }) : null
|
|
251
291
|
]
|
|
@@ -253,24 +293,26 @@ function E({ mode: E = "my" } = {}) {
|
|
|
253
293
|
})]
|
|
254
294
|
}) : null]
|
|
255
295
|
}),
|
|
256
|
-
W.length === 0 ? /* @__PURE__ */ C(
|
|
257
|
-
|
|
296
|
+
W.length === 0 ? /* @__PURE__ */ C(b, {
|
|
297
|
+
treatment: "plain",
|
|
298
|
+
className: "border-border-seam p-6",
|
|
258
299
|
children: /* @__PURE__ */ C(o, {
|
|
259
|
-
icon: /* @__PURE__ */ C(
|
|
300
|
+
icon: /* @__PURE__ */ C(oe, {
|
|
260
301
|
size: 40,
|
|
261
302
|
"aria-hidden": "true"
|
|
262
303
|
}),
|
|
263
304
|
title: D("workspaces.list.emptyNoneTitle", "No workspaces found"),
|
|
264
|
-
description: A(
|
|
265
|
-
action: A(
|
|
305
|
+
description: A(c.WORKSPACE_CREATE) ? D("workspaces.list.emptyNoneDescription", "Create a workspace to start mapping members, organization ownership, and collaboration settings.") : D("workspaces.list.emptyNoneDescriptionViewer", "No workspaces have been created yet."),
|
|
306
|
+
action: A(c.WORKSPACE_CREATE) ? {
|
|
266
307
|
label: D("workspaces.create.button", "Create Workspace"),
|
|
267
308
|
onClick: () => O(`${k}/workspaces/new`)
|
|
268
309
|
} : void 0
|
|
269
310
|
})
|
|
270
|
-
}) : /* @__PURE__ */ w(
|
|
311
|
+
}) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C("div", {
|
|
271
312
|
className: "grid gap-4 md:hidden",
|
|
272
|
-
children: W.map((e) => /* @__PURE__ */ w(
|
|
273
|
-
|
|
313
|
+
children: W.map((e) => /* @__PURE__ */ w(b, {
|
|
314
|
+
treatment: "insight",
|
|
315
|
+
className: "border-border-seam p-4",
|
|
274
316
|
children: [/* @__PURE__ */ w("div", {
|
|
275
317
|
className: "flex items-start gap-3",
|
|
276
318
|
children: [/* @__PURE__ */ C(i, {
|
|
@@ -284,7 +326,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
284
326
|
children: [/* @__PURE__ */ C("h2", {
|
|
285
327
|
className: "text-base font-semibold text-[var(--color-text-primary)]",
|
|
286
328
|
children: e.name
|
|
287
|
-
}), /* @__PURE__ */ C(
|
|
329
|
+
}), /* @__PURE__ */ C(m, { status: e.status })]
|
|
288
330
|
}), /* @__PURE__ */ w("p", {
|
|
289
331
|
className: "mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]",
|
|
290
332
|
children: ["/", e.slug]
|
|
@@ -312,26 +354,26 @@ function E({ mode: E = "my" } = {}) {
|
|
|
312
354
|
type: "button",
|
|
313
355
|
onClick: () => O(`${k}/workspaces/${e.id}`),
|
|
314
356
|
className: "inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
|
|
315
|
-
children: [/* @__PURE__ */ C(
|
|
357
|
+
children: [/* @__PURE__ */ C(_, {
|
|
316
358
|
size: 16,
|
|
317
359
|
"aria-hidden": "true"
|
|
318
360
|
}), D("common.view", "View")]
|
|
319
361
|
}),
|
|
320
|
-
A(
|
|
362
|
+
A(c.WORKSPACE_UPDATE) && /* @__PURE__ */ w("button", {
|
|
321
363
|
type: "button",
|
|
322
364
|
onClick: () => O(`${k}/workspaces/${e.id}/edit`),
|
|
323
365
|
className: "inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
|
|
324
|
-
children: [/* @__PURE__ */ C(
|
|
366
|
+
children: [/* @__PURE__ */ C(v, {
|
|
325
367
|
size: 16,
|
|
326
368
|
"aria-hidden": "true"
|
|
327
369
|
}), D("common.edit", "Edit")]
|
|
328
370
|
}),
|
|
329
|
-
A(
|
|
371
|
+
A(c.WORKSPACE_DELETE) && /* @__PURE__ */ w("button", {
|
|
330
372
|
type: "button",
|
|
331
|
-
onClick: () =>
|
|
332
|
-
disabled:
|
|
373
|
+
onClick: () => X(e.id, e.name),
|
|
374
|
+
disabled: G,
|
|
333
375
|
className: "inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-sm text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
334
|
-
children: [/* @__PURE__ */ C(
|
|
376
|
+
children: [/* @__PURE__ */ C(y, {
|
|
335
377
|
size: 16,
|
|
336
378
|
"aria-hidden": "true"
|
|
337
379
|
}), D("workspaces.suspend.confirm", "Suspend")]
|
|
@@ -339,8 +381,9 @@ function E({ mode: E = "my" } = {}) {
|
|
|
339
381
|
]
|
|
340
382
|
})]
|
|
341
383
|
}, e.id))
|
|
342
|
-
}), /* @__PURE__ */ C(
|
|
343
|
-
|
|
384
|
+
}), /* @__PURE__ */ C(b, {
|
|
385
|
+
treatment: "plain",
|
|
386
|
+
className: "hidden overflow-hidden border-border-seam p-0 md:block",
|
|
344
387
|
children: /* @__PURE__ */ C("div", {
|
|
345
388
|
className: "overflow-x-auto",
|
|
346
389
|
children: /* @__PURE__ */ w("table", {
|
|
@@ -351,8 +394,8 @@ function E({ mode: E = "my" } = {}) {
|
|
|
351
394
|
/* @__PURE__ */ C("th", {
|
|
352
395
|
className: "w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]",
|
|
353
396
|
children: /* @__PURE__ */ C(i, {
|
|
354
|
-
checked:
|
|
355
|
-
indeterminate:
|
|
397
|
+
checked: q,
|
|
398
|
+
indeterminate: J,
|
|
356
399
|
onChange: $,
|
|
357
400
|
ariaLabel: D("workspaces.list.selectAll", "Select all workspaces")
|
|
358
401
|
})
|
|
@@ -375,7 +418,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
375
418
|
})
|
|
376
419
|
] })
|
|
377
420
|
}), /* @__PURE__ */ C("tbody", {
|
|
378
|
-
className: "divide-y divide-[var(--color-border-
|
|
421
|
+
className: "divide-y divide-[var(--color-border-seam)]",
|
|
379
422
|
children: W.map((e) => /* @__PURE__ */ w("tr", {
|
|
380
423
|
className: "transition-colors hover:bg-[var(--color-bg-subtle)]",
|
|
381
424
|
children: [
|
|
@@ -399,7 +442,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
399
442
|
}),
|
|
400
443
|
/* @__PURE__ */ C("td", {
|
|
401
444
|
className: "px-6 py-4 align-top",
|
|
402
|
-
children: /* @__PURE__ */ C(
|
|
445
|
+
children: /* @__PURE__ */ C(m, { status: e.status })
|
|
403
446
|
}),
|
|
404
447
|
/* @__PURE__ */ C("td", {
|
|
405
448
|
className: "px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]",
|
|
@@ -416,30 +459,30 @@ function E({ mode: E = "my" } = {}) {
|
|
|
416
459
|
className: "rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]",
|
|
417
460
|
title: `${D("common.view", "View")} ${e.name}`,
|
|
418
461
|
"aria-label": `${D("common.view", "View")} ${e.name}`,
|
|
419
|
-
children: /* @__PURE__ */ C(
|
|
462
|
+
children: /* @__PURE__ */ C(_, {
|
|
420
463
|
size: 18,
|
|
421
464
|
"aria-hidden": "true"
|
|
422
465
|
})
|
|
423
466
|
}),
|
|
424
|
-
A(
|
|
467
|
+
A(c.WORKSPACE_UPDATE) && /* @__PURE__ */ C("button", {
|
|
425
468
|
type: "button",
|
|
426
469
|
onClick: () => O(`${k}/workspaces/${e.id}/edit`),
|
|
427
470
|
className: "rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]",
|
|
428
471
|
title: `${D("common.edit", "Edit")} ${e.name}`,
|
|
429
472
|
"aria-label": `${D("common.edit", "Edit")} ${e.name}`,
|
|
430
|
-
children: /* @__PURE__ */ C(
|
|
473
|
+
children: /* @__PURE__ */ C(v, {
|
|
431
474
|
size: 18,
|
|
432
475
|
"aria-hidden": "true"
|
|
433
476
|
})
|
|
434
477
|
}),
|
|
435
|
-
A(
|
|
478
|
+
A(c.WORKSPACE_DELETE) && /* @__PURE__ */ C("button", {
|
|
436
479
|
type: "button",
|
|
437
|
-
onClick: () =>
|
|
438
|
-
disabled:
|
|
480
|
+
onClick: () => X(e.id, e.name),
|
|
481
|
+
disabled: G,
|
|
439
482
|
className: "rounded-lg p-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
440
483
|
title: `${D("workspaces.suspend.confirm", "Suspend")} ${e.name}`,
|
|
441
484
|
"aria-label": `${D("workspaces.suspend.confirm", "Suspend")} ${e.name}`,
|
|
442
|
-
children: /* @__PURE__ */ C(
|
|
485
|
+
children: /* @__PURE__ */ C(y, {
|
|
443
486
|
size: 18,
|
|
444
487
|
"aria-hidden": "true"
|
|
445
488
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Briefcase, Eye, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useDeleteWorkspace, useWorkspaces } from '../hooks/useWorkspaces';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { WorkspaceFilterInput } from '../types';\nimport { WorkspaceStatus } from '../types';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls the scope of the listing:\n * - `'my'` — membership-scoped (`myWorkspaces`); the default for user-facing\n * app shells. A regular user only sees workspaces they belong to.\n * - `'admin'` — platform-wide (`allWorkspaces`, super-admin only); the admin app.\n */\nexport interface WorkspacesListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function WorkspacesListPage({ mode = 'my' }: WorkspacesListPageProps = {}) {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [filter, setFilter] = useState<WorkspaceFilterInput>({});\n const [selectedWorkspaceIds, setSelectedWorkspaceIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // 'my' shells call the self-scoped `myWorkspaces` (no server-side filter arg),\n // so we over-fetch a page and filter client-side below. The admin app keeps\n // the server-filtered, paginated `allWorkspaces`.\n const scope = mode === 'admin' ? 'all' : 'my';\n const {\n workspaces: fetchedWorkspaces,\n loading,\n error,\n refetch,\n } = useWorkspaces(\n { ...filter, search: debouncedSearchQuery || undefined },\n scope === 'my' ? 100 : 20,\n 0,\n scope\n );\n\n const workspaces = useMemo(() => {\n if (scope !== 'my') return fetchedWorkspaces;\n const query = debouncedSearchQuery.trim().toLowerCase();\n return fetchedWorkspaces.filter((workspace) => {\n const matchesSearch =\n !query ||\n workspace.name.toLowerCase().includes(query) ||\n (workspace.slug?.toLowerCase().includes(query) ?? false);\n const matchesStatus = !filter.status || workspace.status === filter.status;\n return matchesSearch && matchesStatus;\n });\n }, [fetchedWorkspaces, scope, debouncedSearchQuery, filter.status]);\n\n const { deleteWorkspace, loading: deleteLoading } = useDeleteWorkspace();\n\n useEffect(() => {\n setSelectedWorkspaceIds((previousSelection) => {\n const visibleIds = new Set(workspaces.map((workspace) => workspace.id));\n const nextSelection = new Set(\n [...previousSelection].filter((workspaceId) => visibleIds.has(workspaceId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [workspaces]);\n\n const selectedWorkspaces = useMemo(\n () => workspaces.filter((workspace) => selectedWorkspaceIds.has(workspace.id)),\n [selectedWorkspaceIds, workspaces]\n );\n\n const allVisibleSelected =\n workspaces.length > 0 &&\n workspaces.every((workspace) => selectedWorkspaceIds.has(workspace.id));\n const partiallySelected =\n workspaces.some((workspace) => selectedWorkspaceIds.has(workspace.id)) && !allVisibleSelected;\n\n const executeSuspend = async (workspaceIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n workspaceIds.map(async (workspaceId) => {\n const result = await deleteWorkspace(workspaceId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.suspend.failed', 'Failed to suspend workspace')\n );\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedWorkspaceIds(new Set());\n await refetch();\n const successMsg =\n workspaceIds.length === 1\n ? tr('workspaces.suspend.successSingle', 'Workspace suspended successfully')\n : `${workspaceIds.length} ${tr('workspaces.suspend.successMany', 'workspaces suspended successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (suspendError) {\n const errorMsg =\n suspendError instanceof Error\n ? suspendError.message\n : tr('workspaces.suspend.failed', 'Failed to suspend workspace');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (workspaceId: string, workspaceName: string) => {\n nativeImpact('medium');\n const title = tr('workspaces.suspend.title', 'Suspend workspace');\n const description = `${tr('workspaces.suspend.prefix', 'Suspend')} ${workspaceName}? ${tr(\n 'workspaces.suspend.suffix',\n 'Workspace members will lose access until it is reactivated.'\n )}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('workspaces.suspend.confirm', 'Suspend'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('workspaces.suspend.confirm', 'Suspend'),\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend([workspaceId]);\n },\n });\n } else if (nativeResult) {\n void executeSuspend([workspaceId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedWorkspaces.length === 0) return;\n\n openConfirmDialog({\n title: tr('workspaces.suspend.bulkTitle', 'Suspend selected workspaces'),\n description: `${tr('workspaces.suspend.prefix', 'Suspend')} ${selectedWorkspaces.length} ${tr(\n selectedWorkspaces.length === 1\n ? 'workspaces.suspend.bulkSuffixSingle'\n : 'workspaces.suspend.bulkSuffixMany',\n selectedWorkspaces.length === 1 ? 'selected workspace?' : 'selected workspaces?'\n )}`,\n confirmText: `${tr('workspaces.suspend.confirm', 'Suspend')} ${selectedWorkspaces.length}`,\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend(selectedWorkspaces.map((workspace) => workspace.id));\n },\n });\n };\n\n const toggleWorkspaceSelection = (workspaceId: string, checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(workspaceId);\n } else {\n nextSelection.delete(workspaceId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllWorkspaces = (checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n workspaces.forEach((workspace) => {\n if (checked) {\n nextSelection.add(workspace.id);\n } else {\n nextSelection.delete(workspace.id);\n }\n });\n return nextSelection;\n });\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_LIST)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.noPermission', \"You don't have permission to view workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.list.loading', 'Loading workspaces...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {tr('workspaces.list.title', 'Workspaces')}\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.list.subtitle',\n 'Manage organization workspaces, review their status, and open the workspace detail flow.'\n )}\n </p>\n </div>\n\n {hasPermission(PERMISSIONS.WORKSPACE_CREATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n <span className=\"font-medium\">\n {tr('workspaces.create.button', 'Create Workspace')}\n </span>\n </button>\n )}\n </div>\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('workspaces.list.searchPlaceholder', 'Search workspaces...')}\n label={tr('workspaces.list.searchLabel', 'Search workspaces')}\n inputId=\"workspaces-search\"\n className=\"flex-1\"\n />\n\n <label className=\"flex min-h-11 min-w-[180px] flex-col justify-center rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-secondary)]\">\n <span className=\"sr-only\">\n {tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n </span>\n <select\n value={filter.status || ''}\n onChange={(event) =>\n setFilter({\n ...filter,\n status: event.target.value\n ? (event.target.value as WorkspaceStatus)\n : undefined,\n })\n }\n className=\"bg-transparent text-[var(--color-text-primary)] focus:outline-none\"\n aria-label={tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n >\n <option value=\"\">{tr('workspaces.list.allStatuses', 'All statuses')}</option>\n <option value={WorkspaceStatus.ACTIVE}>\n {tr('workspaces.status.active', 'Active')}\n </option>\n <option value={WorkspaceStatus.INACTIVE}>\n {tr('workspaces.status.inactive', 'Inactive')}\n </option>\n <option value={WorkspaceStatus.ARCHIVED}>\n {tr('workspaces.status.archived', 'Archived')}\n </option>\n </select>\n </label>\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('workspaces.list.refresh', 'Refresh workspaces')}\n title={tr('workspaces.list.refresh', 'Refresh workspaces')}\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {workspaces.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedWorkspaceIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedWorkspaceIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedWorkspaceIds.size} {tr('common.selected', 'selected')}\n </span>\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedWorkspaces.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.list.suspendSelected', 'Suspend Selected')}</span>\n {selectedWorkspaces.length > 0 ? (\n <span>({selectedWorkspaces.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </div>\n\n {workspaces.length === 0 ? (\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-6 shadow-[var(--shadow-elevation-1)]\">\n <EmptyState\n icon={<Briefcase size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.list.emptyNoneTitle', 'No workspaces found')}\n description={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? tr(\n 'workspaces.list.emptyNoneDescription',\n 'Create a workspace to start mapping members, organization ownership, and collaboration settings.'\n )\n : tr(\n 'workspaces.list.emptyNoneDescriptionViewer',\n 'No workspaces have been created yet.'\n )\n }\n action={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? {\n label: tr('workspaces.create.button', 'Create Workspace'),\n onClick: () => navigate(`${basePath}/workspaces/new`),\n }\n : undefined\n }\n />\n </div>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {workspaces.map((workspace) => (\n <article\n key={workspace.id}\n className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n\n <div className=\"min-w-0 flex-1 space-y-3\">\n <div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h2>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.memberCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-sm text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('workspaces.suspend.confirm', 'Suspend')}\n </button>\n )}\n </div>\n </article>\n ))}\n </div>\n\n <div className=\"hidden overflow-hidden rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-[var(--shadow-elevation-1)] md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.column.workspace', 'Workspace')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-default)]\">\n {workspaces.map((workspace) => (\n <tr\n key={workspace.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <WorkspaceStatusBadge status={workspace.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(workspace.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${workspace.name}`}\n aria-label={`${tr('common.view', 'View')} ${workspace.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(`${basePath}/workspaces/${workspace.id}/edit`)\n }\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"rounded-lg p-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n title={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n aria-label={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Briefcase, Eye, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useDeleteWorkspace, useWorkspaces } from '../hooks/useWorkspaces';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { WorkspaceFilterInput } from '../types';\nimport { WorkspaceStatus } from '../types';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls the scope of the listing:\n * - `'my'` — membership-scoped (`myWorkspaces`); the default for user-facing\n * app shells. A regular user only sees workspaces they belong to.\n * - `'admin'` — platform-wide (`allWorkspaces`, super-admin only); the admin app.\n */\nexport interface WorkspacesListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function WorkspacesListPage({ mode = 'my' }: WorkspacesListPageProps = {}) {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [filter, setFilter] = useState<WorkspaceFilterInput>({});\n const [selectedWorkspaceIds, setSelectedWorkspaceIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // 'my' shells call the self-scoped `myWorkspaces` (no server-side filter arg),\n // so we over-fetch a page and filter client-side below. The admin app keeps\n // the server-filtered, paginated `allWorkspaces`.\n const scope = mode === 'admin' ? 'all' : 'my';\n const {\n workspaces: fetchedWorkspaces,\n loading,\n error,\n refetch,\n } = useWorkspaces(\n { ...filter, search: debouncedSearchQuery || undefined },\n scope === 'my' ? 100 : 20,\n 0,\n scope\n );\n\n const workspaces = useMemo(() => {\n if (scope !== 'my') return fetchedWorkspaces;\n const query = debouncedSearchQuery.trim().toLowerCase();\n return fetchedWorkspaces.filter((workspace) => {\n const matchesSearch =\n !query ||\n workspace.name.toLowerCase().includes(query) ||\n (workspace.slug?.toLowerCase().includes(query) ?? false);\n const matchesStatus = !filter.status || workspace.status === filter.status;\n return matchesSearch && matchesStatus;\n });\n }, [fetchedWorkspaces, scope, debouncedSearchQuery, filter.status]);\n\n const { deleteWorkspace, loading: deleteLoading } = useDeleteWorkspace();\n\n useEffect(() => {\n setSelectedWorkspaceIds((previousSelection) => {\n const visibleIds = new Set(workspaces.map((workspace) => workspace.id));\n const nextSelection = new Set(\n [...previousSelection].filter((workspaceId) => visibleIds.has(workspaceId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [workspaces]);\n\n const selectedWorkspaces = useMemo(\n () => workspaces.filter((workspace) => selectedWorkspaceIds.has(workspace.id)),\n [selectedWorkspaceIds, workspaces]\n );\n\n const allVisibleSelected =\n workspaces.length > 0 &&\n workspaces.every((workspace) => selectedWorkspaceIds.has(workspace.id));\n const partiallySelected =\n workspaces.some((workspace) => selectedWorkspaceIds.has(workspace.id)) && !allVisibleSelected;\n\n const executeSuspend = async (workspaceIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n workspaceIds.map(async (workspaceId) => {\n const result = await deleteWorkspace(workspaceId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.suspend.failed', 'Failed to suspend workspace')\n );\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedWorkspaceIds(new Set());\n await refetch();\n const successMsg =\n workspaceIds.length === 1\n ? tr('workspaces.suspend.successSingle', 'Workspace suspended successfully')\n : `${workspaceIds.length} ${tr('workspaces.suspend.successMany', 'workspaces suspended successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (suspendError) {\n const errorMsg =\n suspendError instanceof Error\n ? suspendError.message\n : tr('workspaces.suspend.failed', 'Failed to suspend workspace');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (workspaceId: string, workspaceName: string) => {\n nativeImpact('medium');\n const title = tr('workspaces.suspend.title', 'Suspend workspace');\n const description = `${tr('workspaces.suspend.prefix', 'Suspend')} ${workspaceName}? ${tr(\n 'workspaces.suspend.suffix',\n 'Workspace members will lose access until it is reactivated.'\n )}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('workspaces.suspend.confirm', 'Suspend'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('workspaces.suspend.confirm', 'Suspend'),\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend([workspaceId]);\n },\n });\n } else if (nativeResult) {\n void executeSuspend([workspaceId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedWorkspaces.length === 0) return;\n\n openConfirmDialog({\n title: tr('workspaces.suspend.bulkTitle', 'Suspend selected workspaces'),\n description: `${tr('workspaces.suspend.prefix', 'Suspend')} ${selectedWorkspaces.length} ${tr(\n selectedWorkspaces.length === 1\n ? 'workspaces.suspend.bulkSuffixSingle'\n : 'workspaces.suspend.bulkSuffixMany',\n selectedWorkspaces.length === 1 ? 'selected workspace?' : 'selected workspaces?'\n )}`,\n confirmText: `${tr('workspaces.suspend.confirm', 'Suspend')} ${selectedWorkspaces.length}`,\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend(selectedWorkspaces.map((workspace) => workspace.id));\n },\n });\n };\n\n const toggleWorkspaceSelection = (workspaceId: string, checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(workspaceId);\n } else {\n nextSelection.delete(workspaceId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllWorkspaces = (checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n workspaces.forEach((workspace) => {\n if (checked) {\n nextSelection.add(workspace.id);\n } else {\n nextSelection.delete(workspace.id);\n }\n });\n return nextSelection;\n });\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_LIST)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.noPermission', \"You don't have permission to view workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.list.loading', 'Loading workspaces...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {tr('workspaces.list.title', 'Workspaces')}\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.list.subtitle',\n 'Manage organization workspaces, review their status, and open the workspace detail flow.'\n )}\n </p>\n </div>\n\n {hasPermission(PERMISSIONS.WORKSPACE_CREATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n <span className=\"font-medium\">\n {tr('workspaces.create.button', 'Create Workspace')}\n </span>\n </button>\n )}\n </div>\n\n {fetchedWorkspaces.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('workspaces.list.title', 'Workspaces')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {fetchedWorkspaces.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('workspaces.status.active', 'Active')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {fetchedWorkspaces.filter((w) => w.status === WorkspaceStatus.ACTIVE).length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"col-span-2 p-4 sm:col-span-1\">\n <p className=\"text-sm text-text-secondary\">\n {tr('workspaces.list.members', 'Members')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {fetchedWorkspaces.reduce((sum, w) => sum + (w.memberCount ?? 0), 0)}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('workspaces.list.searchPlaceholder', 'Search workspaces...')}\n label={tr('workspaces.list.searchLabel', 'Search workspaces')}\n inputId=\"workspaces-search\"\n className=\"flex-1\"\n />\n\n <label className=\"flex min-h-11 min-w-[180px] flex-col justify-center rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-secondary)]\">\n <span className=\"sr-only\">\n {tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n </span>\n <select\n value={filter.status || ''}\n onChange={(event) =>\n setFilter({\n ...filter,\n status: event.target.value\n ? (event.target.value as WorkspaceStatus)\n : undefined,\n })\n }\n className=\"bg-transparent text-[var(--color-text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n >\n <option value=\"\">{tr('workspaces.list.allStatuses', 'All statuses')}</option>\n <option value={WorkspaceStatus.ACTIVE}>\n {tr('workspaces.status.active', 'Active')}\n </option>\n <option value={WorkspaceStatus.INACTIVE}>\n {tr('workspaces.status.inactive', 'Inactive')}\n </option>\n <option value={WorkspaceStatus.ARCHIVED}>\n {tr('workspaces.status.archived', 'Archived')}\n </option>\n </select>\n </label>\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('workspaces.list.refresh', 'Refresh workspaces')}\n title={tr('workspaces.list.refresh', 'Refresh workspaces')}\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {workspaces.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedWorkspaceIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedWorkspaceIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedWorkspaceIds.size} {tr('common.selected', 'selected')}\n </span>\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedWorkspaces.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.list.suspendSelected', 'Suspend Selected')}</span>\n {selectedWorkspaces.length > 0 ? (\n <span>({selectedWorkspaces.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </GlassCard>\n\n {workspaces.length === 0 ? (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <EmptyState\n icon={<Briefcase size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.list.emptyNoneTitle', 'No workspaces found')}\n description={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? tr(\n 'workspaces.list.emptyNoneDescription',\n 'Create a workspace to start mapping members, organization ownership, and collaboration settings.'\n )\n : tr(\n 'workspaces.list.emptyNoneDescriptionViewer',\n 'No workspaces have been created yet.'\n )\n }\n action={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? {\n label: tr('workspaces.create.button', 'Create Workspace'),\n onClick: () => navigate(`${basePath}/workspaces/new`),\n }\n : undefined\n }\n />\n </GlassCard>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {workspaces.map((workspace) => (\n <GlassCard\n key={workspace.id}\n treatment=\"insight\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n\n <div className=\"min-w-0 flex-1 space-y-3\">\n <div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h2>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.memberCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-sm text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('workspaces.suspend.confirm', 'Suspend')}\n </button>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n\n <GlassCard\n treatment=\"plain\"\n className=\"hidden overflow-hidden border-border-seam p-0 md:block\"\n >\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.column.workspace', 'Workspace')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-seam)]\">\n {workspaces.map((workspace) => (\n <tr\n key={workspace.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <WorkspaceStatusBadge status={workspace.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(workspace.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${workspace.name}`}\n aria-label={`${tr('common.view', 'View')} ${workspace.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(`${basePath}/workspaces/${workspace.id}/edit`)\n }\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"rounded-lg p-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n title={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n aria-label={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|