@burdenoff/microfe-workspaces 2026.531.2 → 2026.531.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/WorkspacesRoutes.js +36 -17
- package/dist/WorkspacesRoutes.js.map +1 -1
- package/dist/components/InviteMemberDialog.js +204 -117
- package/dist/components/InviteMemberDialog.js.map +1 -1
- package/dist/components/MemberListItem.js +2 -1
- package/dist/components/MemberListItem.js.map +1 -1
- package/dist/components/ProjectMemberPickerDialog.js +211 -0
- package/dist/components/ProjectMemberPickerDialog.js.map +1 -0
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useMemberMutations.js +13 -13
- package/dist/hooks/useMemberMutations.js.map +1 -1
- package/dist/hooks/useProjectMemberMutations.js +104 -0
- package/dist/hooks/useProjectMemberMutations.js.map +1 -0
- package/dist/hooks/useProjectMembers.js +42 -0
- package/dist/hooks/useProjectMembers.js.map +1 -0
- package/dist/hooks/useWorkspaceMembers.js +60 -24
- package/dist/hooks/useWorkspaceMembers.js.map +1 -1
- package/dist/hooks/useWorkspacePermissions.js +4 -0
- package/dist/hooks/useWorkspacePermissions.js.map +1 -1
- package/dist/hooks/useWorkspacesEventEmitter.js.map +1 -1
- package/dist/index.js +16 -15
- package/dist/pages/ActivityListPage.js +5 -5
- package/dist/pages/InviteAcceptancePage.js +211 -207
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +210 -208
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +124 -120
- package/dist/pages/PendingInvitesPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +249 -213
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +265 -0
- package/dist/pages/ProjectMembersPage.js.map +1 -0
- package/dist/pages/ProjectsListPage.js +9 -9
- package/dist/pages/WorkspaceDetailPage.js +119 -111
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceInvitePage.js +790 -0
- package/dist/pages/WorkspaceInvitePage.js.map +1 -0
- package/dist/pages/WorkspacesListPage.js +115 -100
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/utils/invitationDisplay.js +25 -0
- package/dist/utils/invitationDisplay.js.map +1 -0
- package/dist/utils/workspaceBulkInviteCsv.js +42 -0
- package/dist/utils/workspaceBulkInviteCsv.js.map +1 -0
- package/package.json +1 -1
|
@@ -4,223 +4,231 @@ import { useScopedNavigation as n } from "../hooks/useScopedNavigation.js";
|
|
|
4
4
|
import { tWithFallback as r } from "../utils/i18n.js";
|
|
5
5
|
import { useWorkspacesPageView as i } from "../hooks/useWorkspacesPageView.js";
|
|
6
6
|
import { useWorkspaceMembers as a } from "../hooks/useWorkspaceMembers.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { Activity as l, ArrowLeft as u, ChevronRight as d, FolderKanban as f, Settings as p,
|
|
11
|
-
import { Fragment as
|
|
12
|
-
import { Badge as
|
|
13
|
-
import { useNavigate as
|
|
14
|
-
import { useI18n as
|
|
7
|
+
import { useWorkspacePermissions as o } from "../hooks/useWorkspacePermissions.js";
|
|
8
|
+
import { useProjects as s } from "../hooks/useProjects.js";
|
|
9
|
+
import { useWorkspaceActivity as c } from "../hooks/useWorkspaceActivity.js";
|
|
10
|
+
import { Activity as l, ArrowLeft as u, ChevronRight as d, FolderKanban as f, Settings as p, UserPlus as m, Users as h } from "lucide-react";
|
|
11
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as y, Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, Skeleton as T } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { useNavigate as E, useParams as D } from "react-router-dom";
|
|
14
|
+
import { useI18n as O } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
15
15
|
//#region src/pages/WorkspaceDetailPage.tsx
|
|
16
|
-
function
|
|
17
|
-
let { workspaceId:
|
|
16
|
+
function k() {
|
|
17
|
+
let { workspaceId: k } = D();
|
|
18
18
|
i("workspaces.detail", {
|
|
19
|
-
workspaceId:
|
|
19
|
+
workspaceId: k,
|
|
20
20
|
requireParams: !0
|
|
21
21
|
});
|
|
22
|
-
let { t:
|
|
23
|
-
if (
|
|
22
|
+
let { t: A } = O(), j = E(), { basePath: M = "/" } = e(), { withCurrentSearch: N } = n(), { data: P, isLoading: F, error: I } = t(k || ""), { data: L } = s({ workspaceId: k }, { limit: 1 }, k), { data: R } = a(k || "", { limit: 1 }), { data: z } = c(k), { canViewWorkspace: B, canUpdateWorkspace: V, canInviteMember: H, isLoading: U } = o();
|
|
23
|
+
if (U) return /* @__PURE__ */ v("div", {
|
|
24
24
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
25
|
-
children: [/* @__PURE__ */
|
|
25
|
+
children: [/* @__PURE__ */ _(T, { className: "h-10 w-1/3" }), /* @__PURE__ */ v("div", {
|
|
26
26
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
27
27
|
children: [
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
-
/* @__PURE__ */
|
|
30
|
-
/* @__PURE__ */
|
|
28
|
+
/* @__PURE__ */ _(T, { className: "h-32" }),
|
|
29
|
+
/* @__PURE__ */ _(T, { className: "h-32" }),
|
|
30
|
+
/* @__PURE__ */ _(T, { className: "h-32" })
|
|
31
31
|
]
|
|
32
32
|
})]
|
|
33
33
|
});
|
|
34
|
-
if (!
|
|
34
|
+
if (!B) return /* @__PURE__ */ _("div", {
|
|
35
35
|
className: "flex items-center justify-center min-h-[400px]",
|
|
36
|
-
children: /* @__PURE__ */
|
|
36
|
+
children: /* @__PURE__ */ v("div", {
|
|
37
37
|
className: "text-center space-y-2",
|
|
38
|
-
children: [/* @__PURE__ */
|
|
38
|
+
children: [/* @__PURE__ */ _("h2", {
|
|
39
39
|
className: "text-lg font-semibold",
|
|
40
|
-
children: r(
|
|
41
|
-
}), /* @__PURE__ */
|
|
40
|
+
children: r(A, "workspaceDetail.accessDenied", "Access Denied")
|
|
41
|
+
}), /* @__PURE__ */ _("p", {
|
|
42
42
|
className: "text-sm text-muted-foreground",
|
|
43
|
-
children: r(
|
|
43
|
+
children: r(A, "workspaceDetail.accessDeniedDesc", "You don't have permission to view this workspace.")
|
|
44
44
|
})]
|
|
45
45
|
})
|
|
46
46
|
});
|
|
47
|
-
if (
|
|
47
|
+
if (F) return /* @__PURE__ */ v("div", {
|
|
48
48
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
49
|
+
children: [/* @__PURE__ */ _(T, { className: "h-10 w-1/3" }), /* @__PURE__ */ v("div", {
|
|
50
50
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
51
51
|
children: [
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
/* @__PURE__ */
|
|
54
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ _(T, { className: "h-32" }),
|
|
53
|
+
/* @__PURE__ */ _(T, { className: "h-32" }),
|
|
54
|
+
/* @__PURE__ */ _(T, { className: "h-32" })
|
|
55
55
|
]
|
|
56
56
|
})]
|
|
57
57
|
});
|
|
58
|
-
if (
|
|
58
|
+
if (I || !P) return /* @__PURE__ */ v("div", {
|
|
59
59
|
className: "space-y-4 p-6",
|
|
60
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ v(b, {
|
|
61
61
|
variant: "ghost",
|
|
62
|
-
onClick: () =>
|
|
62
|
+
onClick: () => j(N(`${M}/list`)),
|
|
63
63
|
className: "gap-2",
|
|
64
|
-
children: [/* @__PURE__ */
|
|
65
|
-
}), /* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ _(u, { size: 20 }), r(A, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
65
|
+
}), /* @__PURE__ */ _("div", {
|
|
66
66
|
className: "text-center py-12",
|
|
67
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ _("p", {
|
|
68
68
|
className: "text-destructive",
|
|
69
|
-
children: r(
|
|
69
|
+
children: r(A, "workspaceDetail.notFound", "Workspace not found")
|
|
70
70
|
})
|
|
71
71
|
})]
|
|
72
72
|
});
|
|
73
|
-
let
|
|
74
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
73
|
+
let W = (e, t) => {
|
|
74
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), j(t));
|
|
75
75
|
};
|
|
76
|
-
return /* @__PURE__ */
|
|
76
|
+
return /* @__PURE__ */ v("div", {
|
|
77
77
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
78
78
|
children: [
|
|
79
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ v("div", {
|
|
80
80
|
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ v("div", { children: [
|
|
82
|
+
/* @__PURE__ */ v(b, {
|
|
83
83
|
variant: "ghost",
|
|
84
|
-
onClick: () =>
|
|
84
|
+
onClick: () => j(N(`${M}/list`)),
|
|
85
85
|
className: "gap-2 mb-2 -ml-2",
|
|
86
|
-
children: [/* @__PURE__ */
|
|
86
|
+
children: [/* @__PURE__ */ _(u, { size: 20 }), r(A, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
87
87
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ _("h1", {
|
|
89
89
|
className: "text-2xl sm:text-3xl font-bold",
|
|
90
|
-
children:
|
|
90
|
+
children: P.name
|
|
91
91
|
}),
|
|
92
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ v("div", {
|
|
93
93
|
className: "flex items-center gap-2 mt-2",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ _(y, {
|
|
95
95
|
variant: "outline",
|
|
96
|
-
children:
|
|
97
|
-
}), /* @__PURE__ */
|
|
96
|
+
children: P.type
|
|
97
|
+
}), /* @__PURE__ */ _(y, { children: P.status })]
|
|
98
98
|
})
|
|
99
|
-
] }),
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
] }), /* @__PURE__ */ v("div", {
|
|
100
|
+
className: "flex flex-wrap items-center gap-2",
|
|
101
|
+
children: [H ? /* @__PURE__ */ v(b, {
|
|
102
|
+
variant: "outline",
|
|
103
|
+
onClick: () => j(N(`${M}/${k}/invite`)),
|
|
104
|
+
className: "gap-2",
|
|
105
|
+
children: [/* @__PURE__ */ _(m, { size: 18 }), r(A, "workspaceDetail.inviteMembers", "Invite Member")]
|
|
106
|
+
}) : null, V && /* @__PURE__ */ v(b, {
|
|
107
|
+
onClick: () => j(N(`${M}/${k}/settings`)),
|
|
108
|
+
className: "gap-2",
|
|
109
|
+
children: [/* @__PURE__ */ _(p, { size: 20 }), r(A, "workspaceDetail.settings", "Settings")]
|
|
110
|
+
})]
|
|
103
111
|
})]
|
|
104
112
|
}),
|
|
105
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ v("div", {
|
|
106
114
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
107
115
|
children: [
|
|
108
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ v(x, {
|
|
109
117
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
110
|
-
onClick: () =>
|
|
118
|
+
onClick: () => j(N(`${M}/${k}/projects`)),
|
|
111
119
|
role: "button",
|
|
112
120
|
tabIndex: 0,
|
|
113
|
-
onKeyDown: (e) =>
|
|
114
|
-
children: [/* @__PURE__ */
|
|
121
|
+
onKeyDown: (e) => W(e, N(`${M}/${k}/projects`)),
|
|
122
|
+
children: [/* @__PURE__ */ v(C, {
|
|
115
123
|
className: "flex flex-row items-center justify-between pb-2",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
124
|
+
children: [/* @__PURE__ */ v(w, {
|
|
117
125
|
className: "flex items-center gap-2",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
126
|
+
children: [/* @__PURE__ */ _(f, {
|
|
119
127
|
size: 20,
|
|
120
128
|
className: "text-muted-foreground"
|
|
121
|
-
}), r(
|
|
122
|
-
}), /* @__PURE__ */
|
|
129
|
+
}), r(A, "workspaceDetail.projects", "Projects")]
|
|
130
|
+
}), /* @__PURE__ */ _(d, {
|
|
123
131
|
size: 20,
|
|
124
132
|
className: "text-muted-foreground"
|
|
125
133
|
})]
|
|
126
|
-
}), /* @__PURE__ */
|
|
134
|
+
}), /* @__PURE__ */ v(S, { children: [/* @__PURE__ */ _("p", {
|
|
127
135
|
className: "text-3xl font-bold",
|
|
128
|
-
children:
|
|
129
|
-
}), /* @__PURE__ */
|
|
136
|
+
children: L?.total ?? P.projectCount ?? 0
|
|
137
|
+
}), /* @__PURE__ */ _("p", {
|
|
130
138
|
className: "text-sm text-muted-foreground",
|
|
131
|
-
children: r(
|
|
139
|
+
children: r(A, "workspaceDetail.projectsDesc", "Projects in this workspace")
|
|
132
140
|
})] })]
|
|
133
141
|
}),
|
|
134
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ v(x, {
|
|
135
143
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
136
|
-
onClick: () =>
|
|
144
|
+
onClick: () => j(N(`${M}/${k}/members`)),
|
|
137
145
|
role: "button",
|
|
138
146
|
tabIndex: 0,
|
|
139
|
-
onKeyDown: (e) =>
|
|
140
|
-
children: [/* @__PURE__ */
|
|
147
|
+
onKeyDown: (e) => W(e, N(`${M}/${k}/members`)),
|
|
148
|
+
children: [/* @__PURE__ */ v(C, {
|
|
141
149
|
className: "flex flex-row items-center justify-between pb-2",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
150
|
+
children: [/* @__PURE__ */ v(w, {
|
|
143
151
|
className: "flex items-center gap-2",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
152
|
+
children: [/* @__PURE__ */ _(h, {
|
|
145
153
|
size: 20,
|
|
146
154
|
className: "text-muted-foreground"
|
|
147
|
-
}), r(
|
|
148
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), r(A, "workspaceDetail.members", "Members")]
|
|
156
|
+
}), /* @__PURE__ */ _(d, {
|
|
149
157
|
size: 20,
|
|
150
158
|
className: "text-muted-foreground"
|
|
151
159
|
})]
|
|
152
|
-
}), /* @__PURE__ */
|
|
160
|
+
}), /* @__PURE__ */ v(S, { children: [/* @__PURE__ */ _("p", {
|
|
153
161
|
className: "text-3xl font-bold",
|
|
154
|
-
children:
|
|
155
|
-
}), /* @__PURE__ */
|
|
162
|
+
children: R?.total ?? P.memberCount ?? 0
|
|
163
|
+
}), /* @__PURE__ */ _("p", {
|
|
156
164
|
className: "text-sm text-muted-foreground",
|
|
157
|
-
children: r(
|
|
165
|
+
children: r(A, "workspaceDetail.membersDesc", "Workspace members")
|
|
158
166
|
})] })]
|
|
159
167
|
}),
|
|
160
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ v(x, {
|
|
161
169
|
className: "cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200",
|
|
162
|
-
onClick: () =>
|
|
170
|
+
onClick: () => j(N(`${M}/${k}/activity`)),
|
|
163
171
|
role: "button",
|
|
164
172
|
tabIndex: 0,
|
|
165
|
-
onKeyDown: (e) =>
|
|
166
|
-
children: [/* @__PURE__ */
|
|
173
|
+
onKeyDown: (e) => W(e, N(`${M}/${k}/activity`)),
|
|
174
|
+
children: [/* @__PURE__ */ v(C, {
|
|
167
175
|
className: "flex flex-row items-center justify-between pb-2",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ v(w, {
|
|
169
177
|
className: "flex items-center gap-2",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
178
|
+
children: [/* @__PURE__ */ _(l, {
|
|
171
179
|
size: 20,
|
|
172
180
|
className: "text-muted-foreground"
|
|
173
|
-
}), r(
|
|
174
|
-
}), /* @__PURE__ */
|
|
181
|
+
}), r(A, "workspaceDetail.activity", "Activity")]
|
|
182
|
+
}), /* @__PURE__ */ _(d, {
|
|
175
183
|
size: 20,
|
|
176
184
|
className: "text-muted-foreground"
|
|
177
185
|
})]
|
|
178
|
-
}), /* @__PURE__ */
|
|
186
|
+
}), /* @__PURE__ */ v(S, { children: [/* @__PURE__ */ _("p", {
|
|
179
187
|
className: "text-3xl font-bold",
|
|
180
|
-
children:
|
|
181
|
-
}), /* @__PURE__ */
|
|
188
|
+
children: z?.length ?? 0
|
|
189
|
+
}), /* @__PURE__ */ _("p", {
|
|
182
190
|
className: "text-sm text-muted-foreground",
|
|
183
|
-
children: r(
|
|
191
|
+
children: r(A, "workspaceDetail.activityDesc", "Recent activity items")
|
|
184
192
|
})] })]
|
|
185
193
|
})
|
|
186
194
|
]
|
|
187
195
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
196
|
+
/* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, { children: r(A, "workspaceDetail.workspaceInformation", "Workspace Information") }) }), /* @__PURE__ */ _(S, {
|
|
189
197
|
className: "space-y-2",
|
|
190
|
-
children: /* @__PURE__ */
|
|
198
|
+
children: /* @__PURE__ */ v("div", {
|
|
191
199
|
className: "grid grid-cols-2 gap-2 text-sm",
|
|
192
200
|
children: [
|
|
193
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ _("span", {
|
|
194
202
|
className: "text-muted-foreground",
|
|
195
|
-
children: r(
|
|
203
|
+
children: r(A, "workspaceDetail.id", "ID:")
|
|
196
204
|
}),
|
|
197
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ _("span", {
|
|
198
206
|
className: "font-mono text-xs",
|
|
199
|
-
children:
|
|
207
|
+
children: P.id
|
|
200
208
|
}),
|
|
201
|
-
|
|
209
|
+
P.domain && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
202
210
|
className: "text-muted-foreground",
|
|
203
|
-
children: r(
|
|
204
|
-
}), /* @__PURE__ */
|
|
205
|
-
|
|
211
|
+
children: r(A, "workspaceDetail.domain", "Domain:")
|
|
212
|
+
}), /* @__PURE__ */ _("span", { children: P.domain })] }),
|
|
213
|
+
P.contactEmail && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
206
214
|
className: "text-muted-foreground",
|
|
207
|
-
children: r(
|
|
208
|
-
}), /* @__PURE__ */
|
|
209
|
-
|
|
215
|
+
children: r(A, "workspaceDetail.contactEmail", "Contact Email:")
|
|
216
|
+
}), /* @__PURE__ */ _("span", { children: P.contactEmail })] }),
|
|
217
|
+
P.website && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
210
218
|
className: "text-muted-foreground",
|
|
211
|
-
children: r(
|
|
212
|
-
}), /* @__PURE__ */
|
|
213
|
-
href:
|
|
219
|
+
children: r(A, "workspaceDetail.website", "Website:")
|
|
220
|
+
}), /* @__PURE__ */ _("a", {
|
|
221
|
+
href: P.website,
|
|
214
222
|
target: "_blank",
|
|
215
223
|
rel: "noopener noreferrer",
|
|
216
224
|
className: "text-primary hover:underline transition-colors duration-200",
|
|
217
|
-
children:
|
|
225
|
+
children: P.website
|
|
218
226
|
})] }),
|
|
219
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ _("span", {
|
|
220
228
|
className: "text-muted-foreground",
|
|
221
|
-
children: r(
|
|
229
|
+
children: r(A, "workspaceDetail.created", "Created:")
|
|
222
230
|
}),
|
|
223
|
-
/* @__PURE__ */
|
|
231
|
+
/* @__PURE__ */ _("span", { children: new Date(P.createdAt).toLocaleDateString() })
|
|
224
232
|
]
|
|
225
233
|
})
|
|
226
234
|
})] })
|
|
@@ -228,6 +236,6 @@ function O() {
|
|
|
228
236
|
});
|
|
229
237
|
}
|
|
230
238
|
//#endregion
|
|
231
|
-
export {
|
|
239
|
+
export { k as WorkspaceDetailPage };
|
|
232
240
|
|
|
233
241
|
//# sourceMappingURL=WorkspaceDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../src/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useParams, useNavigate } from 'react-router-dom';\nimport { Settings, ArrowLeft, FolderKanban, Users, Activity, ChevronRight } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useProjects } from '../hooks/useProjects';\nimport { useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { useWorkspaceActivity } from '../hooks/useWorkspaceActivity';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspaceDetailPage() {\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.detail', { workspaceId, requireParams: true });\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { data: workspace, isLoading, error } = useWorkspace(workspaceId || '');\n const { data: projects } = useProjects({ workspaceId }, { limit: 1 }, workspaceId);\n const { data: members } = useWorkspaceMembers(workspaceId || '', { limit: 1 });\n const { data: activities } = useWorkspaceActivity(workspaceId);\n const {\n canViewWorkspace,\n canUpdateWorkspace,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canViewWorkspace) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'workspaceDetail.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'workspaceDetail.accessDeniedDesc',\n \"You don't have permission to view this workspace.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <div className=\"text-center py-12\">\n <p className=\"text-destructive\">\n {tWithFallback(t, 'workspaceDetail.notFound', 'Workspace not found')}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCardKeyDown = (e: React.KeyboardEvent, path: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigate(path);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">{workspace.name}</h1>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge variant=\"outline\">{workspace.type}</Badge>\n <Badge>{workspace.status}</Badge>\n </div>\n </div>\n {canUpdateWorkspace && (\n <Button\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`))}\n className=\"gap-2\"\n >\n <Settings size={20} />\n {tWithFallback(t, 'workspaceDetail.settings', 'Settings')}\n </Button>\n )}\n </div>\n\n {/* Stats Cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/projects`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <FolderKanban size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{projects?.total ?? workspace.projectCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/members`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Users size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{members?.total ?? workspace.memberCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/activity`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/activity`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Activity size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {/* Workspace Info */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'workspaceDetail.workspaceInformation', 'Workspace Information')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.id', 'ID:')}\n </span>\n <span className=\"font-mono text-xs\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span>{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.website', 'Website:')}\n </span>\n <a\n href={workspace.website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary hover:underline transition-colors duration-200\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../src/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useParams, useNavigate } from 'react-router-dom';\nimport {\n Settings,\n ArrowLeft,\n FolderKanban,\n Users,\n Activity,\n ChevronRight,\n UserPlus,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n Card,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useProjects } from '../hooks/useProjects';\nimport { useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { useWorkspaceActivity } from '../hooks/useWorkspaceActivity';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspaceDetailPage() {\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.detail', { workspaceId, requireParams: true });\n const { t } = useI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { data: workspace, isLoading, error } = useWorkspace(workspaceId || '');\n const { data: projects } = useProjects({ workspaceId }, { limit: 1 }, workspaceId);\n const { data: members } = useWorkspaceMembers(workspaceId || '', { limit: 1 });\n const { data: activities } = useWorkspaceActivity(workspaceId);\n const {\n canViewWorkspace,\n canUpdateWorkspace,\n canInviteMember,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (!canViewWorkspace) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'workspaceDetail.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'workspaceDetail.accessDeniedDesc',\n \"You don't have permission to view this workspace.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n <Skeleton className=\"h-32\" />\n </div>\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <div className=\"text-center py-12\">\n <p className=\"text-destructive\">\n {tWithFallback(t, 'workspaceDetail.notFound', 'Workspace not found')}\n </p>\n </div>\n </div>\n );\n }\n\n const handleCardKeyDown = (e: React.KeyboardEvent, path: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigate(path);\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/list`))}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceDetail.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">{workspace.name}</h1>\n <div className=\"flex items-center gap-2 mt-2\">\n <Badge variant=\"outline\">{workspace.type}</Badge>\n <Badge>{workspace.status}</Badge>\n </div>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {canInviteMember ? (\n <Button\n variant=\"outline\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`))}\n className=\"gap-2\"\n >\n <UserPlus size={18} />\n {tWithFallback(t, 'workspaceDetail.inviteMembers', 'Invite Member')}\n </Button>\n ) : null}\n {canUpdateWorkspace && (\n <Button\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`))}\n className=\"gap-2\"\n >\n <Settings size={20} />\n {tWithFallback(t, 'workspaceDetail.settings', 'Settings')}\n </Button>\n )}\n </div>\n </div>\n\n {/* Stats Cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/projects`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <FolderKanban size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{projects?.total ?? workspace.projectCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/members`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Users size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{members?.total ?? workspace.memberCount ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </Card>\n\n <Card\n className=\"cursor-pointer hover:border-primary/50 hover:shadow-md transition-all duration-200\"\n onClick={() => navigate(withCurrentSearch(`${basePath}/${workspaceId}/activity`))}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) =>\n handleCardKeyDown(e, withCurrentSearch(`${basePath}/${workspaceId}/activity`))\n }\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2\">\n <CardTitle className=\"flex items-center gap-2\">\n <Activity size={20} className=\"text-muted-foreground\" />\n {tWithFallback(t, 'workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={20} className=\"text-muted-foreground\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </Card>\n </div>\n\n {/* Workspace Info */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'workspaceDetail.workspaceInformation', 'Workspace Information')}\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.id', 'ID:')}\n </span>\n <span className=\"font-mono text-xs\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span>{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.website', 'Website:')}\n </span>\n <a\n href={workspace.website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-primary hover:underline transition-colors duration-200\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-muted-foreground\">\n {tWithFallback(t, 'workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|