@burdenoff/microfe-workspaces 2026.625.4 → 2026.626.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useMemberMutations.js +6 -6
- package/dist/hooks/useMemberMutations.js.map +1 -1
- package/dist/pages/ActivityListPage.js +94 -90
- package/dist/pages/ActivityListPage.js.map +1 -1
- package/dist/pages/CreateWorkspacePage.js +68 -63
- package/dist/pages/CreateWorkspacePage.js.map +1 -1
- package/dist/pages/InviteAcceptancePage.js +101 -96
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +185 -184
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +70 -68
- package/dist/pages/PendingInvitesPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +119 -78
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +105 -104
- package/dist/pages/ProjectMembersPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +158 -157
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +236 -198
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceInvitePage.js +341 -300
- package/dist/pages/WorkspaceInvitePage.js.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.js +87 -85
- package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +122 -121
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +55 -51
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/widgets/GroupsWidget.js +16 -17
- package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TagCloudWidget.js +18 -19
- package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +10 -11
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,30 +8,30 @@ import { useUpdateWorkspace as s } from "../hooks/useWorkspaceMutations.js";
|
|
|
8
8
|
import { useMemo as c } from "react";
|
|
9
9
|
import { ArrowLeft as l, Save as u } from "lucide-react";
|
|
10
10
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
11
|
-
import { Button as p, CardContent as m, CardHeader as h, CardTitle as g, GlassCard as _, OptionalFields as v } from "@burdenoff/fe-libs/ui";
|
|
12
|
-
import { useNavigate as
|
|
13
|
-
import { AccessDenied as
|
|
14
|
-
import { useI18n as
|
|
15
|
-
import { Form as
|
|
16
|
-
import { TagsWidget as
|
|
11
|
+
import { Button as p, CardContent as m, CardHeader as h, CardTitle as g, GlassCard as _, OptionalFields as v, PagePurpose as y } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
import { useNavigate as b, useParams as x } from "react-router-dom";
|
|
13
|
+
import { AccessDenied as S, PermissionGate as C } from "@burdenoff/fe-libs/shared/components";
|
|
14
|
+
import { useI18n as w } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
15
|
+
import { Form as T, FormControl as E, FormField as D, FormItem as O, FormLabel as k, FormMessage as A, Input as j, z as M } from "@burdenoff/fe-libs/form";
|
|
16
|
+
import { TagsWidget as N } from "@burdenoff/fe-libs/tag";
|
|
17
17
|
//#region src/pages/WorkspaceSettingsPage.tsx
|
|
18
|
-
var
|
|
19
|
-
name:
|
|
20
|
-
contactEmail:
|
|
21
|
-
domain:
|
|
22
|
-
website:
|
|
18
|
+
var P = M.object({
|
|
19
|
+
name: M.string().min(2).max(100),
|
|
20
|
+
contactEmail: M.string().email().optional().or(M.literal("")),
|
|
21
|
+
domain: M.string().optional(),
|
|
22
|
+
website: M.string().url().optional().or(M.literal(""))
|
|
23
23
|
});
|
|
24
|
-
function
|
|
25
|
-
let { t:
|
|
24
|
+
function F() {
|
|
25
|
+
let { t: M } = w(), { workspaceId: F } = x();
|
|
26
26
|
o("workspaces.settings", {
|
|
27
|
-
workspaceId:
|
|
27
|
+
workspaceId: F,
|
|
28
28
|
requireParams: !0
|
|
29
29
|
});
|
|
30
|
-
let
|
|
31
|
-
variables: { input: { workspaceId:
|
|
32
|
-
skip: !
|
|
30
|
+
let I = b(), { basePath: L = "/" } = e(), { data: R, isLoading: z } = r(F || ""), { mutate: B, isPending: V } = s(), { data: H, refetch: U } = t({
|
|
31
|
+
variables: { input: { workspaceId: F ?? "" } },
|
|
32
|
+
skip: !F,
|
|
33
33
|
fetchPolicy: "cache-and-network"
|
|
34
|
-
}), [
|
|
34
|
+
}), [W, { loading: G }] = n(), K = c(() => (H?.getWorkspaceTags ?? []).flatMap((e) => e.tag ? [{
|
|
35
35
|
id: e.tagId,
|
|
36
36
|
key: e.tag.key,
|
|
37
37
|
label: e.tag.label,
|
|
@@ -42,32 +42,32 @@ function P() {
|
|
|
42
42
|
color: e.tag.color ?? null,
|
|
43
43
|
icon: e.tag.icon ?? null,
|
|
44
44
|
description: e.tag.description ?? null
|
|
45
|
-
}] : []), [
|
|
46
|
-
|
|
47
|
-
workspaceId:
|
|
45
|
+
}] : []), [H?.getWorkspaceTags]), q = async (e) => {
|
|
46
|
+
F && (await W({ variables: { input: {
|
|
47
|
+
workspaceId: F,
|
|
48
48
|
tagIds: e.map((e) => e.id)
|
|
49
|
-
} } }), await
|
|
49
|
+
} } }), await U());
|
|
50
50
|
};
|
|
51
|
-
return
|
|
51
|
+
return z ? /* @__PURE__ */ d("div", {
|
|
52
52
|
className: "p-6",
|
|
53
|
-
children: a(
|
|
54
|
-
}) :
|
|
53
|
+
children: a(M, "workspaceSettings.loading", "Loading...")
|
|
54
|
+
}) : R ? /* @__PURE__ */ d(C, {
|
|
55
55
|
permission: i.WORKSPACE_UPDATE,
|
|
56
56
|
fallback: /* @__PURE__ */ f("div", {
|
|
57
57
|
className: "p-6",
|
|
58
58
|
children: [/* @__PURE__ */ f(p, {
|
|
59
59
|
variant: "ghost",
|
|
60
|
-
onClick: () =>
|
|
60
|
+
onClick: () => I(`${L}/${F}`),
|
|
61
61
|
className: "gap-2 mb-6 -ml-2",
|
|
62
|
-
children: [/* @__PURE__ */ d(l, { size: 20 }), a(
|
|
63
|
-
}), /* @__PURE__ */ d(
|
|
62
|
+
children: [/* @__PURE__ */ d(l, { size: 20 }), a(M, "workspaceSettings.backToWorkspace", "Back to Workspace")]
|
|
63
|
+
}), /* @__PURE__ */ d(S, {
|
|
64
64
|
variant: "card",
|
|
65
|
-
title: a(
|
|
66
|
-
description: a(
|
|
67
|
-
details: a(
|
|
65
|
+
title: a(M, "workspaceSettings.permissionRequired", "Permission Required"),
|
|
66
|
+
description: a(M, "workspaceSettings.permissionRequiredDesc", "You don't have permission to edit workspace settings."),
|
|
67
|
+
details: a(M, "workspaceSettings.permissionRequiredDetails", "Required: workspace:update"),
|
|
68
68
|
primaryAction: {
|
|
69
|
-
label: a(
|
|
70
|
-
onClick: () =>
|
|
69
|
+
label: a(M, "workspaceSettings.goBack", "Go Back"),
|
|
70
|
+
onClick: () => I(`${L}/${F}`)
|
|
71
71
|
}
|
|
72
72
|
})]
|
|
73
73
|
}),
|
|
@@ -77,27 +77,29 @@ function P() {
|
|
|
77
77
|
/* @__PURE__ */ f("div", { children: [
|
|
78
78
|
/* @__PURE__ */ f(p, {
|
|
79
79
|
variant: "ghost",
|
|
80
|
-
onClick: () =>
|
|
80
|
+
onClick: () => I(`${L}/${F}`),
|
|
81
81
|
className: "gap-2 mb-2 -ml-2",
|
|
82
|
-
children: [/* @__PURE__ */ d(l, { size: 20 }), a(
|
|
82
|
+
children: [/* @__PURE__ */ d(l, { size: 20 }), a(M, "workspaceSettings.backToWorkspace", "Back to Workspace")]
|
|
83
83
|
}),
|
|
84
84
|
/* @__PURE__ */ d("h1", {
|
|
85
85
|
className: "text-2xl sm:text-3xl font-bold",
|
|
86
|
-
children: a(
|
|
86
|
+
children: a(M, "workspaceSettings.title", "Workspace Settings")
|
|
87
87
|
}),
|
|
88
88
|
/* @__PURE__ */ d("p", {
|
|
89
89
|
className: "text-text-secondary",
|
|
90
|
-
children: a(
|
|
90
|
+
children: a(M, "workspaceSettings.subtitle", "Manage workspace configuration")
|
|
91
91
|
})
|
|
92
92
|
] }),
|
|
93
|
+
/* @__PURE__ */ d(y, { children: a(M, "workspaceSettings.purpose", "This is where you control how the workspace presents itself and how it's organised — its display name, a contact email, an optional custom domain and website, and the tags used to classify and filter it. Update these to keep the workspace's identity accurate as your team grows.") }),
|
|
93
94
|
/* @__PURE__ */ f(_, {
|
|
94
|
-
treatment: "
|
|
95
|
+
treatment: "glass",
|
|
96
|
+
glow: !0,
|
|
95
97
|
className: "border-border-seam",
|
|
96
|
-
children: [/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(g, { children: a(
|
|
97
|
-
schema:
|
|
98
|
+
children: [/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(g, { children: a(M, "workspaceSettings.generalSettings", "General Settings") }) }), /* @__PURE__ */ d(m, { children: /* @__PURE__ */ d(T, {
|
|
99
|
+
schema: P,
|
|
98
100
|
onSubmit: (e) => {
|
|
99
|
-
|
|
100
|
-
id:
|
|
101
|
+
F && B({
|
|
102
|
+
id: F,
|
|
101
103
|
input: {
|
|
102
104
|
...e,
|
|
103
105
|
contactEmail: e.contactEmail || void 0,
|
|
@@ -105,60 +107,60 @@ function P() {
|
|
|
105
107
|
website: e.website || void 0
|
|
106
108
|
}
|
|
107
109
|
}, { onSuccess: () => {
|
|
108
|
-
|
|
110
|
+
I(`${L}/${F}`);
|
|
109
111
|
} });
|
|
110
112
|
},
|
|
111
113
|
formOptions: { defaultValues: {
|
|
112
|
-
name:
|
|
113
|
-
contactEmail:
|
|
114
|
-
domain:
|
|
115
|
-
website:
|
|
114
|
+
name: R?.name || "",
|
|
115
|
+
contactEmail: R?.contactEmail || "",
|
|
116
|
+
domain: R?.domain || "",
|
|
117
|
+
website: R?.website || ""
|
|
116
118
|
} },
|
|
117
119
|
children: (e) => /* @__PURE__ */ f("div", {
|
|
118
120
|
className: "space-y-4",
|
|
119
121
|
children: [
|
|
120
|
-
/* @__PURE__ */ d(
|
|
122
|
+
/* @__PURE__ */ d(D, {
|
|
121
123
|
control: e.control,
|
|
122
124
|
name: "name",
|
|
123
|
-
render: ({ field: e }) => /* @__PURE__ */ f(
|
|
124
|
-
/* @__PURE__ */ d(
|
|
125
|
-
/* @__PURE__ */ d(
|
|
126
|
-
/* @__PURE__ */ d(
|
|
125
|
+
render: ({ field: e }) => /* @__PURE__ */ f(O, { children: [
|
|
126
|
+
/* @__PURE__ */ d(k, { children: a(M, "workspaceSettings.workspaceName", "Workspace Name") }),
|
|
127
|
+
/* @__PURE__ */ d(E, { children: /* @__PURE__ */ d(j, { ...e }) }),
|
|
128
|
+
/* @__PURE__ */ d(A, {})
|
|
127
129
|
] })
|
|
128
130
|
}),
|
|
129
|
-
/* @__PURE__ */ d(
|
|
131
|
+
/* @__PURE__ */ d(D, {
|
|
130
132
|
control: e.control,
|
|
131
133
|
name: "contactEmail",
|
|
132
|
-
render: ({ field: e }) => /* @__PURE__ */ f(
|
|
133
|
-
/* @__PURE__ */ d(
|
|
134
|
-
/* @__PURE__ */ d(
|
|
134
|
+
render: ({ field: e }) => /* @__PURE__ */ f(O, { children: [
|
|
135
|
+
/* @__PURE__ */ d(k, { children: a(M, "workspaceSettings.contactEmail", "Contact Email") }),
|
|
136
|
+
/* @__PURE__ */ d(E, { children: /* @__PURE__ */ d(j, {
|
|
135
137
|
type: "email",
|
|
136
138
|
...e
|
|
137
139
|
}) }),
|
|
138
|
-
/* @__PURE__ */ d(
|
|
140
|
+
/* @__PURE__ */ d(A, {})
|
|
139
141
|
] })
|
|
140
142
|
}),
|
|
141
143
|
/* @__PURE__ */ f(v, {
|
|
142
|
-
title: a(
|
|
143
|
-
description: a(
|
|
144
|
-
children: [/* @__PURE__ */ d(
|
|
144
|
+
title: a(M, "workspaceSettings.advancedTitle", "Advanced settings"),
|
|
145
|
+
description: a(M, "workspaceSettings.advancedDescription", "Custom domain + website. Most workspaces leave these blank."),
|
|
146
|
+
children: [/* @__PURE__ */ d(D, {
|
|
145
147
|
control: e.control,
|
|
146
148
|
name: "domain",
|
|
147
|
-
render: ({ field: e }) => /* @__PURE__ */ f(
|
|
148
|
-
/* @__PURE__ */ d(
|
|
149
|
-
/* @__PURE__ */ d(
|
|
150
|
-
/* @__PURE__ */ d(
|
|
149
|
+
render: ({ field: e }) => /* @__PURE__ */ f(O, { children: [
|
|
150
|
+
/* @__PURE__ */ d(k, { children: a(M, "workspaceSettings.domain", "Domain") }),
|
|
151
|
+
/* @__PURE__ */ d(E, { children: /* @__PURE__ */ d(j, { ...e }) }),
|
|
152
|
+
/* @__PURE__ */ d(A, {})
|
|
151
153
|
] })
|
|
152
|
-
}), /* @__PURE__ */ d(
|
|
154
|
+
}), /* @__PURE__ */ d(D, {
|
|
153
155
|
control: e.control,
|
|
154
156
|
name: "website",
|
|
155
|
-
render: ({ field: e }) => /* @__PURE__ */ f(
|
|
156
|
-
/* @__PURE__ */ d(
|
|
157
|
-
/* @__PURE__ */ d(
|
|
157
|
+
render: ({ field: e }) => /* @__PURE__ */ f(O, { children: [
|
|
158
|
+
/* @__PURE__ */ d(k, { children: a(M, "workspaceSettings.website", "Website") }),
|
|
159
|
+
/* @__PURE__ */ d(E, { children: /* @__PURE__ */ d(j, {
|
|
158
160
|
type: "url",
|
|
159
161
|
...e
|
|
160
162
|
}) }),
|
|
161
|
-
/* @__PURE__ */ d(
|
|
163
|
+
/* @__PURE__ */ d(A, {})
|
|
162
164
|
] })
|
|
163
165
|
})]
|
|
164
166
|
}),
|
|
@@ -166,37 +168,37 @@ function P() {
|
|
|
166
168
|
className: "flex gap-2",
|
|
167
169
|
children: [/* @__PURE__ */ f(p, {
|
|
168
170
|
type: "submit",
|
|
169
|
-
disabled:
|
|
171
|
+
disabled: V,
|
|
170
172
|
className: "gap-2",
|
|
171
|
-
children: [/* @__PURE__ */ d(u, { size: 20 }),
|
|
173
|
+
children: [/* @__PURE__ */ d(u, { size: 20 }), V ? a(M, "workspaceSettings.saving", "Saving...") : a(M, "workspaceSettings.saveChanges", "Save Changes")]
|
|
172
174
|
}), /* @__PURE__ */ d(p, {
|
|
173
175
|
type: "button",
|
|
174
176
|
variant: "outline",
|
|
175
|
-
onClick: () =>
|
|
176
|
-
children: a(
|
|
177
|
+
onClick: () => I(`${L}/${F}`),
|
|
178
|
+
children: a(M, "workspaceSettings.cancel", "Cancel")
|
|
177
179
|
})]
|
|
178
180
|
})
|
|
179
181
|
]
|
|
180
182
|
})
|
|
181
183
|
}) })]
|
|
182
184
|
}),
|
|
183
|
-
|
|
185
|
+
F && /* @__PURE__ */ f(_, {
|
|
184
186
|
treatment: "plain",
|
|
185
187
|
className: "border-border-seam",
|
|
186
|
-
children: [/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(g, { children: a(
|
|
188
|
+
children: [/* @__PURE__ */ d(h, { children: /* @__PURE__ */ d(g, { children: a(M, "workspaceSettings.tags", "Tags") }) }), /* @__PURE__ */ f(m, {
|
|
187
189
|
className: "space-y-3",
|
|
188
190
|
children: [/* @__PURE__ */ d("p", {
|
|
189
191
|
className: "text-sm text-text-muted",
|
|
190
|
-
children: a(
|
|
191
|
-
}), /* @__PURE__ */ d(
|
|
192
|
+
children: a(M, "workspaceSettings.tagsDescription", "Use universal tags to classify and filter this workspace.")
|
|
193
|
+
}), /* @__PURE__ */ d(N, {
|
|
192
194
|
entityType: "Workspace",
|
|
193
|
-
entityId:
|
|
194
|
-
workspaceId:
|
|
195
|
-
tags:
|
|
196
|
-
onAdd: (e) =>
|
|
197
|
-
onRemove: (e) => K
|
|
195
|
+
entityId: F,
|
|
196
|
+
workspaceId: F,
|
|
197
|
+
tags: K,
|
|
198
|
+
onAdd: (e) => q([...K, e]),
|
|
199
|
+
onRemove: (e) => q(K.filter((t) => t.id !== e)),
|
|
198
200
|
syncGraphNotifications: !1,
|
|
199
|
-
className:
|
|
201
|
+
className: G ? "pointer-events-none opacity-75" : void 0
|
|
200
202
|
})]
|
|
201
203
|
})]
|
|
202
204
|
})
|
|
@@ -204,10 +206,10 @@ function P() {
|
|
|
204
206
|
})
|
|
205
207
|
}) : /* @__PURE__ */ d("div", {
|
|
206
208
|
className: "p-6",
|
|
207
|
-
children: a(
|
|
209
|
+
children: a(M, "workspaceSettings.notFound", "Workspace not found")
|
|
208
210
|
});
|
|
209
211
|
}
|
|
210
212
|
//#endregion
|
|
211
|
-
export {
|
|
213
|
+
export { F as WorkspaceSettingsPage };
|
|
212
214
|
|
|
213
215
|
//# sourceMappingURL=WorkspaceSettingsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceSettingsPage.js","names":[],"sources":["../../src/pages/WorkspaceSettingsPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { ArrowLeft, Save } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { type TagItem, TagsWidget } from '@burdenoff/fe-libs/tag';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n GlassCard,\n CardHeader,\n CardTitle,\n CardContent,\n OptionalFields,\n} from '@burdenoff/fe-libs/ui';\nimport {\n useGetWorkspaceTagsQuery,\n useReplaceWorkspaceTagsMutation,\n type WorkspaceTagAssignmentFieldsFragment,\n} from '../generated/wspace-operations';\nimport {\n Form,\n FormField,\n FormItem,\n FormLabel,\n FormControl,\n FormMessage,\n Input,\n z,\n} from '@burdenoff/fe-libs/form';\nimport { PermissionGate, AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useUpdateWorkspace } from '../hooks/useWorkspaceMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nconst updateWorkspaceSchema = z.object({\n name: z.string().min(2).max(100),\n contactEmail: z.string().email().optional().or(z.literal('')),\n domain: z.string().optional(),\n website: z.string().url().optional().or(z.literal('')),\n});\n\ntype UpdateWorkspaceFormData = z.infer<typeof updateWorkspaceSchema>;\n\nexport function WorkspaceSettingsPage() {\n const { t } = useI18n();\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.settings', { workspaceId, requireParams: true });\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { data: workspace, isLoading } = useWorkspace(workspaceId || '');\n const { mutate: updateWorkspace, isPending } = useUpdateWorkspace();\n\n // Workspace tags (universal-tags assignments) — backend exposed via\n // wspace-workspace-svc workspace-tags.gql; this UI is the canonical\n // editor for them. Identical pattern to ProjectDetailPage.\n const { data: tagsData, refetch: refetchTags } = useGetWorkspaceTagsQuery({\n variables: { input: { workspaceId: workspaceId ?? '' } },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n const [replaceWorkspaceTags, { loading: tagsUpdating }] = useReplaceWorkspaceTagsMutation();\n // The widget keys tags by `id` for add/remove. We store the\n // assignment's tagId there so the round-trip back to\n // replaceWorkspaceTags has the right value to send. Display fields\n // come from the embedded `tag: UniversalTag` resolved by the\n // assignment — assignments without a hydrated tag (deleted or\n // unresolved) are dropped so the widget never renders empty badges.\n const widgetTags = useMemo<TagItem[]>(() => {\n const assignments = tagsData?.getWorkspaceTags ?? [];\n return assignments.flatMap((a: WorkspaceTagAssignmentFieldsFragment) => {\n if (!a.tag) return [];\n return [\n {\n id: a.tagId,\n key: a.tag.key,\n label: a.tag.label,\n value: a.tag.value ?? null,\n vocabularyId: a.tag.vocabularyId ?? null,\n parentId: a.tag.parentId ?? null,\n hierarchyPath: a.tag.hierarchyPath ?? null,\n color: a.tag.color ?? null,\n icon: a.tag.icon ?? null,\n description: a.tag.description ?? null,\n } satisfies TagItem,\n ];\n });\n }, [tagsData?.getWorkspaceTags]);\n\n const persistTags = async (next: TagItem[]) => {\n if (!workspaceId) return;\n await replaceWorkspaceTags({\n variables: {\n input: {\n workspaceId,\n tagIds: next.map((t) => t.id),\n },\n },\n });\n await refetchTags();\n };\n\n const handleAddTag = (tag: TagItem) => persistTags([...widgetTags, tag]);\n const handleRemoveTag = (tagId: string) => persistTags(widgetTags.filter((t) => t.id !== tagId));\n\n const handleSubmit = (data: UpdateWorkspaceFormData) => {\n if (!workspaceId) return;\n\n updateWorkspace(\n {\n id: workspaceId,\n input: {\n ...data,\n contactEmail: data.contactEmail || undefined,\n domain: data.domain || undefined,\n website: data.website || undefined,\n },\n },\n {\n onSuccess: () => {\n navigate(`${basePath}/${workspaceId}`);\n },\n }\n );\n };\n\n if (isLoading) {\n return <div className=\"p-6\">{tWithFallback(t, 'workspaceSettings.loading', 'Loading...')}</div>;\n }\n\n if (!workspace) {\n return (\n <div className=\"p-6\">\n {tWithFallback(t, 'workspaceSettings.notFound', 'Workspace not found')}\n </div>\n );\n }\n\n return (\n <PermissionGate\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_UPDATE}\n fallback={\n <div className=\"p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n className=\"gap-2 mb-6 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceSettings.backToWorkspace', 'Back to Workspace')}\n </Button>\n <AccessDenied\n variant=\"card\"\n title={tWithFallback(t, 'workspaceSettings.permissionRequired', 'Permission Required')}\n description={tWithFallback(\n t,\n 'workspaceSettings.permissionRequiredDesc',\n \"You don't have permission to edit workspace settings.\"\n )}\n details={tWithFallback(\n t,\n 'workspaceSettings.permissionRequiredDetails',\n 'Required: workspace:update'\n )}\n primaryAction={{\n label: tWithFallback(t, 'workspaceSettings.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/${workspaceId}`),\n }}\n />\n </div>\n }\n >\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceSettings.backToWorkspace', 'Back to Workspace')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'workspaceSettings.title', 'Workspace Settings')}\n </h1>\n <p className=\"text-text-secondary\">\n {tWithFallback(t, 'workspaceSettings.subtitle', 'Manage workspace configuration')}\n </p>\n </div>\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'workspaceSettings.generalSettings', 'General Settings')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <Form\n schema={updateWorkspaceSchema}\n onSubmit={handleSubmit}\n formOptions={{\n defaultValues: {\n name: workspace?.name || '',\n contactEmail: workspace?.contactEmail || '',\n domain: workspace?.domain || '',\n website: workspace?.website || '',\n },\n }}\n >\n {(form) => (\n <div className=\"space-y-4\">\n <FormField\n control={form.control}\n name=\"name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.workspaceName', 'Workspace Name')}\n </FormLabel>\n <FormControl>\n <Input {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name=\"contactEmail\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.contactEmail', 'Contact Email')}\n </FormLabel>\n <FormControl>\n <Input type=\"email\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <OptionalFields\n title={tWithFallback(t, 'workspaceSettings.advancedTitle', 'Advanced settings')}\n description={tWithFallback(\n t,\n 'workspaceSettings.advancedDescription',\n 'Custom domain + website. Most workspaces leave these blank.'\n )}\n >\n <FormField\n control={form.control}\n name=\"domain\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.domain', 'Domain')}\n </FormLabel>\n <FormControl>\n <Input {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name=\"website\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.website', 'Website')}\n </FormLabel>\n <FormControl>\n <Input type=\"url\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </OptionalFields>\n\n <div className=\"flex gap-2\">\n <Button type=\"submit\" disabled={isPending} className=\"gap-2\">\n <Save size={20} />\n {isPending\n ? tWithFallback(t, 'workspaceSettings.saving', 'Saving...')\n : tWithFallback(t, 'workspaceSettings.saveChanges', 'Save Changes')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n >\n {tWithFallback(t, 'workspaceSettings.cancel', 'Cancel')}\n </Button>\n </div>\n </div>\n )}\n </Form>\n </CardContent>\n </GlassCard>\n\n {workspaceId && (\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle>{tWithFallback(t, 'workspaceSettings.tags', 'Tags')}</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(\n t,\n 'workspaceSettings.tagsDescription',\n 'Use universal tags to classify and filter this workspace.'\n )}\n </p>\n <TagsWidget\n entityType=\"Workspace\"\n entityId={workspaceId}\n workspaceId={workspaceId}\n tags={widgetTags}\n onAdd={handleAddTag}\n onRemove={handleRemoveTag}\n syncGraphNotifications={false}\n className={tagsUpdating ? 'pointer-events-none opacity-75' : undefined}\n />\n </CardContent>\n </GlassCard>\n )}\n </div>\n </PermissionGate>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceSettingsPage.js","names":[],"sources":["../../src/pages/WorkspaceSettingsPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { ArrowLeft, Save } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { type TagItem, TagsWidget } from '@burdenoff/fe-libs/tag';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Button,\n GlassCard,\n CardHeader,\n CardTitle,\n CardContent,\n OptionalFields,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport {\n useGetWorkspaceTagsQuery,\n useReplaceWorkspaceTagsMutation,\n type WorkspaceTagAssignmentFieldsFragment,\n} from '../generated/wspace-operations';\nimport {\n Form,\n FormField,\n FormItem,\n FormLabel,\n FormControl,\n FormMessage,\n Input,\n z,\n} from '@burdenoff/fe-libs/form';\nimport { PermissionGate, AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useUpdateWorkspace } from '../hooks/useWorkspaceMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nconst updateWorkspaceSchema = z.object({\n name: z.string().min(2).max(100),\n contactEmail: z.string().email().optional().or(z.literal('')),\n domain: z.string().optional(),\n website: z.string().url().optional().or(z.literal('')),\n});\n\ntype UpdateWorkspaceFormData = z.infer<typeof updateWorkspaceSchema>;\n\nexport function WorkspaceSettingsPage() {\n const { t } = useI18n();\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.settings', { workspaceId, requireParams: true });\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { data: workspace, isLoading } = useWorkspace(workspaceId || '');\n const { mutate: updateWorkspace, isPending } = useUpdateWorkspace();\n\n // Workspace tags (universal-tags assignments) — backend exposed via\n // wspace-workspace-svc workspace-tags.gql; this UI is the canonical\n // editor for them. Identical pattern to ProjectDetailPage.\n const { data: tagsData, refetch: refetchTags } = useGetWorkspaceTagsQuery({\n variables: { input: { workspaceId: workspaceId ?? '' } },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n const [replaceWorkspaceTags, { loading: tagsUpdating }] = useReplaceWorkspaceTagsMutation();\n // The widget keys tags by `id` for add/remove. We store the\n // assignment's tagId there so the round-trip back to\n // replaceWorkspaceTags has the right value to send. Display fields\n // come from the embedded `tag: UniversalTag` resolved by the\n // assignment — assignments without a hydrated tag (deleted or\n // unresolved) are dropped so the widget never renders empty badges.\n const widgetTags = useMemo<TagItem[]>(() => {\n const assignments = tagsData?.getWorkspaceTags ?? [];\n return assignments.flatMap((a: WorkspaceTagAssignmentFieldsFragment) => {\n if (!a.tag) return [];\n return [\n {\n id: a.tagId,\n key: a.tag.key,\n label: a.tag.label,\n value: a.tag.value ?? null,\n vocabularyId: a.tag.vocabularyId ?? null,\n parentId: a.tag.parentId ?? null,\n hierarchyPath: a.tag.hierarchyPath ?? null,\n color: a.tag.color ?? null,\n icon: a.tag.icon ?? null,\n description: a.tag.description ?? null,\n } satisfies TagItem,\n ];\n });\n }, [tagsData?.getWorkspaceTags]);\n\n const persistTags = async (next: TagItem[]) => {\n if (!workspaceId) return;\n await replaceWorkspaceTags({\n variables: {\n input: {\n workspaceId,\n tagIds: next.map((t) => t.id),\n },\n },\n });\n await refetchTags();\n };\n\n const handleAddTag = (tag: TagItem) => persistTags([...widgetTags, tag]);\n const handleRemoveTag = (tagId: string) => persistTags(widgetTags.filter((t) => t.id !== tagId));\n\n const handleSubmit = (data: UpdateWorkspaceFormData) => {\n if (!workspaceId) return;\n\n updateWorkspace(\n {\n id: workspaceId,\n input: {\n ...data,\n contactEmail: data.contactEmail || undefined,\n domain: data.domain || undefined,\n website: data.website || undefined,\n },\n },\n {\n onSuccess: () => {\n navigate(`${basePath}/${workspaceId}`);\n },\n }\n );\n };\n\n if (isLoading) {\n return <div className=\"p-6\">{tWithFallback(t, 'workspaceSettings.loading', 'Loading...')}</div>;\n }\n\n if (!workspace) {\n return (\n <div className=\"p-6\">\n {tWithFallback(t, 'workspaceSettings.notFound', 'Workspace not found')}\n </div>\n );\n }\n\n return (\n <PermissionGate\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_UPDATE}\n fallback={\n <div className=\"p-6\">\n <Button\n variant=\"ghost\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n className=\"gap-2 mb-6 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceSettings.backToWorkspace', 'Back to Workspace')}\n </Button>\n <AccessDenied\n variant=\"card\"\n title={tWithFallback(t, 'workspaceSettings.permissionRequired', 'Permission Required')}\n description={tWithFallback(\n t,\n 'workspaceSettings.permissionRequiredDesc',\n \"You don't have permission to edit workspace settings.\"\n )}\n details={tWithFallback(\n t,\n 'workspaceSettings.permissionRequiredDetails',\n 'Required: workspace:update'\n )}\n primaryAction={{\n label: tWithFallback(t, 'workspaceSettings.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/${workspaceId}`),\n }}\n />\n </div>\n }\n >\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div>\n <Button\n variant=\"ghost\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n className=\"gap-2 mb-2 -ml-2\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'workspaceSettings.backToWorkspace', 'Back to Workspace')}\n </Button>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'workspaceSettings.title', 'Workspace Settings')}\n </h1>\n <p className=\"text-text-secondary\">\n {tWithFallback(t, 'workspaceSettings.subtitle', 'Manage workspace configuration')}\n </p>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'workspaceSettings.purpose',\n \"This is where you control how the workspace presents itself and how it's organised — its display name, a contact email, an optional custom domain and website, and the tags used to classify and filter it. Update these to keep the workspace's identity accurate as your team grows.\"\n )}\n </PagePurpose>\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'workspaceSettings.generalSettings', 'General Settings')}\n </CardTitle>\n </CardHeader>\n <CardContent>\n <Form\n schema={updateWorkspaceSchema}\n onSubmit={handleSubmit}\n formOptions={{\n defaultValues: {\n name: workspace?.name || '',\n contactEmail: workspace?.contactEmail || '',\n domain: workspace?.domain || '',\n website: workspace?.website || '',\n },\n }}\n >\n {(form) => (\n <div className=\"space-y-4\">\n <FormField\n control={form.control}\n name=\"name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.workspaceName', 'Workspace Name')}\n </FormLabel>\n <FormControl>\n <Input {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name=\"contactEmail\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.contactEmail', 'Contact Email')}\n </FormLabel>\n <FormControl>\n <Input type=\"email\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <OptionalFields\n title={tWithFallback(t, 'workspaceSettings.advancedTitle', 'Advanced settings')}\n description={tWithFallback(\n t,\n 'workspaceSettings.advancedDescription',\n 'Custom domain + website. Most workspaces leave these blank.'\n )}\n >\n <FormField\n control={form.control}\n name=\"domain\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.domain', 'Domain')}\n </FormLabel>\n <FormControl>\n <Input {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={form.control}\n name=\"website\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>\n {tWithFallback(t, 'workspaceSettings.website', 'Website')}\n </FormLabel>\n <FormControl>\n <Input type=\"url\" {...field} />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </OptionalFields>\n\n <div className=\"flex gap-2\">\n <Button type=\"submit\" disabled={isPending} className=\"gap-2\">\n <Save size={20} />\n {isPending\n ? tWithFallback(t, 'workspaceSettings.saving', 'Saving...')\n : tWithFallback(t, 'workspaceSettings.saveChanges', 'Save Changes')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`${basePath}/${workspaceId}`)}\n >\n {tWithFallback(t, 'workspaceSettings.cancel', 'Cancel')}\n </Button>\n </div>\n </div>\n )}\n </Form>\n </CardContent>\n </GlassCard>\n\n {workspaceId && (\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle>{tWithFallback(t, 'workspaceSettings.tags', 'Tags')}</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <p className=\"text-sm text-text-muted\">\n {tWithFallback(\n t,\n 'workspaceSettings.tagsDescription',\n 'Use universal tags to classify and filter this workspace.'\n )}\n </p>\n <TagsWidget\n entityType=\"Workspace\"\n entityId={workspaceId}\n workspaceId={workspaceId}\n tags={widgetTags}\n onAdd={handleAddTag}\n onRemove={handleRemoveTag}\n syncGraphNotifications={false}\n className={tagsUpdating ? 'pointer-events-none opacity-75' : undefined}\n />\n </CardContent>\n </GlassCard>\n )}\n </div>\n </PermissionGate>\n );\n}\n"],"mappings":"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"}
|