@burdenoff/microfe-workspaces 2026.625.3 → 2026.625.4
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/pages/ActivityListPage.js +32 -48
- package/dist/pages/ActivityListPage.js.map +1 -1
- package/dist/pages/MembersListPage.js +196 -241
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +69 -78
- package/dist/pages/PendingInvitesPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +37 -52
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +73 -86
- package/dist/pages/ProjectMembersPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +103 -118
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +74 -76
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +167 -178
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/widgets/AgentsWidget.js +21 -22
- package/dist/pages/dashboard/widgets/AgentsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/ProjectsWidget.js +26 -27
- package/dist/pages/dashboard/widgets/ProjectsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js +19 -23
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/SessionsWidget.js +30 -32
- package/dist/pages/dashboard/widgets/SessionsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js +18 -20
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/VibesWidget.js +18 -19
- package/dist/pages/dashboard/widgets/VibesWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WelcomeWidget.js +14 -12
- package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js +20 -21
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,229 +1,218 @@
|
|
|
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 { Badge as
|
|
14
|
-
import { useNavigate as
|
|
15
|
-
import { useDebounce as
|
|
16
|
-
import { PermissionButton as
|
|
17
|
-
import { useI18n as
|
|
3
|
+
import { useMyWorkspaces as ee } from "../hooks/useWorkspaces.js";
|
|
4
|
+
import { useMyPendingInvitations as n } from "../hooks/usePendingInvitations.js";
|
|
5
|
+
import { useScopedNavigation as r } from "../hooks/useScopedNavigation.js";
|
|
6
|
+
import { WorkspaceCard as i } from "../components/WorkspaceCard.js";
|
|
7
|
+
import { WORKSPACE_PERMISSIONS as a } from "../constants/permissions.js";
|
|
8
|
+
import { tWithFallback as o } from "../utils/i18n.js";
|
|
9
|
+
import { useWorkspacesPageView as s } from "../hooks/useWorkspacesPageView.js";
|
|
10
|
+
import { useEffect as c, useState as l } from "react";
|
|
11
|
+
import { Grid3X3 as u, List as d, Mail as f, MoreHorizontal as p, Plus as m, Search as h, UserPlus as g } from "lucide-react";
|
|
12
|
+
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
13
|
+
import { AuroraBackground as b, Badge as x, Button as S, DropdownMenu as C, DropdownMenuContent as w, DropdownMenuItem as T, DropdownMenuTrigger as E, GradientText as D, IllustratedEmptyState as te, Input as O, Skeleton as k } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { useNavigate as A } from "react-router-dom";
|
|
15
|
+
import { useDebounce as j } from "@burdenoff/fe-libs/shared/hooks";
|
|
16
|
+
import { PermissionButton as M } from "@burdenoff/fe-libs/shared/components";
|
|
17
|
+
import { useI18n as N } 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 P() {
|
|
20
|
+
s("workspaces.list");
|
|
21
|
+
let { t: P } = N(), F = A(), { basePath: I = "/", currentUser: L, workspaceId: R } = e(), { withCurrentSearch: z } = r(), { viewMode: B, setViewMode: V, workspaceFilters: H, setWorkspaceFilters: U } = t(), W = () => {
|
|
22
|
+
F(z(`${I}/new`));
|
|
23
|
+
}, [G, K] = l(H.search || ""), q = j(G, 500);
|
|
24
|
+
c(() => {
|
|
25
|
+
q !== H.search && U({ search: q });
|
|
26
26
|
}, [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
q,
|
|
28
|
+
H.search,
|
|
29
|
+
U
|
|
30
30
|
]);
|
|
31
|
-
let { data:
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
}, $ =
|
|
36
|
-
...
|
|
37
|
-
items:
|
|
38
|
-
total:
|
|
31
|
+
let { data: J, isLoading: Y, error: X } = ee(), { data: Z = [] } = n(L?.email), Q = Z.length, ne = () => {
|
|
32
|
+
F(z(`${I}/invites`));
|
|
33
|
+
}, re = () => {
|
|
34
|
+
R && F(z(`${I}/${R}/invite`));
|
|
35
|
+
}, $ = J ? {
|
|
36
|
+
...J,
|
|
37
|
+
items: q ? J.items.filter((e) => e.name.toLowerCase().includes(q.toLowerCase())) : J.items,
|
|
38
|
+
total: q ? J.items.filter((e) => e.name.toLowerCase().includes(q.toLowerCase())).length : J.total
|
|
39
39
|
} : void 0;
|
|
40
|
-
return
|
|
40
|
+
return X ? /* @__PURE__ */ v("div", {
|
|
41
41
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
42
|
-
children: /* @__PURE__ */
|
|
42
|
+
children: /* @__PURE__ */ y("div", {
|
|
43
43
|
className: "flex flex-col items-center justify-center py-12",
|
|
44
|
-
children: [/* @__PURE__ */
|
|
44
|
+
children: [/* @__PURE__ */ v("p", {
|
|
45
45
|
className: "text-status-error-text text-lg font-semibold",
|
|
46
|
-
children:
|
|
47
|
-
}), /* @__PURE__ */
|
|
46
|
+
children: o(P, "workspacesList.loadError", "Error loading workspaces")
|
|
47
|
+
}), /* @__PURE__ */ v("p", {
|
|
48
48
|
className: "text-text-secondary text-sm mt-2",
|
|
49
|
-
children:
|
|
49
|
+
children: X instanceof Error ? X.message : o(P, "workspacesList.unknownError", "Unknown error")
|
|
50
50
|
})]
|
|
51
51
|
})
|
|
52
|
-
}) : /* @__PURE__ */
|
|
52
|
+
}) : /* @__PURE__ */ y("div", {
|
|
53
53
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
54
54
|
children: [
|
|
55
|
-
/* @__PURE__ */
|
|
56
|
-
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
|
|
55
|
+
/* @__PURE__ */ y("div", {
|
|
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
|
-
children: [
|
|
59
|
-
|
|
60
|
-
children:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"aria-label": s(M, "workspacesList.gridViewAriaLabel", "Show workspaces in grid view"),
|
|
74
|
-
title: s(M, "workspacesList.gridViewTitle", "Grid view"),
|
|
75
|
-
children: /* @__PURE__ */ y(d, { size: 20 })
|
|
76
|
-
}),
|
|
77
|
-
/* @__PURE__ */ y(x, {
|
|
78
|
-
variant: R === "list" ? "default" : "outline",
|
|
79
|
-
size: "icon",
|
|
80
|
-
onClick: () => z("list"),
|
|
81
|
-
className: "hidden sm:flex",
|
|
82
|
-
"aria-label": s(M, "workspacesList.listViewAriaLabel", "Show workspaces in list view"),
|
|
83
|
-
title: s(M, "workspacesList.listViewTitle", "List view"),
|
|
84
|
-
children: /* @__PURE__ */ y(f, { size: 20 })
|
|
85
|
-
}),
|
|
86
|
-
/* @__PURE__ */ b(S, { children: [/* @__PURE__ */ y(T, {
|
|
87
|
-
asChild: !0,
|
|
88
|
-
children: /* @__PURE__ */ b(x, {
|
|
89
|
-
variant: "outline",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ v(b, { intensity: "subtle" }),
|
|
60
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
|
|
61
|
+
className: "text-2xl sm:text-3xl font-bold",
|
|
62
|
+
children: /* @__PURE__ */ v(D, { children: o(P, "workspacesList.title", "Workspaces") })
|
|
63
|
+
}), /* @__PURE__ */ v("p", {
|
|
64
|
+
className: "text-sm sm:text-base text-text-secondary",
|
|
65
|
+
children: o(P, "workspacesList.description", "Manage and organize your workspaces")
|
|
66
|
+
})] }),
|
|
67
|
+
/* @__PURE__ */ y("div", {
|
|
68
|
+
className: "flex items-center gap-2",
|
|
69
|
+
"data-tour": "workspaces-list-actions",
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ v(S, {
|
|
72
|
+
variant: B === "grid" ? "default" : "outline",
|
|
90
73
|
size: "icon",
|
|
91
|
-
|
|
92
|
-
className: "
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
74
|
+
onClick: () => V("grid"),
|
|
75
|
+
className: "hidden sm:flex",
|
|
76
|
+
"aria-label": o(P, "workspacesList.gridViewAriaLabel", "Show workspaces in grid view"),
|
|
77
|
+
title: o(P, "workspacesList.gridViewTitle", "Grid view"),
|
|
78
|
+
children: /* @__PURE__ */ v(u, { size: 20 })
|
|
79
|
+
}),
|
|
80
|
+
/* @__PURE__ */ v(S, {
|
|
81
|
+
variant: B === "list" ? "default" : "outline",
|
|
82
|
+
size: "icon",
|
|
83
|
+
onClick: () => V("list"),
|
|
84
|
+
className: "hidden sm:flex",
|
|
85
|
+
"aria-label": o(P, "workspacesList.listViewAriaLabel", "Show workspaces in list view"),
|
|
86
|
+
title: o(P, "workspacesList.listViewTitle", "List view"),
|
|
87
|
+
children: /* @__PURE__ */ v(d, { size: 20 })
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ y(C, { children: [/* @__PURE__ */ v(E, {
|
|
90
|
+
asChild: !0,
|
|
91
|
+
children: /* @__PURE__ */ y(S, {
|
|
92
|
+
variant: "outline",
|
|
93
|
+
size: "icon",
|
|
94
|
+
"aria-label": "More actions",
|
|
95
|
+
className: "relative",
|
|
96
|
+
children: [/* @__PURE__ */ v(p, { size: 18 }), Q > 0 ? /* @__PURE__ */ v("span", { className: "absolute -top-1 -right-1 flex size-2 rounded-full bg-action-primary-bg" }) : null]
|
|
97
|
+
})
|
|
98
|
+
}), /* @__PURE__ */ y(w, {
|
|
99
|
+
align: "end",
|
|
100
|
+
children: [/* @__PURE__ */ v(M, {
|
|
101
|
+
permission: a.MEMBER_CREATE,
|
|
102
|
+
deniedBehavior: "disable",
|
|
103
|
+
deniedTooltip: o(P, "workspacesList.inviteDeniedTooltip", "You don't have permission to invite members into the current workspace"),
|
|
104
|
+
children: /* @__PURE__ */ y(T, {
|
|
105
|
+
onSelect: re,
|
|
106
|
+
disabled: !R,
|
|
107
|
+
className: "gap-2",
|
|
108
|
+
children: [/* @__PURE__ */ v(g, { size: 16 }), o(P, "workspacesList.inviteMemberButton", "Invite Member")]
|
|
109
|
+
})
|
|
110
|
+
}), /* @__PURE__ */ y(T, {
|
|
111
|
+
onSelect: ne,
|
|
112
|
+
className: "gap-2",
|
|
113
|
+
children: [
|
|
114
|
+
/* @__PURE__ */ v(f, { size: 16 }),
|
|
115
|
+
/* @__PURE__ */ v("span", {
|
|
116
|
+
className: "flex-1",
|
|
117
|
+
children: o(P, "workspacesList.pendingInvitesButton", "Pending Invites")
|
|
118
|
+
}),
|
|
119
|
+
Q > 0 ? /* @__PURE__ */ v(x, {
|
|
120
|
+
variant: "secondary",
|
|
121
|
+
children: Q
|
|
122
|
+
}) : null
|
|
123
|
+
]
|
|
124
|
+
})]
|
|
125
|
+
})] }),
|
|
126
|
+
/* @__PURE__ */ v(M, {
|
|
127
|
+
permission: a.WORKSPACE_CREATE,
|
|
99
128
|
deniedBehavior: "disable",
|
|
100
|
-
deniedTooltip:
|
|
101
|
-
children: /* @__PURE__ */
|
|
102
|
-
|
|
103
|
-
disabled: !I,
|
|
129
|
+
deniedTooltip: o(P, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
130
|
+
children: /* @__PURE__ */ y(S, {
|
|
131
|
+
onClick: W,
|
|
104
132
|
className: "gap-2",
|
|
105
|
-
|
|
133
|
+
"data-tour": "workspaces-create-button",
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ v(m, { size: 20 }),
|
|
136
|
+
/* @__PURE__ */ v("span", {
|
|
137
|
+
className: "hidden sm:inline",
|
|
138
|
+
children: o(P, "workspacesList.createButton", "Create Workspace")
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ v("span", {
|
|
141
|
+
className: "sm:hidden",
|
|
142
|
+
children: o(P, "workspacesList.createButtonShort", "Create")
|
|
143
|
+
})
|
|
144
|
+
]
|
|
106
145
|
})
|
|
107
|
-
}), /* @__PURE__ */ b(w, {
|
|
108
|
-
onSelect: Z,
|
|
109
|
-
className: "gap-2",
|
|
110
|
-
children: [
|
|
111
|
-
/* @__PURE__ */ y(p, { size: 16 }),
|
|
112
|
-
/* @__PURE__ */ y("span", {
|
|
113
|
-
className: "flex-1",
|
|
114
|
-
children: s(M, "workspacesList.pendingInvitesButton", "Pending Invites")
|
|
115
|
-
}),
|
|
116
|
-
X > 0 ? /* @__PURE__ */ y(ee, {
|
|
117
|
-
variant: "secondary",
|
|
118
|
-
children: X
|
|
119
|
-
}) : null
|
|
120
|
-
]
|
|
121
|
-
})]
|
|
122
|
-
})] }),
|
|
123
|
-
/* @__PURE__ */ y(A, {
|
|
124
|
-
permission: o.WORKSPACE_CREATE,
|
|
125
|
-
deniedBehavior: "disable",
|
|
126
|
-
deniedTooltip: s(M, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
127
|
-
children: /* @__PURE__ */ b(x, {
|
|
128
|
-
onClick: H,
|
|
129
|
-
className: "gap-2",
|
|
130
|
-
"data-tour": "workspaces-create-button",
|
|
131
|
-
children: [
|
|
132
|
-
/* @__PURE__ */ y(h, { size: 20 }),
|
|
133
|
-
/* @__PURE__ */ y("span", {
|
|
134
|
-
className: "hidden sm:inline",
|
|
135
|
-
children: s(M, "workspacesList.createButton", "Create Workspace")
|
|
136
|
-
}),
|
|
137
|
-
/* @__PURE__ */ y("span", {
|
|
138
|
-
className: "sm:hidden",
|
|
139
|
-
children: s(M, "workspacesList.createButtonShort", "Create")
|
|
140
|
-
})
|
|
141
|
-
]
|
|
142
146
|
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
]
|
|
148
|
+
})
|
|
149
|
+
]
|
|
146
150
|
}),
|
|
147
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ y("div", {
|
|
148
152
|
className: "relative",
|
|
149
153
|
"data-tour": "workspaces-search-input",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ v(h, {
|
|
151
155
|
className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary",
|
|
152
156
|
size: 20
|
|
153
|
-
}), /* @__PURE__ */
|
|
154
|
-
placeholder:
|
|
155
|
-
value:
|
|
157
|
+
}), /* @__PURE__ */ v(O, {
|
|
158
|
+
placeholder: o(P, "workspacesList.searchPlaceholder", "Search workspaces..."),
|
|
159
|
+
value: G,
|
|
156
160
|
onChange: (e) => {
|
|
157
|
-
|
|
161
|
+
K(e.target.value);
|
|
158
162
|
},
|
|
159
163
|
className: "pl-[3.25rem]"
|
|
160
164
|
})]
|
|
161
165
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
166
|
+
/* @__PURE__ */ v("div", {
|
|
163
167
|
className: "space-y-4 sm:space-y-6",
|
|
164
168
|
"data-tour": "workspaces-view-container",
|
|
165
|
-
children:
|
|
169
|
+
children: Y ? /* @__PURE__ */ v("div", {
|
|
166
170
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
167
|
-
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */
|
|
171
|
+
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ y("div", {
|
|
168
172
|
className: "space-y-3 p-6 border border-border-seam rounded-lg",
|
|
169
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ y("div", {
|
|
170
174
|
className: "flex items-center gap-3",
|
|
171
|
-
children: [/* @__PURE__ */
|
|
175
|
+
children: [/* @__PURE__ */ v(k, { className: "size-12 rounded-lg" }), /* @__PURE__ */ y("div", {
|
|
172
176
|
className: "space-y-2 flex-1",
|
|
173
|
-
children: [/* @__PURE__ */
|
|
177
|
+
children: [/* @__PURE__ */ v(k, { className: "h-4 w-3/4" }), /* @__PURE__ */ v(k, { className: "h-3 w-1/2" })]
|
|
174
178
|
})]
|
|
175
|
-
}), /* @__PURE__ */
|
|
179
|
+
}), /* @__PURE__ */ v(k, { className: "h-3 w-1/3" })]
|
|
176
180
|
}, t))
|
|
177
|
-
}) : $?.items.length === 0 ? /* @__PURE__ */
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
children: s(M, "workspacesList.emptyTitle", "No workspaces found")
|
|
190
|
-
}),
|
|
191
|
-
/* @__PURE__ */ y("p", {
|
|
192
|
-
className: "text-text-secondary mb-4 max-w-sm",
|
|
193
|
-
children: B.search ? s(M, "workspacesList.emptySearchHint", "Try adjusting your search criteria") : s(M, "workspacesList.emptyCreateHint", "Get started by creating your first workspace")
|
|
194
|
-
}),
|
|
195
|
-
!B.search && /* @__PURE__ */ y(A, {
|
|
196
|
-
permission: o.WORKSPACE_CREATE,
|
|
197
|
-
deniedBehavior: "disable",
|
|
198
|
-
deniedTooltip: s(M, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
199
|
-
children: /* @__PURE__ */ b(x, {
|
|
200
|
-
onClick: H,
|
|
201
|
-
className: "gap-2",
|
|
202
|
-
children: [/* @__PURE__ */ y(h, { size: 20 }), s(M, "workspacesList.createFirstButton", "Create Your First Workspace")]
|
|
203
|
-
})
|
|
181
|
+
}) : $?.items.length === 0 ? /* @__PURE__ */ v(te, {
|
|
182
|
+
illustration: H.search ? "empty-search" : "onboarding",
|
|
183
|
+
title: o(P, "workspacesList.emptyTitle", "No workspaces found"),
|
|
184
|
+
description: H.search ? o(P, "workspacesList.emptySearchHint", "Try adjusting your search criteria") : o(P, "workspacesList.emptyCreateHint", "Get started by creating your first workspace"),
|
|
185
|
+
action: H.search ? void 0 : /* @__PURE__ */ v(M, {
|
|
186
|
+
permission: a.WORKSPACE_CREATE,
|
|
187
|
+
deniedBehavior: "disable",
|
|
188
|
+
deniedTooltip: o(P, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
189
|
+
children: /* @__PURE__ */ y(S, {
|
|
190
|
+
onClick: W,
|
|
191
|
+
className: "gap-2",
|
|
192
|
+
children: [/* @__PURE__ */ v(m, { size: 20 }), o(P, "workspacesList.createFirstButton", "Create Your First Workspace")]
|
|
204
193
|
})
|
|
205
|
-
|
|
206
|
-
}) : /* @__PURE__ */
|
|
194
|
+
})
|
|
195
|
+
}) : /* @__PURE__ */ y(_, { children: [B === "list" ? /* @__PURE__ */ v("div", {
|
|
207
196
|
className: "space-y-3",
|
|
208
|
-
children: $?.items.map((e) => /* @__PURE__ */
|
|
209
|
-
}) : /* @__PURE__ */
|
|
197
|
+
children: $?.items.map((e) => /* @__PURE__ */ v(i, { workspace: e }, e.id))
|
|
198
|
+
}) : /* @__PURE__ */ v("div", {
|
|
210
199
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
211
|
-
children: $?.items.map((e) => /* @__PURE__ */
|
|
212
|
-
}), $ && $.total > 0 && /* @__PURE__ */
|
|
200
|
+
children: $?.items.map((e) => /* @__PURE__ */ v(i, { workspace: e }, e.id))
|
|
201
|
+
}), $ && $.total > 0 && /* @__PURE__ */ y("div", {
|
|
213
202
|
className: "flex items-center justify-between text-sm text-text-secondary",
|
|
214
|
-
children: [/* @__PURE__ */
|
|
215
|
-
|
|
203
|
+
children: [/* @__PURE__ */ y("p", { children: [
|
|
204
|
+
o(P, "workspacesList.showing", "Showing"),
|
|
216
205
|
" ",
|
|
217
206
|
$.items.length,
|
|
218
207
|
" ",
|
|
219
|
-
|
|
208
|
+
o(P, "workspacesList.of", "of"),
|
|
220
209
|
" ",
|
|
221
210
|
$.total,
|
|
222
211
|
" ",
|
|
223
|
-
$.total === 1 ?
|
|
224
|
-
] }), $.hasMore && /* @__PURE__ */
|
|
212
|
+
$.total === 1 ? o(P, "workspacesList.workspace", "workspace") : o(P, "workspacesList.workspaces", "workspaces")
|
|
213
|
+
] }), $.hasMore && /* @__PURE__ */ v("p", {
|
|
225
214
|
className: "text-xs",
|
|
226
|
-
children:
|
|
215
|
+
children: o(P, "workspacesList.moreAvailable", "More workspaces available - pagination coming soon")
|
|
227
216
|
})]
|
|
228
217
|
})] })
|
|
229
218
|
})
|
|
@@ -231,6 +220,6 @@ function M() {
|
|
|
231
220
|
});
|
|
232
221
|
}
|
|
233
222
|
//#endregion
|
|
234
|
-
export {
|
|
223
|
+
export { P as WorkspacesListPage };
|
|
235
224
|
|
|
236
225
|
//# 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} 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=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\"\n data-tour=\"workspaces-list-header\"\n >\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'workspacesList.title', 'Workspaces')}\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 <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-bg-sunken p-6 mb-4\">\n <Grid3X3 size={48} className=\"text-text-secondary\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tWithFallback(t, 'workspacesList.emptyTitle', 'No workspaces found')}\n </h3>\n <p className=\"text-text-secondary mb-4 max-w-sm\">\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 </p>\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 )}\n </div>\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} 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,40 +1,39 @@
|
|
|
1
1
|
import { WidgetWrapper as e } from "../WidgetWrapper.js";
|
|
2
2
|
import { AlertTriangle as t, ArrowRight as n, Bot as r, Wifi as i, WifiOff as a } from "lucide-react";
|
|
3
3
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
4
|
-
import { Button as c } from "@burdenoff/fe-libs/ui";
|
|
4
|
+
import { Button as c, IllustratedEmptyState as l } from "@burdenoff/fe-libs/ui";
|
|
5
5
|
//#region src/pages/dashboard/widgets/AgentsWidget.tsx
|
|
6
|
-
function
|
|
7
|
-
let
|
|
6
|
+
function u({ workspaceData: u, isLoading: d, navigate: f }) {
|
|
7
|
+
let p = u?.agentFleet ?? null, m = p?.total ?? 0;
|
|
8
8
|
return /* @__PURE__ */ o(e, {
|
|
9
9
|
title: "Agent Fleet",
|
|
10
10
|
icon: /* @__PURE__ */ o(r, { className: "size-4" }),
|
|
11
11
|
size: "small",
|
|
12
|
-
isLoading:
|
|
13
|
-
unavailable: !
|
|
12
|
+
isLoading: d,
|
|
13
|
+
unavailable: !u,
|
|
14
14
|
headerAction: /* @__PURE__ */ s(c, {
|
|
15
15
|
variant: "ghost",
|
|
16
16
|
size: "sm",
|
|
17
17
|
className: "text-xs",
|
|
18
|
-
onClick: () =>
|
|
18
|
+
onClick: () => f("/vibecontrols/agents"),
|
|
19
19
|
children: ["Open ", /* @__PURE__ */ o(n, { className: "ml-1 size-3" })]
|
|
20
20
|
}),
|
|
21
|
-
children: !
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}), /* @__PURE__ */ o(c, {
|
|
21
|
+
children: !p || m === 0 ? /* @__PURE__ */ o(l, {
|
|
22
|
+
illustration: "empty-agents",
|
|
23
|
+
title: "No agents connected",
|
|
24
|
+
className: "py-4",
|
|
25
|
+
action: /* @__PURE__ */ o(c, {
|
|
27
26
|
variant: "outline",
|
|
28
27
|
size: "sm",
|
|
29
|
-
onClick: () =>
|
|
28
|
+
onClick: () => f("/vibecontrols/agents/new"),
|
|
30
29
|
children: "Connect agent"
|
|
31
|
-
})
|
|
30
|
+
})
|
|
32
31
|
}) : /* @__PURE__ */ s("div", {
|
|
33
32
|
className: "space-y-3",
|
|
34
33
|
children: [
|
|
35
34
|
/* @__PURE__ */ s("p", {
|
|
36
35
|
className: "text-2xl font-semibold text-text-primary",
|
|
37
|
-
children: [
|
|
36
|
+
children: [m, /* @__PURE__ */ o("span", {
|
|
38
37
|
className: "ml-1 text-xs font-normal text-text-secondary",
|
|
39
38
|
children: "total"
|
|
40
39
|
})]
|
|
@@ -45,10 +44,10 @@ function l({ workspaceData: l, isLoading: u, navigate: d }) {
|
|
|
45
44
|
/* @__PURE__ */ s("div", {
|
|
46
45
|
className: "rounded-md bg-status-success-bg/30 p-2",
|
|
47
46
|
children: [
|
|
48
|
-
/* @__PURE__ */ o(i, { className:
|
|
47
|
+
/* @__PURE__ */ o(i, { className: `mx-auto size-4 text-status-success-text ${p.online > 0 ? "motion-safe:animate-vc-glow-pulse" : ""}` }),
|
|
49
48
|
/* @__PURE__ */ o("p", {
|
|
50
49
|
className: "mt-1 text-sm font-semibold text-text-primary",
|
|
51
|
-
children:
|
|
50
|
+
children: p.online
|
|
52
51
|
}),
|
|
53
52
|
/* @__PURE__ */ o("p", {
|
|
54
53
|
className: "text-[10px] text-text-secondary",
|
|
@@ -62,7 +61,7 @@ function l({ workspaceData: l, isLoading: u, navigate: d }) {
|
|
|
62
61
|
/* @__PURE__ */ o(t, { className: "mx-auto size-4 text-status-warning-text" }),
|
|
63
62
|
/* @__PURE__ */ o("p", {
|
|
64
63
|
className: "mt-1 text-sm font-semibold text-text-primary",
|
|
65
|
-
children:
|
|
64
|
+
children: p.degraded
|
|
66
65
|
}),
|
|
67
66
|
/* @__PURE__ */ o("p", {
|
|
68
67
|
className: "text-[10px] text-text-secondary",
|
|
@@ -76,7 +75,7 @@ function l({ workspaceData: l, isLoading: u, navigate: d }) {
|
|
|
76
75
|
/* @__PURE__ */ o(a, { className: "mx-auto size-4 text-text-tertiary" }),
|
|
77
76
|
/* @__PURE__ */ o("p", {
|
|
78
77
|
className: "mt-1 text-sm font-semibold text-text-primary",
|
|
79
|
-
children:
|
|
78
|
+
children: p.offline
|
|
80
79
|
}),
|
|
81
80
|
/* @__PURE__ */ o("p", {
|
|
82
81
|
className: "text-[10px] text-text-secondary",
|
|
@@ -86,12 +85,12 @@ function l({ workspaceData: l, isLoading: u, navigate: d }) {
|
|
|
86
85
|
})
|
|
87
86
|
]
|
|
88
87
|
}),
|
|
89
|
-
|
|
88
|
+
p.lastSeenAt ? /* @__PURE__ */ s("p", {
|
|
90
89
|
className: "text-[11px] text-text-secondary text-center",
|
|
91
90
|
children: [
|
|
92
91
|
"Last seen",
|
|
93
92
|
" ",
|
|
94
|
-
new Date(
|
|
93
|
+
new Date(p.lastSeenAt).toLocaleString(void 0, {
|
|
95
94
|
hour: "2-digit",
|
|
96
95
|
minute: "2-digit",
|
|
97
96
|
month: "short",
|
|
@@ -104,6 +103,6 @@ function l({ workspaceData: l, isLoading: u, navigate: d }) {
|
|
|
104
103
|
});
|
|
105
104
|
}
|
|
106
105
|
//#endregion
|
|
107
|
-
export {
|
|
106
|
+
export { u as AgentsWidget };
|
|
108
107
|
|
|
109
108
|
//# sourceMappingURL=AgentsWidget.js.map
|