@burdenoff/microfe-workspaces 2026.802.1 → 2026.829.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/generated/global-operations.js +44 -1
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/wspace-operations.js +18 -18
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/hooks/useWorkspaceMutations.js +84 -61
- package/dist/hooks/useWorkspaceMutations.js.map +1 -1
- package/dist/pages/MembersListPage.js +3 -3
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +3 -3
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +152 -114
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceInvitePage.js +2 -2
- package/dist/pages/WorkspaceInvitePage.js.map +1 -1
- package/dist/pages/dashboard/DashboardCustomizer.js +62 -62
- package/dist/pages/dashboard/DashboardCustomizer.js.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +88 -69
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/config.js +77 -1
- package/dist/pages/dashboard/config.js.map +1 -1
- package/dist/pages/dashboard/widgets/AgentsWidget.js +56 -54
- package/dist/pages/dashboard/widgets/AgentsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/GroupsWidget.js +29 -31
- package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/MembersWidget.js +33 -33
- package/dist/pages/dashboard/widgets/MembersWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/ProjectsWidget.js +42 -44
- package/dist/pages/dashboard/widgets/ProjectsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/QuickActionsWidget.js +171 -161
- package/dist/pages/dashboard/widgets/QuickActionsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js +54 -44
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/SessionsWidget.js +57 -41
- package/dist/pages/dashboard/widgets/SessionsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/StorageWidget.js +52 -54
- package/dist/pages/dashboard/widgets/StorageWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TagCloudWidget.js +28 -30
- package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TipsWidget.js +141 -131
- package/dist/pages/dashboard/widgets/TipsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js +46 -40
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/VibesWidget.js +44 -34
- package/dist/pages/dashboard/widgets/VibesWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WelcomeWidget.js +43 -41
- package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowRunsWidget.js +68 -62
- package/dist/pages/dashboard/widgets/WorkflowRunsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +50 -44
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowsOverviewWidget.js +59 -49
- package/dist/pages/dashboard/widgets/WorkflowsOverviewWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js +35 -33
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js.map +1 -1
- package/package.json +4 -4
|
@@ -2,74 +2,85 @@ import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
|
2
2
|
import { useWorkspace as t } from "../hooks/useWorkspaces.js";
|
|
3
3
|
import { useScopedNavigation as n } from "../hooks/useScopedNavigation.js";
|
|
4
4
|
import { tWithFallback as r } from "../utils/i18n.js";
|
|
5
|
-
import { useWorkspacesPageView as
|
|
6
|
-
import { useWorkspaceMembers as
|
|
7
|
-
import { useWorkspacePermissions as
|
|
8
|
-
import { useProjects as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
5
|
+
import { useWorkspacesPageView as ee } from "../hooks/useWorkspacesPageView.js";
|
|
6
|
+
import { useWorkspaceMembers as te } from "../hooks/useWorkspaceMembers.js";
|
|
7
|
+
import { useWorkspacePermissions as ne } from "../hooks/useWorkspacePermissions.js";
|
|
8
|
+
import { useProjects as i } from "../hooks/useProjects.js";
|
|
9
|
+
import { useArchiveWorkspace as a } from "../hooks/useWorkspaceMutations.js";
|
|
10
|
+
import { useWorkspaceActivity as o } from "../hooks/useWorkspaceActivity.js";
|
|
11
|
+
import { useState as s } from "react";
|
|
12
|
+
import { Activity as c, Archive as l, ArrowLeft as u, ChevronRight as d, FolderKanban as f, Settings as p, UserPlus as m, Users as h } from "lucide-react";
|
|
11
13
|
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
12
|
-
import {
|
|
13
|
-
import { useNavigate as
|
|
14
|
-
import { useI18n as
|
|
14
|
+
import { AlertDialog as y, AlertDialogAction as b, AlertDialogCancel as x, AlertDialogContent as S, AlertDialogDescription as re, AlertDialogFooter as C, AlertDialogHeader as w, AlertDialogTitle as T, Badge as E, Button as D, CTAOverflowMenu as ie, CardContent as O, CardHeader as k, CardTitle as A, GlassCard as j, IllustratedEmptyState as M, NextSteps as N, PagePurpose as P, Skeleton as F } from "@burdenoff/fe-libs/ui";
|
|
15
|
+
import { useNavigate as I, useParams as L } from "react-router";
|
|
16
|
+
import { useI18n as R } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
15
17
|
//#region src/pages/WorkspaceDetailPage.tsx
|
|
16
|
-
function
|
|
17
|
-
let { workspaceId:
|
|
18
|
-
|
|
19
|
-
workspaceId:
|
|
18
|
+
function z() {
|
|
19
|
+
let { workspaceId: z } = L();
|
|
20
|
+
ee("workspaces.detail", {
|
|
21
|
+
workspaceId: z,
|
|
20
22
|
requireParams: !0
|
|
21
23
|
});
|
|
22
|
-
let { t:
|
|
23
|
-
if (
|
|
24
|
+
let { t: B } = R(), V = I(), { basePath: H = "/" } = e(), { withCurrentSearch: U } = n(), [W, G] = s(!1), [K, q] = s(null), { mutate: J, isPending: Y } = a(), { data: X, isLoading: ae, error: oe } = t(z || ""), { data: se } = i({ workspaceId: z }, { limit: 1 }, z), { data: ce } = te(z || "", { limit: 1 }), { data: le } = o(z), { canViewWorkspace: ue, canUpdateWorkspace: Z, canArchiveWorkspace: de, canInviteMember: Q, isLoading: fe } = ne();
|
|
25
|
+
if (fe) return /* @__PURE__ */ v("div", {
|
|
24
26
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
25
|
-
children: [/* @__PURE__ */ _(
|
|
27
|
+
children: [/* @__PURE__ */ _(F, { className: "h-10 w-1/3" }), /* @__PURE__ */ v("div", {
|
|
26
28
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
27
29
|
children: [
|
|
28
|
-
/* @__PURE__ */ _(
|
|
29
|
-
/* @__PURE__ */ _(
|
|
30
|
-
/* @__PURE__ */ _(
|
|
30
|
+
/* @__PURE__ */ _(F, { className: "h-32" }),
|
|
31
|
+
/* @__PURE__ */ _(F, { className: "h-32" }),
|
|
32
|
+
/* @__PURE__ */ _(F, { className: "h-32" })
|
|
31
33
|
]
|
|
32
34
|
})]
|
|
33
35
|
});
|
|
34
|
-
if (!
|
|
36
|
+
if (!ue) return /* @__PURE__ */ _("div", {
|
|
35
37
|
className: "flex items-center justify-center min-h-[400px]",
|
|
36
38
|
children: /* @__PURE__ */ v("div", {
|
|
37
39
|
className: "text-center space-y-2",
|
|
38
40
|
children: [/* @__PURE__ */ _("h2", {
|
|
39
41
|
className: "text-lg font-semibold",
|
|
40
|
-
children: r(
|
|
42
|
+
children: r(B, "workspaceDetail.accessDenied", "Access Denied")
|
|
41
43
|
}), /* @__PURE__ */ _("p", {
|
|
42
44
|
className: "text-sm text-text-secondary",
|
|
43
|
-
children: r(
|
|
45
|
+
children: r(B, "workspaceDetail.accessDeniedDesc", "You don't have permission to view this workspace.")
|
|
44
46
|
})]
|
|
45
47
|
})
|
|
46
48
|
});
|
|
47
|
-
if (
|
|
49
|
+
if (ae) return /* @__PURE__ */ v("div", {
|
|
48
50
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
49
|
-
children: [/* @__PURE__ */ _(
|
|
51
|
+
children: [/* @__PURE__ */ _(F, { className: "h-10 w-1/3" }), /* @__PURE__ */ v("div", {
|
|
50
52
|
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
51
53
|
children: [
|
|
52
|
-
/* @__PURE__ */ _(
|
|
53
|
-
/* @__PURE__ */ _(
|
|
54
|
-
/* @__PURE__ */ _(
|
|
54
|
+
/* @__PURE__ */ _(F, { className: "h-32" }),
|
|
55
|
+
/* @__PURE__ */ _(F, { className: "h-32" }),
|
|
56
|
+
/* @__PURE__ */ _(F, { className: "h-32" })
|
|
55
57
|
]
|
|
56
58
|
})]
|
|
57
59
|
});
|
|
58
|
-
if (
|
|
60
|
+
if (oe || !X) return /* @__PURE__ */ v("div", {
|
|
59
61
|
className: "space-y-4 p-6",
|
|
60
|
-
children: [/* @__PURE__ */ v(
|
|
62
|
+
children: [/* @__PURE__ */ v(D, {
|
|
61
63
|
variant: "ghost",
|
|
62
|
-
onClick: () =>
|
|
64
|
+
onClick: () => V(U(`${H}/list`)),
|
|
63
65
|
className: "gap-2",
|
|
64
|
-
children: [/* @__PURE__ */ _(u, { size: 20 }), r(
|
|
65
|
-
}), /* @__PURE__ */ _(
|
|
66
|
+
children: [/* @__PURE__ */ _(u, { size: 20 }), r(B, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
67
|
+
}), /* @__PURE__ */ _(M, {
|
|
66
68
|
illustration: "empty-search",
|
|
67
|
-
title: r(
|
|
68
|
-
description: r(
|
|
69
|
+
title: r(B, "workspaceDetail.notFound", "Workspace not found"),
|
|
70
|
+
description: r(B, "workspaceDetail.notFoundDescription", "This workspace doesn't exist or you don't have permission to view it.")
|
|
69
71
|
})]
|
|
70
72
|
});
|
|
71
|
-
let
|
|
72
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
73
|
+
let $ = (e, t) => {
|
|
74
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), V(t));
|
|
75
|
+
}, pe = () => {
|
|
76
|
+
z && (q(null), J(z, {
|
|
77
|
+
onSuccess: () => {
|
|
78
|
+
G(!1), V(U(`${H}/list`));
|
|
79
|
+
},
|
|
80
|
+
onError: () => {
|
|
81
|
+
q(r(B, "workspaceDetail.archiveFailed", "The workspace could not be archived. Please try again."));
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
73
84
|
};
|
|
74
85
|
return /* @__PURE__ */ v("div", {
|
|
75
86
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
@@ -77,71 +88,75 @@ function N() {
|
|
|
77
88
|
/* @__PURE__ */ v("div", {
|
|
78
89
|
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
|
|
79
90
|
children: [/* @__PURE__ */ v("div", { children: [
|
|
80
|
-
/* @__PURE__ */ v(
|
|
91
|
+
/* @__PURE__ */ v(D, {
|
|
81
92
|
variant: "ghost",
|
|
82
|
-
onClick: () =>
|
|
93
|
+
onClick: () => V(U(`${H}/list`)),
|
|
83
94
|
className: "gap-2 mb-2 -ml-2",
|
|
84
|
-
children: [/* @__PURE__ */ _(u, { size: 20 }), r(
|
|
95
|
+
children: [/* @__PURE__ */ _(u, { size: 20 }), r(B, "workspaceDetail.backToWorkspaces", "Back to Workspaces")]
|
|
85
96
|
}),
|
|
86
97
|
/* @__PURE__ */ _("h1", {
|
|
87
98
|
className: "text-2xl sm:text-3xl font-bold",
|
|
88
|
-
children:
|
|
99
|
+
children: X.name
|
|
89
100
|
}),
|
|
90
101
|
/* @__PURE__ */ v("div", {
|
|
91
102
|
className: "flex items-center gap-2 mt-2",
|
|
92
|
-
children: [/* @__PURE__ */ _(
|
|
103
|
+
children: [/* @__PURE__ */ _(E, {
|
|
93
104
|
variant: "outline",
|
|
94
|
-
children:
|
|
95
|
-
}), /* @__PURE__ */ _(
|
|
105
|
+
children: X.type
|
|
106
|
+
}), /* @__PURE__ */ _(E, { children: X.status })]
|
|
96
107
|
})
|
|
97
|
-
] }), /* @__PURE__ */ _(
|
|
98
|
-
primary:
|
|
99
|
-
label: r(
|
|
108
|
+
] }), /* @__PURE__ */ _(ie, {
|
|
109
|
+
primary: Z ? {
|
|
110
|
+
label: r(B, "workspaceDetail.settings", "Settings"),
|
|
100
111
|
icon: /* @__PURE__ */ _(p, { size: 18 }),
|
|
101
|
-
onSelect: () =>
|
|
102
|
-
} :
|
|
103
|
-
label: r(
|
|
112
|
+
onSelect: () => V(U(`${H}/${z}/settings`))
|
|
113
|
+
} : Q ? {
|
|
114
|
+
label: r(B, "workspaceDetail.inviteMembers", "Invite Member"),
|
|
104
115
|
icon: /* @__PURE__ */ _(m, { size: 18 }),
|
|
105
|
-
onSelect: () =>
|
|
116
|
+
onSelect: () => V(U(`${H}/${z}/invite`))
|
|
106
117
|
} : void 0,
|
|
107
|
-
actions: [...
|
|
108
|
-
label: r(
|
|
118
|
+
actions: [...Z && Q ? [{
|
|
119
|
+
label: r(B, "workspaceDetail.inviteMembers", "Invite Member"),
|
|
109
120
|
icon: /* @__PURE__ */ _(m, { size: 16 }),
|
|
110
|
-
onSelect: () =>
|
|
121
|
+
onSelect: () => V(U(`${H}/${z}/invite`))
|
|
122
|
+
}] : [], ...de ? [{
|
|
123
|
+
label: r(B, "workspaceDetail.archiveWorkspace", "Archive Workspace"),
|
|
124
|
+
icon: /* @__PURE__ */ _(l, { size: 16 }),
|
|
125
|
+
onSelect: () => G(!0)
|
|
111
126
|
}] : []]
|
|
112
127
|
})]
|
|
113
128
|
}),
|
|
114
|
-
/* @__PURE__ */ _(
|
|
115
|
-
/* @__PURE__ */ _(
|
|
129
|
+
/* @__PURE__ */ _(P, { children: r(B, "workspaceDetail.purpose", "This is the home for a single workspace — the hub that ties together its projects, the people who collaborate in it, and everything that happens inside. Use the cards below to jump into work, manage who has access, or review recent activity.") }),
|
|
130
|
+
/* @__PURE__ */ _(N, {
|
|
116
131
|
storageKey: "workspaces-workspace-detail",
|
|
117
132
|
steps: [
|
|
118
133
|
{
|
|
119
134
|
id: "open-projects",
|
|
120
|
-
label: r(
|
|
121
|
-
description: r(
|
|
135
|
+
label: r(B, "workspaceDetail.stepProjects", "Open the projects board"),
|
|
136
|
+
description: r(B, "workspaceDetail.stepProjectsDesc", "Projects are where the actual work lives — start or pick one up."),
|
|
122
137
|
icon: /* @__PURE__ */ _(f, { size: 16 }),
|
|
123
|
-
onClick: () =>
|
|
138
|
+
onClick: () => V(U(`${H}/${z}/projects`))
|
|
124
139
|
},
|
|
125
|
-
...
|
|
140
|
+
...Q ? [{
|
|
126
141
|
id: "invite-member",
|
|
127
|
-
label: r(
|
|
128
|
-
description: r(
|
|
142
|
+
label: r(B, "workspaceDetail.stepInvite", "Invite a teammate"),
|
|
143
|
+
description: r(B, "workspaceDetail.stepInviteDesc", "Bring people into this workspace so they can collaborate."),
|
|
129
144
|
icon: /* @__PURE__ */ _(m, { size: 16 }),
|
|
130
|
-
onClick: () =>
|
|
145
|
+
onClick: () => V(U(`${H}/${z}/invite`))
|
|
131
146
|
}] : [],
|
|
132
147
|
{
|
|
133
148
|
id: "review-members",
|
|
134
|
-
label: r(
|
|
135
|
-
description: r(
|
|
149
|
+
label: r(B, "workspaceDetail.stepMembers", "Review who has access"),
|
|
150
|
+
description: r(B, "workspaceDetail.stepMembersDesc", "Check the current members and their roles."),
|
|
136
151
|
icon: /* @__PURE__ */ _(h, { size: 16 }),
|
|
137
|
-
onClick: () =>
|
|
152
|
+
onClick: () => V(U(`${H}/${z}/members`))
|
|
138
153
|
},
|
|
139
|
-
...
|
|
154
|
+
...Z ? [{
|
|
140
155
|
id: "configure-settings",
|
|
141
|
-
label: r(
|
|
142
|
-
description: r(
|
|
156
|
+
label: r(B, "workspaceDetail.stepSettings", "Configure workspace settings"),
|
|
157
|
+
description: r(B, "workspaceDetail.stepSettingsDesc", "Set the name, domain and contact details for this workspace."),
|
|
143
158
|
icon: /* @__PURE__ */ _(p, { size: 16 }),
|
|
144
|
-
onClick: () =>
|
|
159
|
+
onClick: () => V(U(`${H}/${z}/settings`))
|
|
145
160
|
}] : []
|
|
146
161
|
]
|
|
147
162
|
}),
|
|
@@ -152,144 +167,167 @@ function N() {
|
|
|
152
167
|
children: /* @__PURE__ */ v("div", {
|
|
153
168
|
className: "grid grid-cols-1 sm:grid-cols-3 gap-4",
|
|
154
169
|
children: [
|
|
155
|
-
/* @__PURE__ */ v(
|
|
170
|
+
/* @__PURE__ */ v(j, {
|
|
156
171
|
treatment: "metric",
|
|
157
172
|
glow: !0,
|
|
158
173
|
className: "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50",
|
|
159
|
-
onClick: () =>
|
|
174
|
+
onClick: () => V(U(`${H}/${z}/projects`)),
|
|
160
175
|
role: "button",
|
|
161
176
|
tabIndex: 0,
|
|
162
|
-
onKeyDown: (e) =>
|
|
163
|
-
children: [/* @__PURE__ */ v(
|
|
177
|
+
onKeyDown: (e) => $(e, U(`${H}/${z}/projects`)),
|
|
178
|
+
children: [/* @__PURE__ */ v(k, {
|
|
164
179
|
className: "flex flex-row items-center justify-between pb-2",
|
|
165
|
-
children: [/* @__PURE__ */ v(
|
|
180
|
+
children: [/* @__PURE__ */ v(A, {
|
|
166
181
|
className: "flex items-center gap-2 text-text-secondary text-sm font-medium",
|
|
167
182
|
children: [/* @__PURE__ */ _(f, {
|
|
168
183
|
size: 18,
|
|
169
184
|
className: "text-text-muted"
|
|
170
|
-
}), r(
|
|
185
|
+
}), r(B, "workspaceDetail.projects", "Projects")]
|
|
171
186
|
}), /* @__PURE__ */ _(d, {
|
|
172
187
|
size: 18,
|
|
173
188
|
className: "text-text-muted"
|
|
174
189
|
})]
|
|
175
|
-
}), /* @__PURE__ */ v(
|
|
190
|
+
}), /* @__PURE__ */ v(O, { children: [/* @__PURE__ */ _("p", {
|
|
176
191
|
className: "text-3xl font-bold tabular-nums",
|
|
177
|
-
children:
|
|
192
|
+
children: se?.total ?? X.projectCount ?? 0
|
|
178
193
|
}), /* @__PURE__ */ _("p", {
|
|
179
194
|
className: "text-sm text-text-muted",
|
|
180
|
-
children: r(
|
|
195
|
+
children: r(B, "workspaceDetail.projectsDesc", "Projects in this workspace")
|
|
181
196
|
})] })]
|
|
182
197
|
}),
|
|
183
|
-
/* @__PURE__ */ v(
|
|
198
|
+
/* @__PURE__ */ v(j, {
|
|
184
199
|
treatment: "metric",
|
|
185
200
|
className: "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50",
|
|
186
|
-
onClick: () =>
|
|
201
|
+
onClick: () => V(U(`${H}/${z}/members`)),
|
|
187
202
|
role: "button",
|
|
188
203
|
tabIndex: 0,
|
|
189
|
-
onKeyDown: (e) =>
|
|
190
|
-
children: [/* @__PURE__ */ v(
|
|
204
|
+
onKeyDown: (e) => $(e, U(`${H}/${z}/members`)),
|
|
205
|
+
children: [/* @__PURE__ */ v(k, {
|
|
191
206
|
className: "flex flex-row items-center justify-between pb-2",
|
|
192
|
-
children: [/* @__PURE__ */ v(
|
|
207
|
+
children: [/* @__PURE__ */ v(A, {
|
|
193
208
|
className: "flex items-center gap-2 text-text-secondary text-sm font-medium",
|
|
194
209
|
children: [/* @__PURE__ */ _(h, {
|
|
195
210
|
size: 18,
|
|
196
211
|
className: "text-text-muted"
|
|
197
|
-
}), r(
|
|
212
|
+
}), r(B, "workspaceDetail.members", "Members")]
|
|
198
213
|
}), /* @__PURE__ */ _(d, {
|
|
199
214
|
size: 18,
|
|
200
215
|
className: "text-text-muted"
|
|
201
216
|
})]
|
|
202
|
-
}), /* @__PURE__ */ v(
|
|
217
|
+
}), /* @__PURE__ */ v(O, { children: [/* @__PURE__ */ _("p", {
|
|
203
218
|
className: "text-3xl font-bold tabular-nums",
|
|
204
|
-
children:
|
|
219
|
+
children: ce?.total ?? X.memberCount ?? 0
|
|
205
220
|
}), /* @__PURE__ */ _("p", {
|
|
206
221
|
className: "text-sm text-text-muted",
|
|
207
|
-
children: r(
|
|
222
|
+
children: r(B, "workspaceDetail.membersDesc", "Workspace members")
|
|
208
223
|
})] })]
|
|
209
224
|
}),
|
|
210
|
-
/* @__PURE__ */ v(
|
|
225
|
+
/* @__PURE__ */ v(j, {
|
|
211
226
|
treatment: "metric",
|
|
212
227
|
className: "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50",
|
|
213
|
-
onClick: () =>
|
|
228
|
+
onClick: () => V(U(`${H}/${z}/activity`)),
|
|
214
229
|
role: "button",
|
|
215
230
|
tabIndex: 0,
|
|
216
|
-
onKeyDown: (e) =>
|
|
217
|
-
children: [/* @__PURE__ */ v(
|
|
231
|
+
onKeyDown: (e) => $(e, U(`${H}/${z}/activity`)),
|
|
232
|
+
children: [/* @__PURE__ */ v(k, {
|
|
218
233
|
className: "flex flex-row items-center justify-between pb-2",
|
|
219
|
-
children: [/* @__PURE__ */ v(
|
|
234
|
+
children: [/* @__PURE__ */ v(A, {
|
|
220
235
|
className: "flex items-center gap-2 text-text-secondary text-sm font-medium",
|
|
221
|
-
children: [/* @__PURE__ */ _(
|
|
236
|
+
children: [/* @__PURE__ */ _(c, {
|
|
222
237
|
size: 18,
|
|
223
238
|
className: "text-text-muted"
|
|
224
|
-
}), r(
|
|
239
|
+
}), r(B, "workspaceDetail.activity", "Activity")]
|
|
225
240
|
}), /* @__PURE__ */ _(d, {
|
|
226
241
|
size: 18,
|
|
227
242
|
className: "text-text-muted"
|
|
228
243
|
})]
|
|
229
|
-
}), /* @__PURE__ */ v(
|
|
244
|
+
}), /* @__PURE__ */ v(O, { children: [/* @__PURE__ */ _("p", {
|
|
230
245
|
className: "text-3xl font-bold tabular-nums",
|
|
231
|
-
children:
|
|
246
|
+
children: le?.length ?? 0
|
|
232
247
|
}), /* @__PURE__ */ _("p", {
|
|
233
248
|
className: "text-sm text-text-muted",
|
|
234
|
-
children: r(
|
|
249
|
+
children: r(B, "workspaceDetail.activityDesc", "Recent activity items")
|
|
235
250
|
})] })]
|
|
236
251
|
})
|
|
237
252
|
]
|
|
238
253
|
})
|
|
239
254
|
}), /* @__PURE__ */ _("aside", {
|
|
240
255
|
className: "lg:sticky lg:top-6 lg:self-start",
|
|
241
|
-
children: /* @__PURE__ */ v(
|
|
256
|
+
children: /* @__PURE__ */ v(j, {
|
|
242
257
|
treatment: "plain",
|
|
243
258
|
className: "border-border-seam",
|
|
244
|
-
children: [/* @__PURE__ */ _(
|
|
259
|
+
children: [/* @__PURE__ */ _(k, { children: /* @__PURE__ */ _(A, { children: r(B, "workspaceDetail.workspaceInformation", "Workspace Information") }) }), /* @__PURE__ */ _(O, {
|
|
245
260
|
className: "space-y-2",
|
|
246
261
|
children: /* @__PURE__ */ v("div", {
|
|
247
262
|
className: "grid grid-cols-2 gap-2 text-sm",
|
|
248
263
|
children: [
|
|
249
264
|
/* @__PURE__ */ _("span", {
|
|
250
265
|
className: "text-text-muted",
|
|
251
|
-
children: r(
|
|
266
|
+
children: r(B, "workspaceDetail.id", "ID:")
|
|
252
267
|
}),
|
|
253
268
|
/* @__PURE__ */ _("span", {
|
|
254
269
|
className: "font-mono text-xs break-all",
|
|
255
|
-
children:
|
|
270
|
+
children: X.id
|
|
256
271
|
}),
|
|
257
|
-
|
|
272
|
+
X.domain && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
258
273
|
className: "text-text-muted",
|
|
259
|
-
children: r(
|
|
260
|
-
}), /* @__PURE__ */ _("span", { children:
|
|
261
|
-
|
|
274
|
+
children: r(B, "workspaceDetail.domain", "Domain:")
|
|
275
|
+
}), /* @__PURE__ */ _("span", { children: X.domain })] }),
|
|
276
|
+
X.contactEmail && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
262
277
|
className: "text-text-muted",
|
|
263
|
-
children: r(
|
|
278
|
+
children: r(B, "workspaceDetail.contactEmail", "Contact Email:")
|
|
264
279
|
}), /* @__PURE__ */ _("span", {
|
|
265
280
|
className: "break-all",
|
|
266
|
-
children:
|
|
281
|
+
children: X.contactEmail
|
|
267
282
|
})] }),
|
|
268
|
-
|
|
283
|
+
X.website && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("span", {
|
|
269
284
|
className: "text-text-muted",
|
|
270
|
-
children: r(
|
|
285
|
+
children: r(B, "workspaceDetail.website", "Website:")
|
|
271
286
|
}), /* @__PURE__ */ _("a", {
|
|
272
|
-
href:
|
|
287
|
+
href: X.website,
|
|
273
288
|
target: "_blank",
|
|
274
289
|
rel: "noopener noreferrer",
|
|
275
290
|
className: "text-primary hover:underline transition-colors duration-200 break-all",
|
|
276
|
-
children:
|
|
291
|
+
children: X.website
|
|
277
292
|
})] }),
|
|
278
293
|
/* @__PURE__ */ _("span", {
|
|
279
294
|
className: "text-text-muted",
|
|
280
|
-
children: r(
|
|
295
|
+
children: r(B, "workspaceDetail.created", "Created:")
|
|
281
296
|
}),
|
|
282
|
-
/* @__PURE__ */ _("span", { children: new Date(
|
|
297
|
+
/* @__PURE__ */ _("span", { children: new Date(X.createdAt).toLocaleDateString() })
|
|
283
298
|
]
|
|
284
299
|
})
|
|
285
300
|
})]
|
|
286
301
|
})
|
|
287
302
|
})]
|
|
303
|
+
}),
|
|
304
|
+
/* @__PURE__ */ _(y, {
|
|
305
|
+
open: W,
|
|
306
|
+
onOpenChange: (e) => {
|
|
307
|
+
G(e), e || q(null);
|
|
308
|
+
},
|
|
309
|
+
children: /* @__PURE__ */ v(S, { children: [
|
|
310
|
+
/* @__PURE__ */ v(w, { children: [/* @__PURE__ */ _(T, { children: r(B, "workspaceDetail.archiveTitle", "Archive workspace?") }), /* @__PURE__ */ _(re, { children: r(B, "workspaceDetail.archiveDescription", "This removes the workspace from active work while preserving its data.") })] }),
|
|
311
|
+
K && /* @__PURE__ */ _("p", {
|
|
312
|
+
className: "text-sm text-status-error-text",
|
|
313
|
+
children: K
|
|
314
|
+
}),
|
|
315
|
+
/* @__PURE__ */ v(C, { children: [/* @__PURE__ */ _(x, {
|
|
316
|
+
disabled: Y,
|
|
317
|
+
children: r(B, "common.cancel", "Cancel")
|
|
318
|
+
}), /* @__PURE__ */ _(b, {
|
|
319
|
+
disabled: Y,
|
|
320
|
+
onClick: (e) => {
|
|
321
|
+
e.preventDefault(), pe();
|
|
322
|
+
},
|
|
323
|
+
children: Y ? r(B, "workspaceDetail.archiving", "Archiving...") : r(B, "workspaceDetail.archive", "Archive")
|
|
324
|
+
})] })
|
|
325
|
+
] })
|
|
288
326
|
})
|
|
289
327
|
]
|
|
290
328
|
});
|
|
291
329
|
}
|
|
292
330
|
//#endregion
|
|
293
|
-
export {
|
|
331
|
+
export { z as WorkspaceDetailPage };
|
|
294
332
|
|
|
295
333
|
//# 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';\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 GlassCard,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n CTAOverflowMenu,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\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-text-secondary\">\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 <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tWithFallback(t, 'workspaceDetail.notFound', 'Workspace not found')}\n description={tWithFallback(\n t,\n 'workspaceDetail.notFoundDescription',\n \"This workspace doesn't exist or you don't have permission to view it.\"\n )}\n />\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 <CTAOverflowMenu\n primary={\n canUpdateWorkspace\n ? {\n label: tWithFallback(t, 'workspaceDetail.settings', 'Settings'),\n icon: <Settings size={18} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`)),\n }\n : canInviteMember\n ? {\n label: tWithFallback(t, 'workspaceDetail.inviteMembers', 'Invite Member'),\n icon: <UserPlus size={18} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n }\n : undefined\n }\n actions={[\n ...(canUpdateWorkspace && canInviteMember\n ? [\n {\n label: tWithFallback(t, 'workspaceDetail.inviteMembers', 'Invite Member'),\n icon: <UserPlus size={16} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n },\n ]\n : []),\n ]}\n />\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'workspaceDetail.purpose',\n 'This is the home for a single workspace — the hub that ties together its projects, the people who collaborate in it, and everything that happens inside. Use the cards below to jump into work, manage who has access, or review recent activity.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"workspaces-workspace-detail\"\n steps={[\n {\n id: 'open-projects',\n label: tWithFallback(t, 'workspaceDetail.stepProjects', 'Open the projects board'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepProjectsDesc',\n 'Projects are where the actual work lives — start or pick one up.'\n ),\n icon: <FolderKanban size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`)),\n },\n ...(canInviteMember\n ? [\n {\n id: 'invite-member',\n label: tWithFallback(t, 'workspaceDetail.stepInvite', 'Invite a teammate'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepInviteDesc',\n 'Bring people into this workspace so they can collaborate.'\n ),\n icon: <UserPlus size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n },\n ]\n : []),\n {\n id: 'review-members',\n label: tWithFallback(t, 'workspaceDetail.stepMembers', 'Review who has access'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepMembersDesc',\n 'Check the current members and their roles.'\n ),\n icon: <Users size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`)),\n },\n ...(canUpdateWorkspace\n ? [\n {\n id: 'configure-settings',\n label: tWithFallback(\n t,\n 'workspaceDetail.stepSettings',\n 'Configure workspace settings'\n ),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepSettingsDesc',\n 'Set the name, domain and contact details for this workspace.'\n ),\n icon: <Settings size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`)),\n },\n ]\n : []),\n ]}\n />\n\n {/* Main + detail rail */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6\">\n {/* Main: stat metrics */}\n <div className=\"lg:col-span-2 space-y-4 sm:space-y-6\">\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <GlassCard\n treatment=\"metric\"\n glow\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <FolderKanban size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">\n {projects?.total ?? workspace.projectCount ?? 0}\n </p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </GlassCard>\n\n <GlassCard\n treatment=\"metric\"\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <Users size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">\n {members?.total ?? workspace.memberCount ?? 0}\n </p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </GlassCard>\n\n <GlassCard\n treatment=\"metric\"\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <Activity size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </GlassCard>\n </div>\n </div>\n\n {/* Detail rail: workspace info */}\n <aside className=\"lg:sticky lg:top-6 lg:self-start\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\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-text-muted\">\n {tWithFallback(t, 'workspaceDetail.id', 'ID:')}\n </span>\n <span className=\"font-mono text-xs break-all\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span className=\"break-all\">{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-text-muted\">\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 break-all\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </GlassCard>\n </aside>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../src/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useParams, useNavigate } from 'react-router';\nimport {\n Settings,\n ArrowLeft,\n FolderKanban,\n Users,\n Activity,\n ChevronRight,\n UserPlus,\n Archive,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n GlassCard,\n CardHeader,\n CardTitle,\n CardContent,\n Badge,\n Skeleton,\n CTAOverflowMenu,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\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';\nimport { useArchiveWorkspace } from '../hooks/useWorkspaceMutations';\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 [showArchiveDialog, setShowArchiveDialog] = useState(false);\n const [archiveError, setArchiveError] = useState<string | null>(null);\n const { mutate: archiveWorkspace, isPending: isArchiving } = useArchiveWorkspace();\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 canArchiveWorkspace,\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-text-secondary\">\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 <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tWithFallback(t, 'workspaceDetail.notFound', 'Workspace not found')}\n description={tWithFallback(\n t,\n 'workspaceDetail.notFoundDescription',\n \"This workspace doesn't exist or you don't have permission to view it.\"\n )}\n />\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 const handleArchive = () => {\n if (!workspaceId) return;\n setArchiveError(null);\n archiveWorkspace(workspaceId, {\n onSuccess: () => {\n setShowArchiveDialog(false);\n navigate(withCurrentSearch(`${basePath}/list`));\n },\n onError: () => {\n setArchiveError(\n tWithFallback(\n t,\n 'workspaceDetail.archiveFailed',\n 'The workspace could not be archived. Please try again.'\n )\n );\n },\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 <CTAOverflowMenu\n primary={\n canUpdateWorkspace\n ? {\n label: tWithFallback(t, 'workspaceDetail.settings', 'Settings'),\n icon: <Settings size={18} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`)),\n }\n : canInviteMember\n ? {\n label: tWithFallback(t, 'workspaceDetail.inviteMembers', 'Invite Member'),\n icon: <UserPlus size={18} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n }\n : undefined\n }\n actions={[\n ...(canUpdateWorkspace && canInviteMember\n ? [\n {\n label: tWithFallback(t, 'workspaceDetail.inviteMembers', 'Invite Member'),\n icon: <UserPlus size={16} />,\n onSelect: () =>\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n },\n ]\n : []),\n ...(canArchiveWorkspace\n ? [\n {\n label: tWithFallback(\n t,\n 'workspaceDetail.archiveWorkspace',\n 'Archive Workspace'\n ),\n icon: <Archive size={16} />,\n onSelect: () => setShowArchiveDialog(true),\n },\n ]\n : []),\n ]}\n />\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'workspaceDetail.purpose',\n 'This is the home for a single workspace — the hub that ties together its projects, the people who collaborate in it, and everything that happens inside. Use the cards below to jump into work, manage who has access, or review recent activity.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"workspaces-workspace-detail\"\n steps={[\n {\n id: 'open-projects',\n label: tWithFallback(t, 'workspaceDetail.stepProjects', 'Open the projects board'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepProjectsDesc',\n 'Projects are where the actual work lives — start or pick one up.'\n ),\n icon: <FolderKanban size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects`)),\n },\n ...(canInviteMember\n ? [\n {\n id: 'invite-member',\n label: tWithFallback(t, 'workspaceDetail.stepInvite', 'Invite a teammate'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepInviteDesc',\n 'Bring people into this workspace so they can collaborate.'\n ),\n icon: <UserPlus size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/invite`)),\n },\n ]\n : []),\n {\n id: 'review-members',\n label: tWithFallback(t, 'workspaceDetail.stepMembers', 'Review who has access'),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepMembersDesc',\n 'Check the current members and their roles.'\n ),\n icon: <Users size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/members`)),\n },\n ...(canUpdateWorkspace\n ? [\n {\n id: 'configure-settings',\n label: tWithFallback(\n t,\n 'workspaceDetail.stepSettings',\n 'Configure workspace settings'\n ),\n description: tWithFallback(\n t,\n 'workspaceDetail.stepSettingsDesc',\n 'Set the name, domain and contact details for this workspace.'\n ),\n icon: <Settings size={16} />,\n onClick: () => navigate(withCurrentSearch(`${basePath}/${workspaceId}/settings`)),\n },\n ]\n : []),\n ]}\n />\n\n {/* Main + detail rail */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6\">\n {/* Main: stat metrics */}\n <div className=\"lg:col-span-2 space-y-4 sm:space-y-6\">\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n <GlassCard\n treatment=\"metric\"\n glow\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <FolderKanban size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.projects', 'Projects')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">\n {projects?.total ?? workspace.projectCount ?? 0}\n </p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.projectsDesc', 'Projects in this workspace')}\n </p>\n </CardContent>\n </GlassCard>\n\n <GlassCard\n treatment=\"metric\"\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <Users size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.members', 'Members')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">\n {members?.total ?? workspace.memberCount ?? 0}\n </p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.membersDesc', 'Workspace members')}\n </p>\n </CardContent>\n </GlassCard>\n\n <GlassCard\n treatment=\"metric\"\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\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 text-text-secondary text-sm font-medium\">\n <Activity size={18} className=\"text-text-muted\" />\n {tWithFallback(t, 'workspaceDetail.activity', 'Activity')}\n </CardTitle>\n <ChevronRight size={18} className=\"text-text-muted\" />\n </CardHeader>\n <CardContent>\n <p className=\"text-3xl font-bold tabular-nums\">{activities?.length ?? 0}</p>\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.activityDesc', 'Recent activity items')}\n </p>\n </CardContent>\n </GlassCard>\n </div>\n </div>\n\n {/* Detail rail: workspace info */}\n <aside className=\"lg:sticky lg:top-6 lg:self-start\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\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-text-muted\">\n {tWithFallback(t, 'workspaceDetail.id', 'ID:')}\n </span>\n <span className=\"font-mono text-xs break-all\">{workspace.id}</span>\n\n {workspace.domain && (\n <>\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.domain', 'Domain:')}\n </span>\n <span>{workspace.domain}</span>\n </>\n )}\n\n {workspace.contactEmail && (\n <>\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.contactEmail', 'Contact Email:')}\n </span>\n <span className=\"break-all\">{workspace.contactEmail}</span>\n </>\n )}\n\n {workspace.website && (\n <>\n <span className=\"text-text-muted\">\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 break-all\"\n >\n {workspace.website}\n </a>\n </>\n )}\n\n <span className=\"text-text-muted\">\n {tWithFallback(t, 'workspaceDetail.created', 'Created:')}\n </span>\n <span>{new Date(workspace.createdAt).toLocaleDateString()}</span>\n </div>\n </CardContent>\n </GlassCard>\n </aside>\n </div>\n\n <AlertDialog\n open={showArchiveDialog}\n onOpenChange={(open) => {\n setShowArchiveDialog(open);\n if (!open) setArchiveError(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {tWithFallback(t, 'workspaceDetail.archiveTitle', 'Archive workspace?')}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {tWithFallback(\n t,\n 'workspaceDetail.archiveDescription',\n 'This removes the workspace from active work while preserving its data.'\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n {archiveError && <p className=\"text-sm text-status-error-text\">{archiveError}</p>}\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isArchiving}>\n {tWithFallback(t, 'common.cancel', 'Cancel')}\n </AlertDialogCancel>\n <AlertDialogAction\n disabled={isArchiving}\n onClick={(event) => {\n event.preventDefault();\n handleArchive();\n }}\n >\n {isArchiving\n ? tWithFallback(t, 'workspaceDetail.archiving', 'Archiving...')\n : tWithFallback(t, 'workspaceDetail.archive', 'Archive')}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -547,7 +547,7 @@ function k() {
|
|
|
547
547
|
}), /* @__PURE__ */ m(Oe, {
|
|
548
548
|
id: "workspace-invite-email",
|
|
549
549
|
type: "email",
|
|
550
|
-
placeholder: "member@example.com",
|
|
550
|
+
placeholder: r(x, "workspaceInvite.emailPlaceholder", "member@example.com"),
|
|
551
551
|
value: P,
|
|
552
552
|
onChange: (e) => ot(e.target.value),
|
|
553
553
|
disabled: q
|
|
@@ -653,7 +653,7 @@ function k() {
|
|
|
653
653
|
t && Mt(t), e.target.value = "";
|
|
654
654
|
},
|
|
655
655
|
className: "hidden",
|
|
656
|
-
"aria-label": "Choose CSV file"
|
|
656
|
+
"aria-label": r(x, "workspaceInvite.chooseCsvFileAriaLabel", "Choose CSV file")
|
|
657
657
|
}),
|
|
658
658
|
/* @__PURE__ */ m(_, {
|
|
659
659
|
type: "button",
|