@burdenoff/microfe-workspaces 2026.625.4 → 2026.626.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/hooks/useMemberMutations.js +6 -6
- package/dist/hooks/useMemberMutations.js.map +1 -1
- package/dist/pages/ActivityListPage.js +94 -90
- package/dist/pages/ActivityListPage.js.map +1 -1
- package/dist/pages/CreateWorkspacePage.js +68 -63
- package/dist/pages/CreateWorkspacePage.js.map +1 -1
- package/dist/pages/InviteAcceptancePage.js +101 -96
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +185 -184
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +70 -68
- package/dist/pages/PendingInvitesPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +119 -78
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +105 -104
- package/dist/pages/ProjectMembersPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +158 -157
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +236 -198
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceInvitePage.js +341 -300
- package/dist/pages/WorkspaceInvitePage.js.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.js +87 -85
- package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +122 -121
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +55 -51
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/widgets/GroupsWidget.js +16 -17
- package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TagCloudWidget.js +18 -19
- package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +10 -11
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,145 +1,145 @@
|
|
|
1
1
|
import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
2
2
|
import { useWorkspacesStore as t } from "../store/workspacesStore.js";
|
|
3
|
-
import { useMyWorkspaces as
|
|
4
|
-
import { useMyPendingInvitations as
|
|
5
|
-
import { useScopedNavigation as
|
|
6
|
-
import { WorkspaceCard as
|
|
7
|
-
import { WORKSPACE_PERMISSIONS as
|
|
8
|
-
import { tWithFallback as
|
|
9
|
-
import { useWorkspacesPageView as
|
|
10
|
-
import { useEffect as
|
|
11
|
-
import { Grid3X3 as
|
|
12
|
-
import { Fragment as
|
|
13
|
-
import { AuroraBackground as
|
|
14
|
-
import { useNavigate as
|
|
15
|
-
import { useDebounce as
|
|
16
|
-
import { PermissionButton as
|
|
17
|
-
import { useI18n as
|
|
3
|
+
import { useMyWorkspaces as n } from "../hooks/useWorkspaces.js";
|
|
4
|
+
import { useMyPendingInvitations as r } from "../hooks/usePendingInvitations.js";
|
|
5
|
+
import { useScopedNavigation as i } from "../hooks/useScopedNavigation.js";
|
|
6
|
+
import { WorkspaceCard as a } from "../components/WorkspaceCard.js";
|
|
7
|
+
import { WORKSPACE_PERMISSIONS as o } from "../constants/permissions.js";
|
|
8
|
+
import { tWithFallback as s } from "../utils/i18n.js";
|
|
9
|
+
import { useWorkspacesPageView as c } from "../hooks/useWorkspacesPageView.js";
|
|
10
|
+
import { useEffect as l, useState as u } from "react";
|
|
11
|
+
import { Grid3X3 as d, List as f, Mail as p, MoreHorizontal as m, Plus as h, Search as g, UserPlus as _ } from "lucide-react";
|
|
12
|
+
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { AuroraBackground as x, Badge as S, Button as C, DropdownMenu as w, DropdownMenuContent as T, DropdownMenuItem as E, DropdownMenuTrigger as ee, GradientText as te, IllustratedEmptyState as D, Input as O, PagePurpose as k, Skeleton as A } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { useNavigate as j } from "react-router-dom";
|
|
15
|
+
import { useDebounce as M } from "@burdenoff/fe-libs/shared/hooks";
|
|
16
|
+
import { PermissionButton as N } from "@burdenoff/fe-libs/shared/components";
|
|
17
|
+
import { useI18n as P } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
18
18
|
//#region src/pages/WorkspacesListPage.tsx
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
let { t:
|
|
22
|
-
|
|
23
|
-
}, [
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
function F() {
|
|
20
|
+
c("workspaces.list");
|
|
21
|
+
let { t: F } = P(), I = j(), { basePath: L = "/", currentUser: R, workspaceId: z } = e(), { withCurrentSearch: B } = i(), { viewMode: V, setViewMode: H, workspaceFilters: U, setWorkspaceFilters: W } = t(), G = () => {
|
|
22
|
+
I(B(`${L}/new`));
|
|
23
|
+
}, [K, q] = u(U.search || ""), J = M(K, 500);
|
|
24
|
+
l(() => {
|
|
25
|
+
J !== U.search && W({ search: J });
|
|
26
26
|
}, [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
J,
|
|
28
|
+
U.search,
|
|
29
|
+
W
|
|
30
30
|
]);
|
|
31
|
-
let { data:
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
}, $ =
|
|
36
|
-
...
|
|
37
|
-
items:
|
|
38
|
-
total:
|
|
31
|
+
let { data: Y, isLoading: X, error: Z } = n(), { data: ne = [] } = r(R?.email), Q = ne.length, re = () => {
|
|
32
|
+
I(B(`${L}/invites`));
|
|
33
|
+
}, ie = () => {
|
|
34
|
+
z && I(B(`${L}/${z}/invite`));
|
|
35
|
+
}, $ = Y ? {
|
|
36
|
+
...Y,
|
|
37
|
+
items: J ? Y.items.filter((e) => e.name.toLowerCase().includes(J.toLowerCase())) : Y.items,
|
|
38
|
+
total: J ? Y.items.filter((e) => e.name.toLowerCase().includes(J.toLowerCase())).length : Y.total
|
|
39
39
|
} : void 0;
|
|
40
|
-
return
|
|
40
|
+
return Z ? /* @__PURE__ */ y("div", {
|
|
41
41
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
42
|
-
children: /* @__PURE__ */
|
|
42
|
+
children: /* @__PURE__ */ b("div", {
|
|
43
43
|
className: "flex flex-col items-center justify-center py-12",
|
|
44
|
-
children: [/* @__PURE__ */
|
|
44
|
+
children: [/* @__PURE__ */ y("p", {
|
|
45
45
|
className: "text-status-error-text text-lg font-semibold",
|
|
46
|
-
children:
|
|
47
|
-
}), /* @__PURE__ */
|
|
46
|
+
children: s(F, "workspacesList.loadError", "Error loading workspaces")
|
|
47
|
+
}), /* @__PURE__ */ y("p", {
|
|
48
48
|
className: "text-text-secondary text-sm mt-2",
|
|
49
|
-
children:
|
|
49
|
+
children: Z instanceof Error ? Z.message : s(F, "workspacesList.unknownError", "Unknown error")
|
|
50
50
|
})]
|
|
51
51
|
})
|
|
52
|
-
}) : /* @__PURE__ */
|
|
52
|
+
}) : /* @__PURE__ */ b("div", {
|
|
53
53
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
54
54
|
children: [
|
|
55
|
-
/* @__PURE__ */
|
|
55
|
+
/* @__PURE__ */ b("div", {
|
|
56
56
|
className: "relative overflow-hidden rounded-card flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 px-3 py-3 sm:px-4 sm:py-4",
|
|
57
57
|
"data-tour": "workspaces-list-header",
|
|
58
58
|
children: [
|
|
59
|
-
/* @__PURE__ */
|
|
60
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ y(x, { intensity: "subtle" }),
|
|
60
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
|
|
61
61
|
className: "text-2xl sm:text-3xl font-bold",
|
|
62
|
-
children: /* @__PURE__ */
|
|
63
|
-
}), /* @__PURE__ */
|
|
62
|
+
children: /* @__PURE__ */ y(te, { children: s(F, "workspacesList.title", "Workspaces") })
|
|
63
|
+
}), /* @__PURE__ */ y("p", {
|
|
64
64
|
className: "text-sm sm:text-base text-text-secondary",
|
|
65
|
-
children:
|
|
65
|
+
children: s(F, "workspacesList.description", "Manage and organize your workspaces")
|
|
66
66
|
})] }),
|
|
67
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ b("div", {
|
|
68
68
|
className: "flex items-center gap-2",
|
|
69
69
|
"data-tour": "workspaces-list-actions",
|
|
70
70
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
72
|
-
variant:
|
|
71
|
+
/* @__PURE__ */ y(C, {
|
|
72
|
+
variant: V === "grid" ? "default" : "outline",
|
|
73
73
|
size: "icon",
|
|
74
|
-
onClick: () =>
|
|
74
|
+
onClick: () => H("grid"),
|
|
75
75
|
className: "hidden sm:flex",
|
|
76
|
-
"aria-label":
|
|
77
|
-
title:
|
|
78
|
-
children: /* @__PURE__ */
|
|
76
|
+
"aria-label": s(F, "workspacesList.gridViewAriaLabel", "Show workspaces in grid view"),
|
|
77
|
+
title: s(F, "workspacesList.gridViewTitle", "Grid view"),
|
|
78
|
+
children: /* @__PURE__ */ y(d, { size: 20 })
|
|
79
79
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
variant:
|
|
80
|
+
/* @__PURE__ */ y(C, {
|
|
81
|
+
variant: V === "list" ? "default" : "outline",
|
|
82
82
|
size: "icon",
|
|
83
|
-
onClick: () =>
|
|
83
|
+
onClick: () => H("list"),
|
|
84
84
|
className: "hidden sm:flex",
|
|
85
|
-
"aria-label":
|
|
86
|
-
title:
|
|
87
|
-
children: /* @__PURE__ */
|
|
85
|
+
"aria-label": s(F, "workspacesList.listViewAriaLabel", "Show workspaces in list view"),
|
|
86
|
+
title: s(F, "workspacesList.listViewTitle", "List view"),
|
|
87
|
+
children: /* @__PURE__ */ y(f, { size: 20 })
|
|
88
88
|
}),
|
|
89
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ b(w, { children: [/* @__PURE__ */ y(ee, {
|
|
90
90
|
asChild: !0,
|
|
91
|
-
children: /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ b(C, {
|
|
92
92
|
variant: "outline",
|
|
93
93
|
size: "icon",
|
|
94
94
|
"aria-label": "More actions",
|
|
95
95
|
className: "relative",
|
|
96
|
-
children: [/* @__PURE__ */
|
|
96
|
+
children: [/* @__PURE__ */ y(m, { size: 18 }), Q > 0 ? /* @__PURE__ */ y("span", { className: "absolute -top-1 -right-1 flex size-2 rounded-full bg-action-primary-bg" }) : null]
|
|
97
97
|
})
|
|
98
|
-
}), /* @__PURE__ */
|
|
98
|
+
}), /* @__PURE__ */ b(T, {
|
|
99
99
|
align: "end",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
101
|
-
permission:
|
|
100
|
+
children: [/* @__PURE__ */ y(N, {
|
|
101
|
+
permission: o.MEMBER_CREATE,
|
|
102
102
|
deniedBehavior: "disable",
|
|
103
|
-
deniedTooltip:
|
|
104
|
-
children: /* @__PURE__ */
|
|
105
|
-
onSelect:
|
|
106
|
-
disabled: !
|
|
103
|
+
deniedTooltip: s(F, "workspacesList.inviteDeniedTooltip", "You don't have permission to invite members into the current workspace"),
|
|
104
|
+
children: /* @__PURE__ */ b(E, {
|
|
105
|
+
onSelect: ie,
|
|
106
|
+
disabled: !z,
|
|
107
107
|
className: "gap-2",
|
|
108
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ y(_, { size: 16 }), s(F, "workspacesList.inviteMemberButton", "Invite Member")]
|
|
109
109
|
})
|
|
110
|
-
}), /* @__PURE__ */
|
|
111
|
-
onSelect:
|
|
110
|
+
}), /* @__PURE__ */ b(E, {
|
|
111
|
+
onSelect: re,
|
|
112
112
|
className: "gap-2",
|
|
113
113
|
children: [
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ y(p, { size: 16 }),
|
|
115
|
+
/* @__PURE__ */ y("span", {
|
|
116
116
|
className: "flex-1",
|
|
117
|
-
children:
|
|
117
|
+
children: s(F, "workspacesList.pendingInvitesButton", "Pending Invites")
|
|
118
118
|
}),
|
|
119
|
-
Q > 0 ? /* @__PURE__ */
|
|
119
|
+
Q > 0 ? /* @__PURE__ */ y(S, {
|
|
120
120
|
variant: "secondary",
|
|
121
121
|
children: Q
|
|
122
122
|
}) : null
|
|
123
123
|
]
|
|
124
124
|
})]
|
|
125
125
|
})] }),
|
|
126
|
-
/* @__PURE__ */
|
|
127
|
-
permission:
|
|
126
|
+
/* @__PURE__ */ y(N, {
|
|
127
|
+
permission: o.WORKSPACE_CREATE,
|
|
128
128
|
deniedBehavior: "disable",
|
|
129
|
-
deniedTooltip:
|
|
130
|
-
children: /* @__PURE__ */
|
|
131
|
-
onClick:
|
|
129
|
+
deniedTooltip: s(F, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
130
|
+
children: /* @__PURE__ */ b(C, {
|
|
131
|
+
onClick: G,
|
|
132
132
|
className: "gap-2",
|
|
133
133
|
"data-tour": "workspaces-create-button",
|
|
134
134
|
children: [
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ y(h, { size: 20 }),
|
|
136
|
+
/* @__PURE__ */ y("span", {
|
|
137
137
|
className: "hidden sm:inline",
|
|
138
|
-
children:
|
|
138
|
+
children: s(F, "workspacesList.createButton", "Create Workspace")
|
|
139
139
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ y("span", {
|
|
141
141
|
className: "sm:hidden",
|
|
142
|
-
children:
|
|
142
|
+
children: s(F, "workspacesList.createButtonShort", "Create")
|
|
143
143
|
})
|
|
144
144
|
]
|
|
145
145
|
})
|
|
@@ -148,71 +148,72 @@ function P() {
|
|
|
148
148
|
})
|
|
149
149
|
]
|
|
150
150
|
}),
|
|
151
|
-
/* @__PURE__ */ y("
|
|
151
|
+
/* @__PURE__ */ y(k, { children: s(F, "workspacesList.purpose", "Workspaces are shared homes for a team or initiative — each one groups its own projects, members, agents and activity. Create one per team, client or product line to keep work isolated, then switch between them from the sidebar.") }),
|
|
152
|
+
/* @__PURE__ */ b("div", {
|
|
152
153
|
className: "relative",
|
|
153
154
|
"data-tour": "workspaces-search-input",
|
|
154
|
-
children: [/* @__PURE__ */
|
|
155
|
+
children: [/* @__PURE__ */ y(g, {
|
|
155
156
|
className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary",
|
|
156
157
|
size: 20
|
|
157
|
-
}), /* @__PURE__ */
|
|
158
|
-
placeholder:
|
|
159
|
-
value:
|
|
158
|
+
}), /* @__PURE__ */ y(O, {
|
|
159
|
+
placeholder: s(F, "workspacesList.searchPlaceholder", "Search workspaces..."),
|
|
160
|
+
value: K,
|
|
160
161
|
onChange: (e) => {
|
|
161
|
-
|
|
162
|
+
q(e.target.value);
|
|
162
163
|
},
|
|
163
164
|
className: "pl-[3.25rem]"
|
|
164
165
|
})]
|
|
165
166
|
}),
|
|
166
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ y("div", {
|
|
167
168
|
className: "space-y-4 sm:space-y-6",
|
|
168
169
|
"data-tour": "workspaces-view-container",
|
|
169
|
-
children:
|
|
170
|
+
children: X ? /* @__PURE__ */ y("div", {
|
|
170
171
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
171
|
-
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */
|
|
172
|
+
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ b("div", {
|
|
172
173
|
className: "space-y-3 p-6 border border-border-seam rounded-lg",
|
|
173
|
-
children: [/* @__PURE__ */
|
|
174
|
+
children: [/* @__PURE__ */ b("div", {
|
|
174
175
|
className: "flex items-center gap-3",
|
|
175
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ y(A, { className: "size-12 rounded-lg" }), /* @__PURE__ */ b("div", {
|
|
176
177
|
className: "space-y-2 flex-1",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ y(A, { className: "h-4 w-3/4" }), /* @__PURE__ */ y(A, { className: "h-3 w-1/2" })]
|
|
178
179
|
})]
|
|
179
|
-
}), /* @__PURE__ */
|
|
180
|
+
}), /* @__PURE__ */ y(A, { className: "h-3 w-1/3" })]
|
|
180
181
|
}, t))
|
|
181
|
-
}) : $?.items.length === 0 ? /* @__PURE__ */
|
|
182
|
-
illustration:
|
|
183
|
-
title:
|
|
184
|
-
description:
|
|
185
|
-
action:
|
|
186
|
-
permission:
|
|
182
|
+
}) : $?.items.length === 0 ? /* @__PURE__ */ y(D, {
|
|
183
|
+
illustration: U.search ? "empty-search" : "onboarding",
|
|
184
|
+
title: s(F, "workspacesList.emptyTitle", "No workspaces found"),
|
|
185
|
+
description: U.search ? s(F, "workspacesList.emptySearchHint", "Try adjusting your search criteria") : s(F, "workspacesList.emptyCreateHint", "Get started by creating your first workspace"),
|
|
186
|
+
action: U.search ? void 0 : /* @__PURE__ */ y(N, {
|
|
187
|
+
permission: o.WORKSPACE_CREATE,
|
|
187
188
|
deniedBehavior: "disable",
|
|
188
|
-
deniedTooltip:
|
|
189
|
-
children: /* @__PURE__ */
|
|
190
|
-
onClick:
|
|
189
|
+
deniedTooltip: s(F, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
190
|
+
children: /* @__PURE__ */ b(C, {
|
|
191
|
+
onClick: G,
|
|
191
192
|
className: "gap-2",
|
|
192
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ y(h, { size: 20 }), s(F, "workspacesList.createFirstButton", "Create Your First Workspace")]
|
|
193
194
|
})
|
|
194
195
|
})
|
|
195
|
-
}) : /* @__PURE__ */
|
|
196
|
+
}) : /* @__PURE__ */ b(v, { children: [V === "list" ? /* @__PURE__ */ y("div", {
|
|
196
197
|
className: "space-y-3",
|
|
197
|
-
children: $?.items.map((e) => /* @__PURE__ */
|
|
198
|
-
}) : /* @__PURE__ */
|
|
198
|
+
children: $?.items.map((e) => /* @__PURE__ */ y(a, { workspace: e }, e.id))
|
|
199
|
+
}) : /* @__PURE__ */ y("div", {
|
|
199
200
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
200
|
-
children: $?.items.map((e) => /* @__PURE__ */
|
|
201
|
-
}), $ && $.total > 0 && /* @__PURE__ */
|
|
201
|
+
children: $?.items.map((e) => /* @__PURE__ */ y(a, { workspace: e }, e.id))
|
|
202
|
+
}), $ && $.total > 0 && /* @__PURE__ */ b("div", {
|
|
202
203
|
className: "flex items-center justify-between text-sm text-text-secondary",
|
|
203
|
-
children: [/* @__PURE__ */
|
|
204
|
-
|
|
204
|
+
children: [/* @__PURE__ */ b("p", { children: [
|
|
205
|
+
s(F, "workspacesList.showing", "Showing"),
|
|
205
206
|
" ",
|
|
206
207
|
$.items.length,
|
|
207
208
|
" ",
|
|
208
|
-
|
|
209
|
+
s(F, "workspacesList.of", "of"),
|
|
209
210
|
" ",
|
|
210
211
|
$.total,
|
|
211
212
|
" ",
|
|
212
|
-
$.total === 1 ?
|
|
213
|
-
] }), $.hasMore && /* @__PURE__ */
|
|
213
|
+
$.total === 1 ? s(F, "workspacesList.workspace", "workspace") : s(F, "workspacesList.workspaces", "workspaces")
|
|
214
|
+
] }), $.hasMore && /* @__PURE__ */ y("p", {
|
|
214
215
|
className: "text-xs",
|
|
215
|
-
children:
|
|
216
|
+
children: s(F, "workspacesList.moreAvailable", "More workspaces available - pagination coming soon")
|
|
216
217
|
})]
|
|
217
218
|
})] })
|
|
218
219
|
})
|
|
@@ -220,6 +221,6 @@ function P() {
|
|
|
220
221
|
});
|
|
221
222
|
}
|
|
222
223
|
//#endregion
|
|
223
|
-
export {
|
|
224
|
+
export { F as WorkspacesListPage };
|
|
224
225
|
|
|
225
226
|
//# sourceMappingURL=WorkspacesListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../src/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { Plus, Grid3X3, List as ListIcon, Search, Mail, UserPlus } from 'lucide-react';\nimport {\n Badge,\n Button,\n Input,\n Skeleton,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { MoreHorizontal } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { useMyWorkspaces } from '../hooks/useWorkspaces';\nimport { useMyPendingInvitations } from '../hooks/usePendingInvitations';\nimport { WorkspaceCard } from '../components/WorkspaceCard';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useState, useEffect } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspacesListPage() {\n useWorkspacesPageView('workspaces.list');\n const { t } = useI18n();\n\n const navigate = useNavigate();\n const { basePath = '/', currentUser, workspaceId: currentWorkspaceId } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { viewMode, setViewMode, workspaceFilters, setWorkspaceFilters } = useWorkspacesStore();\n\n // Navigate to unified workspace creation page\n const handleCreateWorkspace = () => {\n navigate(withCurrentSearch(`${basePath}/new`));\n };\n\n const [searchValue, setSearchValue] = useState(workspaceFilters.search || '');\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n if (debouncedSearch !== workspaceFilters.search) {\n setWorkspaceFilters({ search: debouncedSearch });\n }\n }, [debouncedSearch, workspaceFilters.search, setWorkspaceFilters]);\n\n const { data: rawData, isLoading, error } = useMyWorkspaces();\n const { data: pendingInvitations = [] } = useMyPendingInvitations(currentUser?.email);\n const pendingInvitesCount = pendingInvitations.length;\n\n const handleOpenPendingInvites = () => {\n navigate(withCurrentSearch(`${basePath}/invites`));\n };\n\n const handleInviteMember = () => {\n if (!currentWorkspaceId) {\n return;\n }\n\n navigate(withCurrentSearch(`${basePath}/${currentWorkspaceId}/invite`));\n };\n\n // Client-side search filtering (myWorkspaces doesn't accept filter args)\n const data = rawData\n ? {\n ...rawData,\n items: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n )\n : rawData.items,\n total: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n ).length\n : rawData.total,\n }\n : undefined;\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value);\n };\n\n if (error) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div className=\"flex flex-col items-center justify-center py-12\">\n <p className=\"text-status-error-text text-lg font-semibold\">\n {tWithFallback(t, 'workspacesList.loadError', 'Error loading workspaces')}\n </p>\n <p className=\"text-text-secondary text-sm mt-2\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'workspacesList.unknownError', 'Unknown error')}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header with title + actions */}\n <div\n className=\"relative overflow-hidden rounded-card flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 px-3 py-3 sm:px-4 sm:py-4\"\n data-tour=\"workspaces-list-header\"\n >\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n <GradientText>{tWithFallback(t, 'workspacesList.title', 'Workspaces')}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">\n {tWithFallback(t, 'workspacesList.description', 'Manage and organize your workspaces')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\" data-tour=\"workspaces-list-actions\">\n {/* View mode toggle */}\n <Button\n variant={viewMode === 'grid' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.gridViewAriaLabel',\n 'Show workspaces in grid view'\n )}\n title={tWithFallback(t, 'workspacesList.gridViewTitle', 'Grid view')}\n >\n <Grid3X3 size={20} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.listViewAriaLabel',\n 'Show workspaces in list view'\n )}\n title={tWithFallback(t, 'workspacesList.listViewTitle', 'List view')}\n >\n <ListIcon size={20} />\n </Button>\n {/* Secondary actions collapsed into an overflow \"More\" menu */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"icon\" aria-label=\"More actions\" className=\"relative\">\n <MoreHorizontal size={18} />\n {pendingInvitesCount > 0 ? (\n <span className=\"absolute -top-1 -right-1 flex size-2 rounded-full bg-action-primary-bg\" />\n ) : null}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.MEMBER_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.inviteDeniedTooltip',\n \"You don't have permission to invite members into the current workspace\"\n )}\n >\n <DropdownMenuItem\n onSelect={handleInviteMember}\n disabled={!currentWorkspaceId}\n className=\"gap-2\"\n >\n <UserPlus size={16} />\n {tWithFallback(t, 'workspacesList.inviteMemberButton', 'Invite Member')}\n </DropdownMenuItem>\n </PermissionButton>\n <DropdownMenuItem onSelect={handleOpenPendingInvites} className=\"gap-2\">\n <Mail size={16} />\n <span className=\"flex-1\">\n {tWithFallback(t, 'workspacesList.pendingInvitesButton', 'Pending Invites')}\n </span>\n {pendingInvitesCount > 0 ? (\n <Badge variant=\"secondary\">{pendingInvitesCount}</Badge>\n ) : null}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button\n onClick={handleCreateWorkspace}\n className=\"gap-2\"\n data-tour=\"workspaces-create-button\"\n >\n <Plus size={20} />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, 'workspacesList.createButton', 'Create Workspace')}\n </span>\n <span className=\"sm:hidden\">\n {tWithFallback(t, 'workspacesList.createButtonShort', 'Create')}\n </span>\n </Button>\n </PermissionButton>\n </div>\n </div>\n\n {/* Search */}\n <div className=\"relative\" data-tour=\"workspaces-search-input\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <Input\n placeholder={tWithFallback(t, 'workspacesList.searchPlaceholder', 'Search workspaces...')}\n value={searchValue}\n onChange={handleSearchChange}\n className=\"pl-[3.25rem]\"\n />\n </div>\n\n {/* Content */}\n <div className=\"space-y-4 sm:space-y-6\" data-tour=\"workspaces-view-container\">\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"space-y-3 p-6 border border-border-seam rounded-lg\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-12 rounded-lg\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n ) : data?.items.length === 0 ? (\n <IllustratedEmptyState\n illustration={workspaceFilters.search ? 'empty-search' : 'onboarding'}\n title={tWithFallback(t, 'workspacesList.emptyTitle', 'No workspaces found')}\n description={\n workspaceFilters.search\n ? tWithFallback(\n t,\n 'workspacesList.emptySearchHint',\n 'Try adjusting your search criteria'\n )\n : tWithFallback(\n t,\n 'workspacesList.emptyCreateHint',\n 'Get started by creating your first workspace'\n )\n }\n action={\n !workspaceFilters.search ? (\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button onClick={handleCreateWorkspace} className=\"gap-2\">\n <Plus size={20} />\n {tWithFallback(\n t,\n 'workspacesList.createFirstButton',\n 'Create Your First Workspace'\n )}\n </Button>\n </PermissionButton>\n ) : undefined\n }\n />\n ) : (\n <>\n {/* View */}\n {viewMode === 'list' ? (\n <div className=\"space-y-3\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n )}\n\n {/* Pagination info */}\n {data && data.total > 0 && (\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <p>\n {tWithFallback(t, 'workspacesList.showing', 'Showing')} {data.items.length}{' '}\n {tWithFallback(t, 'workspacesList.of', 'of')} {data.total}{' '}\n {data.total !== 1\n ? tWithFallback(t, 'workspacesList.workspaces', 'workspaces')\n : tWithFallback(t, 'workspacesList.workspace', 'workspace')}\n </p>\n {data.hasMore && (\n <p className=\"text-xs\">\n {tWithFallback(\n t,\n 'workspacesList.moreAvailable',\n 'More workspaces available - pagination coming soon'\n )}\n </p>\n )}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../src/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { Plus, Grid3X3, List as ListIcon, Search, Mail, UserPlus } from 'lucide-react';\nimport {\n Badge,\n Button,\n Input,\n Skeleton,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { MoreHorizontal } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { useMyWorkspaces } from '../hooks/useWorkspaces';\nimport { useMyPendingInvitations } from '../hooks/usePendingInvitations';\nimport { WorkspaceCard } from '../components/WorkspaceCard';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useState, useEffect } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspacesListPage() {\n useWorkspacesPageView('workspaces.list');\n const { t } = useI18n();\n\n const navigate = useNavigate();\n const { basePath = '/', currentUser, workspaceId: currentWorkspaceId } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { viewMode, setViewMode, workspaceFilters, setWorkspaceFilters } = useWorkspacesStore();\n\n // Navigate to unified workspace creation page\n const handleCreateWorkspace = () => {\n navigate(withCurrentSearch(`${basePath}/new`));\n };\n\n const [searchValue, setSearchValue] = useState(workspaceFilters.search || '');\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n if (debouncedSearch !== workspaceFilters.search) {\n setWorkspaceFilters({ search: debouncedSearch });\n }\n }, [debouncedSearch, workspaceFilters.search, setWorkspaceFilters]);\n\n const { data: rawData, isLoading, error } = useMyWorkspaces();\n const { data: pendingInvitations = [] } = useMyPendingInvitations(currentUser?.email);\n const pendingInvitesCount = pendingInvitations.length;\n\n const handleOpenPendingInvites = () => {\n navigate(withCurrentSearch(`${basePath}/invites`));\n };\n\n const handleInviteMember = () => {\n if (!currentWorkspaceId) {\n return;\n }\n\n navigate(withCurrentSearch(`${basePath}/${currentWorkspaceId}/invite`));\n };\n\n // Client-side search filtering (myWorkspaces doesn't accept filter args)\n const data = rawData\n ? {\n ...rawData,\n items: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n )\n : rawData.items,\n total: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n ).length\n : rawData.total,\n }\n : undefined;\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value);\n };\n\n if (error) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div className=\"flex flex-col items-center justify-center py-12\">\n <p className=\"text-status-error-text text-lg font-semibold\">\n {tWithFallback(t, 'workspacesList.loadError', 'Error loading workspaces')}\n </p>\n <p className=\"text-text-secondary text-sm mt-2\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'workspacesList.unknownError', 'Unknown error')}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header with title + actions */}\n <div\n className=\"relative overflow-hidden rounded-card flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 px-3 py-3 sm:px-4 sm:py-4\"\n data-tour=\"workspaces-list-header\"\n >\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n <GradientText>{tWithFallback(t, 'workspacesList.title', 'Workspaces')}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">\n {tWithFallback(t, 'workspacesList.description', 'Manage and organize your workspaces')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\" data-tour=\"workspaces-list-actions\">\n {/* View mode toggle */}\n <Button\n variant={viewMode === 'grid' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.gridViewAriaLabel',\n 'Show workspaces in grid view'\n )}\n title={tWithFallback(t, 'workspacesList.gridViewTitle', 'Grid view')}\n >\n <Grid3X3 size={20} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.listViewAriaLabel',\n 'Show workspaces in list view'\n )}\n title={tWithFallback(t, 'workspacesList.listViewTitle', 'List view')}\n >\n <ListIcon size={20} />\n </Button>\n {/* Secondary actions collapsed into an overflow \"More\" menu */}\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"icon\" aria-label=\"More actions\" className=\"relative\">\n <MoreHorizontal size={18} />\n {pendingInvitesCount > 0 ? (\n <span className=\"absolute -top-1 -right-1 flex size-2 rounded-full bg-action-primary-bg\" />\n ) : null}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.MEMBER_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.inviteDeniedTooltip',\n \"You don't have permission to invite members into the current workspace\"\n )}\n >\n <DropdownMenuItem\n onSelect={handleInviteMember}\n disabled={!currentWorkspaceId}\n className=\"gap-2\"\n >\n <UserPlus size={16} />\n {tWithFallback(t, 'workspacesList.inviteMemberButton', 'Invite Member')}\n </DropdownMenuItem>\n </PermissionButton>\n <DropdownMenuItem onSelect={handleOpenPendingInvites} className=\"gap-2\">\n <Mail size={16} />\n <span className=\"flex-1\">\n {tWithFallback(t, 'workspacesList.pendingInvitesButton', 'Pending Invites')}\n </span>\n {pendingInvitesCount > 0 ? (\n <Badge variant=\"secondary\">{pendingInvitesCount}</Badge>\n ) : null}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button\n onClick={handleCreateWorkspace}\n className=\"gap-2\"\n data-tour=\"workspaces-create-button\"\n >\n <Plus size={20} />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, 'workspacesList.createButton', 'Create Workspace')}\n </span>\n <span className=\"sm:hidden\">\n {tWithFallback(t, 'workspacesList.createButtonShort', 'Create')}\n </span>\n </Button>\n </PermissionButton>\n </div>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'workspacesList.purpose',\n 'Workspaces are shared homes for a team or initiative — each one groups its own projects, members, agents and activity. Create one per team, client or product line to keep work isolated, then switch between them from the sidebar.'\n )}\n </PagePurpose>\n\n {/* Search */}\n <div className=\"relative\" data-tour=\"workspaces-search-input\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <Input\n placeholder={tWithFallback(t, 'workspacesList.searchPlaceholder', 'Search workspaces...')}\n value={searchValue}\n onChange={handleSearchChange}\n className=\"pl-[3.25rem]\"\n />\n </div>\n\n {/* Content */}\n <div className=\"space-y-4 sm:space-y-6\" data-tour=\"workspaces-view-container\">\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"space-y-3 p-6 border border-border-seam rounded-lg\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-12 rounded-lg\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n ) : data?.items.length === 0 ? (\n <IllustratedEmptyState\n illustration={workspaceFilters.search ? 'empty-search' : 'onboarding'}\n title={tWithFallback(t, 'workspacesList.emptyTitle', 'No workspaces found')}\n description={\n workspaceFilters.search\n ? tWithFallback(\n t,\n 'workspacesList.emptySearchHint',\n 'Try adjusting your search criteria'\n )\n : tWithFallback(\n t,\n 'workspacesList.emptyCreateHint',\n 'Get started by creating your first workspace'\n )\n }\n action={\n !workspaceFilters.search ? (\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button onClick={handleCreateWorkspace} className=\"gap-2\">\n <Plus size={20} />\n {tWithFallback(\n t,\n 'workspacesList.createFirstButton',\n 'Create Your First Workspace'\n )}\n </Button>\n </PermissionButton>\n ) : undefined\n }\n />\n ) : (\n <>\n {/* View */}\n {viewMode === 'list' ? (\n <div className=\"space-y-3\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n )}\n\n {/* Pagination info */}\n {data && data.total > 0 && (\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <p>\n {tWithFallback(t, 'workspacesList.showing', 'Showing')} {data.items.length}{' '}\n {tWithFallback(t, 'workspacesList.of', 'of')} {data.total}{' '}\n {data.total !== 1\n ? tWithFallback(t, 'workspacesList.workspaces', 'workspaces')\n : tWithFallback(t, 'workspacesList.workspace', 'workspace')}\n </p>\n {data.hasMore && (\n <p className=\"text-xs\">\n {tWithFallback(\n t,\n 'workspacesList.moreAvailable',\n 'More workspaces available - pagination coming soon'\n )}\n </p>\n )}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|