@strapi-community/plugin-better-auth-dashboard 1.0.0-beta.1 → 1.0.0-beta.2

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.
Files changed (45) hide show
  1. package/dist/admin/Avatar-CdT7eBCh.js +39 -0
  2. package/dist/admin/Avatar-zlMTAZh3.mjs +40 -0
  3. package/dist/admin/{Root-2FMy-qQg.mjs → Root-CgVBJuoM.mjs} +12 -4
  4. package/dist/admin/{Root-DDi0mtve.js → Root-CsiOnzlB.js} +12 -4
  5. package/dist/admin/cs-C_jSgeON.js +416 -0
  6. package/dist/admin/cs-wtnknvBC.mjs +416 -0
  7. package/dist/admin/de-Cg5HyoCY.js +416 -0
  8. package/dist/admin/de-DnnVdUxk.mjs +416 -0
  9. package/dist/admin/en-B3utEgMT.mjs +416 -0
  10. package/dist/admin/en-Cz1IJEvp.js +416 -0
  11. package/dist/admin/es-CGA0Tslt.js +416 -0
  12. package/dist/admin/es-RoCEriJL.mjs +416 -0
  13. package/dist/admin/fr-Ca74t21t.js +416 -0
  14. package/dist/admin/fr-CtmuSfiQ.mjs +416 -0
  15. package/dist/admin/{index-BHfYu0uA.js → index-BCBu-0nr.js} +65 -10
  16. package/dist/admin/{index-D9CiI8Yr.mjs → index-BI2WIsds.mjs} +73 -18
  17. package/dist/admin/index-CPSoAbZt.js +2321 -0
  18. package/dist/admin/index-D9ttdrT3.js +2716 -0
  19. package/dist/admin/index-DQdn5s8q.js +1184 -0
  20. package/dist/admin/index-DvfwvCj0.mjs +1182 -0
  21. package/dist/admin/index-VyHXoQ6p.mjs +2321 -0
  22. package/dist/admin/index-gFqHlMLP.mjs +2716 -0
  23. package/dist/admin/index.js +1 -1
  24. package/dist/admin/index.mjs +1 -1
  25. package/dist/admin/it-BAB9hDdp.mjs +416 -0
  26. package/dist/admin/it-dYT2_ERV.js +416 -0
  27. package/dist/admin/nl-CVqSbUU9.js +416 -0
  28. package/dist/admin/nl-CYv26PHv.mjs +416 -0
  29. package/dist/admin/pl-Bc0cS2mD.mjs +416 -0
  30. package/dist/admin/pl-HYF4BxRv.js +416 -0
  31. package/dist/admin/pt-DDUGyLtb.js +416 -0
  32. package/dist/admin/pt-DZyyK3EG.mjs +416 -0
  33. package/dist/admin/{useModelSchema-CqOTI7P1.js → useModelSchema-BogQah8f.js} +309 -287
  34. package/dist/admin/{useModelSchema-B2tmzlwQ.mjs → useModelSchema-C6bxNjW4.mjs} +320 -298
  35. package/dist/server/index.js +15 -15
  36. package/dist/server/index.mjs +15 -15
  37. package/package.json +4 -4
  38. package/dist/admin/Avatar-Cvk89aMx.js +0 -67
  39. package/dist/admin/Avatar-DNczJU0i.mjs +0 -66
  40. package/dist/admin/index-BQi_BUi6.mjs +0 -1968
  41. package/dist/admin/index-BV-4M_Fp.js +0 -1970
  42. package/dist/admin/index-CANDPUGD.mjs +0 -1215
  43. package/dist/admin/index-CqR8WpOa.js +0 -1217
  44. package/dist/admin/index-D6ktNZcj.js +0 -1685
  45. package/dist/admin/index-DszX3ibA.mjs +0 -1683
@@ -0,0 +1,2321 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { Field, Combobox, ComboboxOption, Button, Flex, TextInput, Checkbox, Box, Typography, Alert, Tabs, Grid, SingleSelect, SingleSelectOption, IconButton, Badge, Loader, Accordion, Main, SearchForm, Searchbar, Table, Thead, Tr, Th, VisuallyHidden, Tbody, Td } from "@strapi/design-system";
3
+ import { Plus, Trash, Pencil } from "@strapi/icons";
4
+ import { useNotification, useFetchClient, Page, useRBAC, Layouts } from "@strapi/strapi/admin";
5
+ import { useState } from "react";
6
+ import { useIntl } from "react-intl";
7
+ import { useQuery, useQueryClient, useMutation } from "react-query";
8
+ import { d as client, g as getTranslation, e as getAuthHeaders, f as useOrganizationOptions, c as PERMISSIONS, P as PLUGIN_ID } from "./index-BI2WIsds.mjs";
9
+ import { A as Avatar } from "./Avatar-zlMTAZh3.mjs";
10
+ import { w as withContext, S as SheetDialog, F as FormSection, a as SectionLabel, M as MediaPickerField, u as useModelSchema, E as EditLayout, C as CustomFieldsSection, b as EditSidebar, c as MetaItem, d as MetaKey, e as MonoChip, f as MetaVal, g as EditViewSidePanels, A as AccountRow, P as ProviderBadge, i as ConfirmDialog, j as Code } from "./useModelSchema-C6bxNjW4.mjs";
11
+ function UserCombobox({
12
+ label,
13
+ hint,
14
+ placeholder,
15
+ value,
16
+ onChange,
17
+ error,
18
+ required
19
+ }) {
20
+ const { formatMessage } = useIntl();
21
+ const [search, setSearch] = useState("");
22
+ const { data, isLoading } = useQuery({
23
+ queryKey: ["user-combobox-search", search],
24
+ queryFn: async () => {
25
+ const whereClause = search ? JSON.stringify([
26
+ {
27
+ field: "email",
28
+ operator: "contains",
29
+ value: search,
30
+ connector: "OR"
31
+ },
32
+ {
33
+ field: "name",
34
+ operator: "contains",
35
+ value: search,
36
+ connector: "OR"
37
+ }
38
+ ]) : void 0;
39
+ const result = await client.dash.listUsers({
40
+ query: {
41
+ limit: search ? 100 : 20,
42
+ offset: 0,
43
+ sortBy: "createdAt",
44
+ sortOrder: "desc",
45
+ ...whereClause ? { where: whereClause } : {}
46
+ }
47
+ });
48
+ return result.data?.users ?? [];
49
+ },
50
+ keepPreviousData: true
51
+ });
52
+ const users = data ?? [];
53
+ return /* @__PURE__ */ jsxs(Field.Root, { hint, error, style: { width: "100%" }, children: [
54
+ /* @__PURE__ */ jsx(Field.Label, { children: label ?? formatMessage({
55
+ id: getTranslation("components.userCombobox.label"),
56
+ defaultMessage: "User"
57
+ }) }),
58
+ /* @__PURE__ */ jsx(
59
+ Combobox,
60
+ {
61
+ placeholder: placeholder ?? formatMessage({
62
+ id: getTranslation("components.userCombobox.placeholder"),
63
+ defaultMessage: "Search users by email or name…"
64
+ }),
65
+ value,
66
+ onChange: (val) => onChange(val),
67
+ onInputChange: (e) => setSearch(e.target.value),
68
+ loading: isLoading,
69
+ required,
70
+ children: users.map((user) => /* @__PURE__ */ jsxs(ComboboxOption, { value: user.id, children: [
71
+ user.name,
72
+ " — ",
73
+ user.email
74
+ ] }, user.id))
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsx(Field.Hint, {}),
78
+ /* @__PURE__ */ jsx(Field.Error, {})
79
+ ] });
80
+ }
81
+ function CreateOrganizationDialog({ teamsEnabled, onClose }) {
82
+ const { formatMessage } = useIntl();
83
+ const qc = useQueryClient();
84
+ const { toggleNotification } = useNotification();
85
+ const [name, setName] = useState("");
86
+ const [slug, setSlug] = useState("");
87
+ const [logo, setLogo] = useState("");
88
+ const [ownerId, setOwnerId] = useState("");
89
+ const [skipDefaultTeam, setSkipDefaultTeam] = useState(false);
90
+ const [defaultTeamName, setDefaultTeamName] = useState("");
91
+ const createMutation = useMutation({
92
+ mutationFn: async () => {
93
+ const result = await client.dash.organization.create(
94
+ {
95
+ name,
96
+ slug,
97
+ ...logo ? { logo } : {},
98
+ ...teamsEnabled && !skipDefaultTeam && defaultTeamName ? { defaultTeamName } : {}
99
+ },
100
+ withContext({ userId: ownerId, skipDefaultTeam }, getAuthHeaders())
101
+ );
102
+ if (result.error)
103
+ throw new Error(
104
+ result.error.message ?? formatMessage({
105
+ id: getTranslation("organizations.create.error.createFailed"),
106
+ defaultMessage: "Create failed"
107
+ })
108
+ );
109
+ return result.data;
110
+ },
111
+ onSuccess: () => {
112
+ qc.invalidateQueries({ queryKey: ["dash-organizations"] });
113
+ toggleNotification({
114
+ type: "success",
115
+ message: formatMessage({
116
+ id: getTranslation("organizations.create.notification.success"),
117
+ defaultMessage: "Organization created successfully"
118
+ })
119
+ });
120
+ onClose();
121
+ },
122
+ onError: (err) => {
123
+ toggleNotification({
124
+ type: "danger",
125
+ message: err.message ?? formatMessage({
126
+ id: getTranslation("organizations.create.notification.error"),
127
+ defaultMessage: "Failed to create organization"
128
+ })
129
+ });
130
+ }
131
+ });
132
+ const handleNameChange = (e) => {
133
+ const val = e.target.value;
134
+ setName(val);
135
+ if (!slug || slug === slugify(name)) {
136
+ setSlug(slugify(val));
137
+ }
138
+ };
139
+ const footer = /* @__PURE__ */ jsxs(Fragment, { children: [
140
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", onClick: onClose, children: formatMessage({
141
+ id: getTranslation("organizations.common.cancel"),
142
+ defaultMessage: "Cancel"
143
+ }) }),
144
+ /* @__PURE__ */ jsx(
145
+ Button,
146
+ {
147
+ loading: createMutation.isLoading,
148
+ disabled: !name || !slug || !ownerId,
149
+ onClick: () => createMutation.mutate(),
150
+ "data-testid": "create-org-submit",
151
+ children: formatMessage({
152
+ id: getTranslation("organizations.common.createOrganization"),
153
+ defaultMessage: "Create organization"
154
+ })
155
+ }
156
+ )
157
+ ] });
158
+ return /* @__PURE__ */ jsx(
159
+ SheetDialog,
160
+ {
161
+ title: formatMessage({
162
+ id: getTranslation("organizations.common.createOrganization"),
163
+ defaultMessage: "Create organization"
164
+ }),
165
+ actionButtons: footer,
166
+ onClose,
167
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, children: [
168
+ /* @__PURE__ */ jsxs(FormSection, { children: [
169
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
170
+ id: getTranslation("organizations.common.details"),
171
+ defaultMessage: "Details"
172
+ }) }),
173
+ /* @__PURE__ */ jsxs(Field.Root, { style: { width: "100%" }, required: true, children: [
174
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
175
+ id: getTranslation("organizations.common.name"),
176
+ defaultMessage: "Name"
177
+ }) }),
178
+ /* @__PURE__ */ jsx(
179
+ TextInput,
180
+ {
181
+ name: "name",
182
+ value: name,
183
+ onChange: handleNameChange,
184
+ placeholder: formatMessage({
185
+ id: getTranslation("organizations.create.name.placeholder"),
186
+ defaultMessage: "Acme Corp"
187
+ })
188
+ }
189
+ )
190
+ ] }),
191
+ /* @__PURE__ */ jsxs(
192
+ Field.Root,
193
+ {
194
+ style: { width: "100%" },
195
+ hint: formatMessage({
196
+ id: getTranslation("organizations.common.slugHint"),
197
+ defaultMessage: "Used in URLs"
198
+ }),
199
+ required: true,
200
+ children: [
201
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
202
+ id: getTranslation("organizations.common.slug"),
203
+ defaultMessage: "Slug"
204
+ }) }),
205
+ /* @__PURE__ */ jsx(
206
+ TextInput,
207
+ {
208
+ name: "slug",
209
+ value: slug,
210
+ onChange: (e) => setSlug(e.target.value),
211
+ placeholder: formatMessage({
212
+ id: getTranslation("organizations.create.slug.placeholder"),
213
+ defaultMessage: "acme-corp"
214
+ })
215
+ }
216
+ ),
217
+ /* @__PURE__ */ jsx(Field.Hint, {})
218
+ ]
219
+ }
220
+ ),
221
+ /* @__PURE__ */ jsx(
222
+ MediaPickerField,
223
+ {
224
+ label: formatMessage({
225
+ id: getTranslation("organizations.common.logo.label"),
226
+ defaultMessage: "Logo URL"
227
+ }),
228
+ name: "logo",
229
+ value: logo,
230
+ onChange: setLogo,
231
+ placeholder: formatMessage({
232
+ id: getTranslation("organizations.common.logo.placeholder"),
233
+ defaultMessage: "https://example.com/logo.png"
234
+ }),
235
+ hint: formatMessage({
236
+ id: getTranslation("organizations.common.logo.hint"),
237
+ defaultMessage: "Optional — publicly accessible image URL"
238
+ })
239
+ }
240
+ )
241
+ ] }),
242
+ /* @__PURE__ */ jsxs(FormSection, { children: [
243
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
244
+ id: getTranslation("organizations.create.owner.label"),
245
+ defaultMessage: "Owner"
246
+ }) }),
247
+ /* @__PURE__ */ jsx(
248
+ UserCombobox,
249
+ {
250
+ label: formatMessage({
251
+ id: getTranslation("organizations.create.owner.label"),
252
+ defaultMessage: "Owner"
253
+ }),
254
+ hint: formatMessage({
255
+ id: getTranslation("organizations.create.owner.hint"),
256
+ defaultMessage: "The user who will own and manage this organization"
257
+ }),
258
+ value: ownerId,
259
+ onChange: setOwnerId,
260
+ required: true
261
+ }
262
+ )
263
+ ] }),
264
+ teamsEnabled && /* @__PURE__ */ jsxs(FormSection, { children: [
265
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
266
+ id: getTranslation("organizations.create.defaultTeam.title"),
267
+ defaultMessage: "Default team"
268
+ }) }),
269
+ /* @__PURE__ */ jsx(
270
+ Checkbox,
271
+ {
272
+ name: "skipDefaultTeam",
273
+ checked: skipDefaultTeam,
274
+ onCheckedChange: (checked) => setSkipDefaultTeam(checked),
275
+ children: formatMessage({
276
+ id: getTranslation("organizations.create.defaultTeam.skip"),
277
+ defaultMessage: "Don't create a default team"
278
+ })
279
+ }
280
+ ),
281
+ !skipDefaultTeam && /* @__PURE__ */ jsxs(Field.Root, { style: { width: "100%" }, children: [
282
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
283
+ id: getTranslation(
284
+ "organizations.create.defaultTeam.name.label"
285
+ ),
286
+ defaultMessage: "Default team name"
287
+ }) }),
288
+ /* @__PURE__ */ jsx(
289
+ TextInput,
290
+ {
291
+ name: "defaultTeamName",
292
+ value: defaultTeamName,
293
+ onChange: (e) => setDefaultTeamName(e.target.value),
294
+ placeholder: formatMessage({
295
+ id: getTranslation(
296
+ "organizations.create.defaultTeam.name.placeholder"
297
+ ),
298
+ defaultMessage: "Leave blank to use the system default"
299
+ })
300
+ }
301
+ )
302
+ ] }),
303
+ skipDefaultTeam && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
304
+ id: getTranslation(
305
+ "organizations.create.defaultTeam.skipHint"
306
+ ),
307
+ defaultMessage: "Members can be added to teams manually after the organization is created."
308
+ }) }) })
309
+ ] })
310
+ ] })
311
+ }
312
+ );
313
+ }
314
+ function slugify(str) {
315
+ return str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
316
+ }
317
+ const INVITATION_STATUS_VARIANT = {
318
+ pending: "warning",
319
+ accepted: "success",
320
+ rejected: "danger",
321
+ canceled: "neutral"
322
+ };
323
+ const INVITATION_STATUS_LABEL = {
324
+ pending: {
325
+ id: getTranslation("organizations.detail.invitations.status.pending"),
326
+ defaultMessage: "pending"
327
+ },
328
+ accepted: {
329
+ id: getTranslation("organizations.detail.invitations.status.accepted"),
330
+ defaultMessage: "accepted"
331
+ },
332
+ rejected: {
333
+ id: getTranslation("organizations.detail.invitations.status.rejected"),
334
+ defaultMessage: "rejected"
335
+ },
336
+ canceled: {
337
+ id: getTranslation("organizations.detail.invitations.status.canceled"),
338
+ defaultMessage: "canceled"
339
+ }
340
+ };
341
+ const ROLE_OPTIONS = [
342
+ {
343
+ value: "member",
344
+ label: {
345
+ id: getTranslation("organizations.common.roles.member"),
346
+ defaultMessage: "Member"
347
+ }
348
+ },
349
+ {
350
+ value: "admin",
351
+ label: {
352
+ id: getTranslation("organizations.common.roles.admin"),
353
+ defaultMessage: "Admin"
354
+ }
355
+ },
356
+ {
357
+ value: "owner",
358
+ label: {
359
+ id: getTranslation("organizations.common.roles.owner"),
360
+ defaultMessage: "Owner"
361
+ }
362
+ }
363
+ ];
364
+ function InlineLoader() {
365
+ const { formatMessage } = useIntl();
366
+ return /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsx(Loader, { small: true, children: formatMessage({
367
+ id: getTranslation("organizations.common.loading"),
368
+ defaultMessage: "Loading…"
369
+ }) }) });
370
+ }
371
+ const STANDARD_ORG_FIELDS = /* @__PURE__ */ new Set([
372
+ "id",
373
+ "name",
374
+ "slug",
375
+ "logo",
376
+ "metadata",
377
+ "memberCount",
378
+ "createdAt",
379
+ "updatedAt"
380
+ ]);
381
+ function OrganizationDetail({
382
+ organizationId,
383
+ teamsEnabled,
384
+ onClose
385
+ }) {
386
+ const { formatMessage } = useIntl();
387
+ const schemaQuery = useModelSchema("organization");
388
+ const qc = useQueryClient();
389
+ const { toggleNotification } = useNotification();
390
+ const { get, put } = useFetchClient();
391
+ const orgQuery = useQuery({
392
+ queryKey: ["dash-org", organizationId],
393
+ queryFn: async () => {
394
+ const result = await client.dash.organization[organizationId](
395
+ {},
396
+ withContext({ organizationId }, getAuthHeaders())
397
+ );
398
+ if (result.error)
399
+ throw new Error(
400
+ result.error.message ?? formatMessage({
401
+ id: getTranslation("organizations.detail.error.loadOrg"),
402
+ defaultMessage: "Failed to load org"
403
+ })
404
+ );
405
+ return result.data;
406
+ }
407
+ });
408
+ const membersQuery = useQuery({
409
+ queryKey: ["dash-org-members", organizationId],
410
+ queryFn: async () => {
411
+ const result = await client.dash.organization[organizationId].members({}, withContext({ organizationId }, getAuthHeaders()));
412
+ if (result.error)
413
+ throw new Error(
414
+ result.error.message ?? formatMessage({
415
+ id: getTranslation("organizations.common.failed"),
416
+ defaultMessage: "Failed"
417
+ })
418
+ );
419
+ return result.data ?? [];
420
+ }
421
+ });
422
+ const teamsQuery = useQuery({
423
+ queryKey: ["dash-org-teams", organizationId],
424
+ queryFn: async () => {
425
+ if (!teamsEnabled) return [];
426
+ const result = await client.dash.organization[organizationId].teams({}, withContext({ organizationId }, getAuthHeaders()));
427
+ if (result.error)
428
+ throw new Error(
429
+ result.error.message ?? formatMessage({
430
+ id: getTranslation("organizations.common.failed"),
431
+ defaultMessage: "Failed"
432
+ })
433
+ );
434
+ return result.data ?? [];
435
+ },
436
+ enabled: teamsEnabled
437
+ });
438
+ const ssoQuery = useQuery({
439
+ queryKey: ["dash-org-sso", organizationId],
440
+ queryFn: async () => {
441
+ const result = await client.dash.organization[organizationId].ssoProviders({}, withContext({ organizationId }, getAuthHeaders()));
442
+ if (result.error)
443
+ throw new Error(
444
+ result.error.message ?? formatMessage({
445
+ id: getTranslation("organizations.common.failed"),
446
+ defaultMessage: "Failed"
447
+ })
448
+ );
449
+ return result.data ?? [];
450
+ }
451
+ });
452
+ const invitationsQuery = useQuery({
453
+ queryKey: ["dash-org-invitations", organizationId],
454
+ queryFn: async () => {
455
+ const result = await client.dash.organization[organizationId].invitations({}, withContext({ organizationId }, getAuthHeaders()));
456
+ if (result.error)
457
+ throw new Error(
458
+ result.error.message ?? formatMessage({
459
+ id: getTranslation("organizations.common.failed"),
460
+ defaultMessage: "Failed"
461
+ })
462
+ );
463
+ return result.data ?? [];
464
+ }
465
+ });
466
+ const strapiOrgQuery = useQuery({
467
+ queryKey: ["dash-strapi-org", organizationId],
468
+ enabled: !!orgQuery.data,
469
+ queryFn: async () => {
470
+ const { data } = await get(
471
+ `/better-auth-dashboard/db?uid=plugin::better-auth.organization&filters[id][$eq]=${organizationId}&pagination[pageSize]=1`
472
+ );
473
+ return data.results?.[0] ?? null;
474
+ }
475
+ });
476
+ const [activeTab, setActiveTab] = useState("details");
477
+ const [editName, setEditName] = useState(void 0);
478
+ const [editSlug, setEditSlug] = useState(void 0);
479
+ const [editLogo, setEditLogo] = useState(void 0);
480
+ const [editExtra, setEditExtra] = useState({});
481
+ const [confirmRemoveMemberId, setConfirmRemoveMemberId] = useState(null);
482
+ const [confirmDeleteTeamId, setConfirmDeleteTeamId] = useState(
483
+ null
484
+ );
485
+ const [confirmDeleteSsoId, setConfirmDeleteSsoId] = useState(
486
+ null
487
+ );
488
+ const [inviteEmail, setInviteEmail] = useState("");
489
+ const [inviteRole, setInviteRole] = useState("member");
490
+ const [confirmCancelInvitationId, setConfirmCancelInvitationId] = useState(null);
491
+ const handleExtraChange = (name, value) => {
492
+ setEditExtra((prev) => ({ ...prev, [name]: value }));
493
+ };
494
+ const org = orgQuery.data;
495
+ const extraData = {
496
+ ...strapiOrgQuery.data ?? {},
497
+ ...editExtra
498
+ };
499
+ const updateOrgMutation = useMutation({
500
+ mutationFn: async () => {
501
+ const body = { ...editExtra };
502
+ if (editName !== void 0) body.name = editName;
503
+ if (editSlug !== void 0) body.slug = editSlug;
504
+ if (editLogo !== void 0) body.logo = editLogo;
505
+ const documentId = strapiOrgQuery.data?.documentId;
506
+ if (!documentId)
507
+ throw new Error(
508
+ formatMessage({
509
+ id: getTranslation("organizations.detail.error.documentId"),
510
+ defaultMessage: "Could not resolve documentId for organization"
511
+ })
512
+ );
513
+ await put(
514
+ `/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.organization`,
515
+ body
516
+ );
517
+ },
518
+ onSuccess: async () => {
519
+ await qc.invalidateQueries({
520
+ queryKey: ["dash-strapi-org", organizationId]
521
+ });
522
+ qc.invalidateQueries({ queryKey: ["dash-org", organizationId] });
523
+ qc.invalidateQueries({ queryKey: ["dash-organizations"] });
524
+ qc.invalidateQueries({ queryKey: ["dash-strapi-org", organizationId] });
525
+ setEditName(void 0);
526
+ setEditSlug(void 0);
527
+ setEditLogo(void 0);
528
+ setEditExtra({});
529
+ toggleNotification({
530
+ type: "success",
531
+ message: formatMessage({
532
+ id: getTranslation("organizations.detail.notification.updated"),
533
+ defaultMessage: "Organization updated successfully"
534
+ })
535
+ });
536
+ onClose();
537
+ },
538
+ onError: (err) => {
539
+ toggleNotification({
540
+ type: "danger",
541
+ message: err.message ?? formatMessage({
542
+ id: getTranslation("organizations.detail.notification.updateError"),
543
+ defaultMessage: "Update failed"
544
+ })
545
+ });
546
+ }
547
+ });
548
+ const [addUserId, setAddUserId] = useState("");
549
+ const [addRole, setAddRole] = useState("member");
550
+ const addMemberMutation = useMutation({
551
+ mutationFn: async () => {
552
+ const result = await client.dash.organization.addMember(
553
+ { userId: addUserId, role: addRole },
554
+ withContext({ organizationId }, getAuthHeaders())
555
+ );
556
+ if (result.error)
557
+ throw new Error(
558
+ result.error.message ?? formatMessage({
559
+ id: getTranslation(
560
+ "organizations.detail.members.error.addFailed"
561
+ ),
562
+ defaultMessage: "Add member failed"
563
+ })
564
+ );
565
+ return result.data;
566
+ },
567
+ onSuccess: () => {
568
+ qc.invalidateQueries({ queryKey: ["dash-org-members", organizationId] });
569
+ setAddUserId("");
570
+ setAddRole("member");
571
+ toggleNotification({
572
+ type: "success",
573
+ message: formatMessage({
574
+ id: getTranslation("organizations.detail.members.notification.added"),
575
+ defaultMessage: "Member added"
576
+ })
577
+ });
578
+ },
579
+ onError: (err) => {
580
+ toggleNotification({
581
+ type: "danger",
582
+ message: err.message ?? formatMessage({
583
+ id: getTranslation(
584
+ "organizations.detail.members.notification.addError"
585
+ ),
586
+ defaultMessage: "Failed to add member"
587
+ })
588
+ });
589
+ }
590
+ });
591
+ const removeMemberMutation = useMutation({
592
+ mutationFn: async (memberId) => {
593
+ const result = await client.dash.organization.removeMember(
594
+ { memberId },
595
+ withContext({ organizationId }, getAuthHeaders())
596
+ );
597
+ if (result.error)
598
+ throw new Error(
599
+ result.error.message ?? formatMessage({
600
+ id: getTranslation("organizations.common.failed"),
601
+ defaultMessage: "Failed"
602
+ })
603
+ );
604
+ },
605
+ onSuccess: () => {
606
+ setConfirmRemoveMemberId(null);
607
+ qc.invalidateQueries({ queryKey: ["dash-org-members", organizationId] });
608
+ toggleNotification({
609
+ type: "success",
610
+ message: formatMessage({
611
+ id: getTranslation(
612
+ "organizations.detail.members.notification.removed"
613
+ ),
614
+ defaultMessage: "Member removed"
615
+ })
616
+ });
617
+ },
618
+ onError: (err) => {
619
+ toggleNotification({
620
+ type: "danger",
621
+ message: err.message ?? formatMessage({
622
+ id: getTranslation(
623
+ "organizations.detail.members.notification.removeError"
624
+ ),
625
+ defaultMessage: "Failed to remove member"
626
+ })
627
+ });
628
+ }
629
+ });
630
+ const updateRoleMutation = useMutation({
631
+ mutationFn: async ({
632
+ memberId,
633
+ role
634
+ }) => {
635
+ const result = await client.dash.organization.updateMemberRole(
636
+ { memberId, role },
637
+ withContext({ organizationId }, getAuthHeaders())
638
+ );
639
+ if (result.error)
640
+ throw new Error(
641
+ result.error.message ?? formatMessage({
642
+ id: getTranslation("organizations.common.failed"),
643
+ defaultMessage: "Failed"
644
+ })
645
+ );
646
+ return result.data;
647
+ },
648
+ onSuccess: () => {
649
+ qc.invalidateQueries({ queryKey: ["dash-org-members", organizationId] });
650
+ toggleNotification({
651
+ type: "success",
652
+ message: formatMessage({
653
+ id: getTranslation(
654
+ "organizations.detail.members.notification.roleUpdated"
655
+ ),
656
+ defaultMessage: "Role updated"
657
+ })
658
+ });
659
+ },
660
+ onError: (err) => {
661
+ toggleNotification({
662
+ type: "danger",
663
+ message: err.message ?? formatMessage({
664
+ id: getTranslation(
665
+ "organizations.detail.members.notification.roleUpdateError"
666
+ ),
667
+ defaultMessage: "Failed to update role"
668
+ })
669
+ });
670
+ }
671
+ });
672
+ const [newTeamName, setNewTeamName] = useState("");
673
+ const createTeamMutation = useMutation({
674
+ mutationFn: async () => {
675
+ const result = await client.dash.organization.createTeam(
676
+ { name: newTeamName },
677
+ withContext({ organizationId }, getAuthHeaders())
678
+ );
679
+ if (result.error)
680
+ throw new Error(
681
+ result.error.message ?? formatMessage({
682
+ id: getTranslation(
683
+ "organizations.detail.teams.error.createFailed"
684
+ ),
685
+ defaultMessage: "Create team failed"
686
+ })
687
+ );
688
+ return result.data;
689
+ },
690
+ onSuccess: () => {
691
+ qc.invalidateQueries({ queryKey: ["dash-org-teams", organizationId] });
692
+ setNewTeamName("");
693
+ toggleNotification({
694
+ type: "success",
695
+ message: formatMessage({
696
+ id: getTranslation("organizations.detail.teams.notification.created"),
697
+ defaultMessage: "Team created"
698
+ })
699
+ });
700
+ },
701
+ onError: (err) => {
702
+ toggleNotification({
703
+ type: "danger",
704
+ message: err.message ?? formatMessage({
705
+ id: getTranslation(
706
+ "organizations.detail.teams.notification.createError"
707
+ ),
708
+ defaultMessage: "Failed to create team"
709
+ })
710
+ });
711
+ }
712
+ });
713
+ const deleteTeamMutation = useMutation({
714
+ mutationFn: async (teamId) => {
715
+ const result = await client.dash.organization.deleteTeam(
716
+ { teamId },
717
+ withContext({ organizationId }, getAuthHeaders())
718
+ );
719
+ if (result.error)
720
+ throw new Error(
721
+ result.error.message ?? formatMessage({
722
+ id: getTranslation("organizations.common.failed"),
723
+ defaultMessage: "Failed"
724
+ })
725
+ );
726
+ },
727
+ onSuccess: () => {
728
+ setConfirmDeleteTeamId(null);
729
+ qc.invalidateQueries({ queryKey: ["dash-org-teams", organizationId] });
730
+ toggleNotification({
731
+ type: "success",
732
+ message: formatMessage({
733
+ id: getTranslation("organizations.detail.teams.notification.deleted"),
734
+ defaultMessage: "Team deleted"
735
+ })
736
+ });
737
+ },
738
+ onError: (err) => {
739
+ toggleNotification({
740
+ type: "danger",
741
+ message: err.message ?? formatMessage({
742
+ id: getTranslation(
743
+ "organizations.detail.teams.notification.deleteError"
744
+ ),
745
+ defaultMessage: "Failed to delete team"
746
+ })
747
+ });
748
+ }
749
+ });
750
+ const deleteSsoMutation = useMutation({
751
+ mutationFn: async (providerId) => {
752
+ const result = await client.dash.organization[organizationId].ssoProvider.delete(
753
+ { providerId },
754
+ withContext({ organizationId }, getAuthHeaders())
755
+ );
756
+ if (result.error)
757
+ throw new Error(
758
+ result.error.message ?? formatMessage({
759
+ id: getTranslation("organizations.common.failed"),
760
+ defaultMessage: "Failed"
761
+ })
762
+ );
763
+ },
764
+ onSuccess: () => {
765
+ setConfirmDeleteSsoId(null);
766
+ qc.invalidateQueries({ queryKey: ["dash-org-sso", organizationId] });
767
+ toggleNotification({
768
+ type: "success",
769
+ message: formatMessage({
770
+ id: getTranslation("organizations.detail.sso.notification.deleted"),
771
+ defaultMessage: "SSO provider deleted"
772
+ })
773
+ });
774
+ },
775
+ onError: (err) => {
776
+ toggleNotification({
777
+ type: "danger",
778
+ message: err.message ?? formatMessage({
779
+ id: getTranslation(
780
+ "organizations.detail.sso.notification.deleteError"
781
+ ),
782
+ defaultMessage: "Failed to delete SSO provider"
783
+ })
784
+ });
785
+ }
786
+ });
787
+ const inviteMemberMutation = useMutation({
788
+ mutationFn: async () => {
789
+ const result = await client.dash.organization.inviteMember(
790
+ { email: inviteEmail, role: inviteRole, invitedBy: "" },
791
+ withContext({ organizationId }, getAuthHeaders())
792
+ );
793
+ if (result.error)
794
+ throw new Error(
795
+ result.error.message ?? formatMessage({
796
+ id: getTranslation("organizations.common.failed"),
797
+ defaultMessage: "Failed"
798
+ })
799
+ );
800
+ return result.data;
801
+ },
802
+ onSuccess: () => {
803
+ qc.invalidateQueries({
804
+ queryKey: ["dash-org-invitations", organizationId]
805
+ });
806
+ setInviteEmail("");
807
+ setInviteRole("member");
808
+ toggleNotification({
809
+ type: "success",
810
+ message: formatMessage({
811
+ id: getTranslation(
812
+ "organizations.detail.invitations.notification.sent"
813
+ ),
814
+ defaultMessage: "Invitation sent"
815
+ })
816
+ });
817
+ },
818
+ onError: (err) => {
819
+ toggleNotification({
820
+ type: "danger",
821
+ message: err.message ?? formatMessage({
822
+ id: getTranslation(
823
+ "organizations.detail.invitations.notification.inviteError"
824
+ ),
825
+ defaultMessage: "Failed to invite"
826
+ })
827
+ });
828
+ }
829
+ });
830
+ const cancelInvitationMutation = useMutation({
831
+ mutationFn: async (invitationId) => {
832
+ const result = await client.dash.organization.cancelInvitation(
833
+ { invitationId },
834
+ withContext({ organizationId }, getAuthHeaders())
835
+ );
836
+ if (result.error)
837
+ throw new Error(
838
+ result.error.message ?? formatMessage({
839
+ id: getTranslation("organizations.common.failed"),
840
+ defaultMessage: "Failed"
841
+ })
842
+ );
843
+ },
844
+ onSuccess: () => {
845
+ setConfirmCancelInvitationId(null);
846
+ qc.invalidateQueries({
847
+ queryKey: ["dash-org-invitations", organizationId]
848
+ });
849
+ toggleNotification({
850
+ type: "success",
851
+ message: formatMessage({
852
+ id: getTranslation(
853
+ "organizations.detail.invitations.notification.cancelled"
854
+ ),
855
+ defaultMessage: "Invitation cancelled"
856
+ })
857
+ });
858
+ },
859
+ onError: (err) => {
860
+ toggleNotification({
861
+ type: "danger",
862
+ message: err.message ?? formatMessage({
863
+ id: getTranslation(
864
+ "organizations.detail.invitations.notification.cancelError"
865
+ ),
866
+ defaultMessage: "Failed to cancel"
867
+ })
868
+ });
869
+ }
870
+ });
871
+ const resendInvitationMutation = useMutation({
872
+ mutationFn: async (invitationId) => {
873
+ const result = await client.dash.organization.resendInvitation(
874
+ { invitationId },
875
+ withContext({ organizationId }, getAuthHeaders())
876
+ );
877
+ if (result.error)
878
+ throw new Error(
879
+ result.error.message ?? formatMessage({
880
+ id: getTranslation("organizations.common.failed"),
881
+ defaultMessage: "Failed"
882
+ })
883
+ );
884
+ },
885
+ onSuccess: () => {
886
+ toggleNotification({
887
+ type: "success",
888
+ message: formatMessage({
889
+ id: getTranslation(
890
+ "organizations.detail.invitations.notification.resent"
891
+ ),
892
+ defaultMessage: "Invitation resent"
893
+ })
894
+ });
895
+ },
896
+ onError: (err) => {
897
+ toggleNotification({
898
+ type: "danger",
899
+ message: err.message ?? formatMessage({
900
+ id: getTranslation(
901
+ "organizations.detail.invitations.notification.resendError"
902
+ ),
903
+ defaultMessage: "Failed to resend"
904
+ })
905
+ });
906
+ }
907
+ });
908
+ const members = membersQuery.data ?? [];
909
+ const teams = teamsQuery.data ?? [];
910
+ const ssoProviders = ssoQuery.data ?? [];
911
+ const invitations = invitationsQuery.data ?? [];
912
+ const hasOrgEdits = editName !== void 0 || editSlug !== void 0 || editLogo !== void 0 || Object.keys(editExtra).length > 0;
913
+ const customFields = Object.entries(schemaQuery.data ?? {}).filter(([name]) => !STANDARD_ORG_FIELDS.has(name)).map(([name, attribute]) => ({ name, attribute }));
914
+ const detailsFooter = activeTab === "details" ? /* @__PURE__ */ jsxs(Fragment, { children: [
915
+ /* @__PURE__ */ jsx(
916
+ Button,
917
+ {
918
+ variant: "tertiary",
919
+ onClick: () => {
920
+ setEditName(void 0);
921
+ setEditSlug(void 0);
922
+ setEditLogo(void 0);
923
+ setEditExtra({});
924
+ onClose();
925
+ },
926
+ children: formatMessage({
927
+ id: getTranslation("organizations.detail.discard"),
928
+ defaultMessage: "Discard"
929
+ })
930
+ }
931
+ ),
932
+ /* @__PURE__ */ jsx(
933
+ Button,
934
+ {
935
+ disabled: !hasOrgEdits,
936
+ loading: updateOrgMutation.isLoading,
937
+ onClick: () => updateOrgMutation.mutate(),
938
+ "data-testid": "save-org-btn",
939
+ children: formatMessage({
940
+ id: getTranslation("organizations.detail.save"),
941
+ defaultMessage: "Save changes"
942
+ })
943
+ }
944
+ )
945
+ ] }) : void 0;
946
+ return /* @__PURE__ */ jsxs(
947
+ SheetDialog,
948
+ {
949
+ title: org?.name ?? formatMessage({
950
+ id: getTranslation("organizations.detail.fallbackTitle"),
951
+ defaultMessage: "Organization"
952
+ }),
953
+ actionButtons: detailsFooter,
954
+ onClose,
955
+ "data-testid": "org-detail-drawer",
956
+ children: [
957
+ orgQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : orgQuery.isError ? /* @__PURE__ */ jsx(
958
+ Alert,
959
+ {
960
+ closeLabel: formatMessage({
961
+ id: getTranslation("organizations.common.close"),
962
+ defaultMessage: "Close"
963
+ }),
964
+ title: formatMessage({
965
+ id: getTranslation("organizations.detail.error.loadTitle"),
966
+ defaultMessage: "Failed to load organization"
967
+ }),
968
+ variant: "danger",
969
+ children: orgQuery.error instanceof Error ? orgQuery.error.message : formatMessage({
970
+ id: getTranslation("organizations.common.errorOccurred"),
971
+ defaultMessage: "An error occurred"
972
+ })
973
+ }
974
+ ) : /* @__PURE__ */ jsxs(Tabs.Root, { defaultValue: "details", onValueChange: setActiveTab, children: [
975
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
976
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "details", children: formatMessage({
977
+ id: getTranslation("organizations.common.details"),
978
+ defaultMessage: "Details"
979
+ }) }),
980
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "members", "data-testid": "org-members-tab", children: formatMessage(
981
+ {
982
+ id: getTranslation("organizations.detail.tabs.members"),
983
+ defaultMessage: "Members ({count})"
984
+ },
985
+ { count: members.length }
986
+ ) }),
987
+ teamsEnabled && /* @__PURE__ */ jsx(Tabs.Trigger, { value: "teams", children: formatMessage(
988
+ {
989
+ id: getTranslation("organizations.detail.tabs.teams"),
990
+ defaultMessage: "Teams ({count})"
991
+ },
992
+ { count: teams.length }
993
+ ) }),
994
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "invitations", children: formatMessage(
995
+ {
996
+ id: getTranslation("organizations.detail.tabs.invitations"),
997
+ defaultMessage: "Invitations ({count})"
998
+ },
999
+ { count: invitations.length }
1000
+ ) }),
1001
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "sso", children: formatMessage(
1002
+ {
1003
+ id: getTranslation("organizations.detail.tabs.sso"),
1004
+ defaultMessage: "SSO ({count})"
1005
+ },
1006
+ { count: ssoProviders.length }
1007
+ ) })
1008
+ ] }),
1009
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "details", children: /* @__PURE__ */ jsxs(EditLayout, { children: [
1010
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, children: [
1011
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1012
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1013
+ id: getTranslation("organizations.common.details"),
1014
+ defaultMessage: "Details"
1015
+ }) }),
1016
+ /* @__PURE__ */ jsxs(Field.Root, { style: { width: "100%" }, children: [
1017
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1018
+ id: getTranslation("organizations.common.name"),
1019
+ defaultMessage: "Name"
1020
+ }) }),
1021
+ /* @__PURE__ */ jsx(
1022
+ TextInput,
1023
+ {
1024
+ value: editName ?? org?.name ?? "",
1025
+ onChange: (e) => setEditName(e.target.value),
1026
+ "data-testid": "org-name-input"
1027
+ }
1028
+ )
1029
+ ] }),
1030
+ /* @__PURE__ */ jsxs(
1031
+ Field.Root,
1032
+ {
1033
+ hint: formatMessage({
1034
+ id: getTranslation("organizations.common.slugHint"),
1035
+ defaultMessage: "Used in URLs"
1036
+ }),
1037
+ style: { width: "100%" },
1038
+ children: [
1039
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1040
+ id: getTranslation("organizations.common.slug"),
1041
+ defaultMessage: "Slug"
1042
+ }) }),
1043
+ /* @__PURE__ */ jsx(
1044
+ TextInput,
1045
+ {
1046
+ value: editSlug ?? org?.slug ?? "",
1047
+ onChange: (e) => setEditSlug(e.target.value),
1048
+ "data-testid": "org-slug-input"
1049
+ }
1050
+ ),
1051
+ /* @__PURE__ */ jsx(Field.Hint, {})
1052
+ ]
1053
+ }
1054
+ ),
1055
+ /* @__PURE__ */ jsx(
1056
+ MediaPickerField,
1057
+ {
1058
+ label: formatMessage({
1059
+ id: getTranslation("organizations.common.logo.label"),
1060
+ defaultMessage: "Logo URL"
1061
+ }),
1062
+ name: "logo",
1063
+ value: editLogo ?? org?.logo ?? "",
1064
+ onChange: setEditLogo,
1065
+ placeholder: formatMessage({
1066
+ id: getTranslation(
1067
+ "organizations.common.logo.placeholder"
1068
+ ),
1069
+ defaultMessage: "https://example.com/logo.png"
1070
+ }),
1071
+ hint: formatMessage({
1072
+ id: getTranslation("organizations.common.logo.hint"),
1073
+ defaultMessage: "Optional — publicly accessible image URL"
1074
+ })
1075
+ }
1076
+ )
1077
+ ] }),
1078
+ /* @__PURE__ */ jsx(
1079
+ CustomFieldsSection,
1080
+ {
1081
+ fields: customFields,
1082
+ data: extraData,
1083
+ onChange: handleExtraChange
1084
+ }
1085
+ )
1086
+ ] }),
1087
+ /* @__PURE__ */ jsxs(EditSidebar, { children: [
1088
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1089
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1090
+ id: getTranslation("organizations.common.details"),
1091
+ defaultMessage: "Details"
1092
+ }) }),
1093
+ /* @__PURE__ */ jsxs(Grid.Root, { gap: 3, gridCols: 2, children: [
1094
+ /* @__PURE__ */ jsx(Grid.Item, { col: 2, children: /* @__PURE__ */ jsxs(MetaItem, { children: [
1095
+ /* @__PURE__ */ jsx(MetaKey, { children: formatMessage({
1096
+ id: getTranslation("organizations.detail.meta.id"),
1097
+ defaultMessage: "Organization ID"
1098
+ }) }),
1099
+ /* @__PURE__ */ jsx(MonoChip, { children: org?.id })
1100
+ ] }) }),
1101
+ /* @__PURE__ */ jsx(Grid.Item, { col: 1, children: /* @__PURE__ */ jsxs(MetaItem, { children: [
1102
+ /* @__PURE__ */ jsx(MetaKey, { children: formatMessage({
1103
+ id: getTranslation("organizations.common.members"),
1104
+ defaultMessage: "Members"
1105
+ }) }),
1106
+ /* @__PURE__ */ jsx(MetaVal, { children: org?.memberCount ?? 0 })
1107
+ ] }) }),
1108
+ /* @__PURE__ */ jsx(Grid.Item, { col: 1, children: /* @__PURE__ */ jsxs(MetaItem, { children: [
1109
+ /* @__PURE__ */ jsx(MetaKey, { children: formatMessage({
1110
+ id: getTranslation("organizations.common.created"),
1111
+ defaultMessage: "Created"
1112
+ }) }),
1113
+ /* @__PURE__ */ jsx(MetaVal, { children: org?.createdAt ? new Date(org.createdAt).toLocaleDateString() : "—" })
1114
+ ] }) })
1115
+ ] })
1116
+ ] }),
1117
+ /* @__PURE__ */ jsx(
1118
+ EditViewSidePanels,
1119
+ {
1120
+ model: "plugin::better-auth.organization",
1121
+ documentId: strapiOrgQuery.data?.documentId,
1122
+ document: strapiOrgQuery.data ?? void 0
1123
+ }
1124
+ )
1125
+ ] })
1126
+ ] }) }),
1127
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "members", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, paddingTop: 6, children: [
1128
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1129
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1130
+ id: getTranslation("organizations.detail.members.add"),
1131
+ defaultMessage: "Add member"
1132
+ }) }),
1133
+ /* @__PURE__ */ jsxs(Grid.Root, { gap: 3, children: [
1134
+ /* @__PURE__ */ jsx(Grid.Item, { col: 8, children: /* @__PURE__ */ jsx(
1135
+ UserCombobox,
1136
+ {
1137
+ label: formatMessage({
1138
+ id: getTranslation("organizations.detail.members.user"),
1139
+ defaultMessage: "User"
1140
+ }),
1141
+ value: addUserId,
1142
+ onChange: setAddUserId
1143
+ }
1144
+ ) }),
1145
+ /* @__PURE__ */ jsx(Grid.Item, { col: 4, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
1146
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1147
+ id: getTranslation("organizations.common.role"),
1148
+ defaultMessage: "Role"
1149
+ }) }),
1150
+ /* @__PURE__ */ jsx(
1151
+ SingleSelect,
1152
+ {
1153
+ value: addRole,
1154
+ onChange: (role) => setAddRole(String(role)),
1155
+ "aria-label": formatMessage({
1156
+ id: getTranslation(
1157
+ "organizations.detail.members.roleLabel"
1158
+ ),
1159
+ defaultMessage: "Member role"
1160
+ }),
1161
+ children: ROLE_OPTIONS.map((option) => /* @__PURE__ */ jsx(
1162
+ SingleSelectOption,
1163
+ {
1164
+ value: option.value,
1165
+ children: formatMessage(option.label)
1166
+ },
1167
+ option.value
1168
+ ))
1169
+ }
1170
+ )
1171
+ ] }) })
1172
+ ] }),
1173
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1174
+ Button,
1175
+ {
1176
+ size: "S",
1177
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
1178
+ disabled: !addUserId,
1179
+ loading: addMemberMutation.isLoading,
1180
+ onClick: () => addMemberMutation.mutate(),
1181
+ "data-testid": "add-member-btn",
1182
+ children: formatMessage({
1183
+ id: getTranslation("organizations.detail.members.add"),
1184
+ defaultMessage: "Add member"
1185
+ })
1186
+ }
1187
+ ) })
1188
+ ] }),
1189
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1190
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage(
1191
+ {
1192
+ id: getTranslation("organizations.detail.tabs.members"),
1193
+ defaultMessage: "Members ({count})"
1194
+ },
1195
+ { count: members.length }
1196
+ ) }),
1197
+ membersQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : members.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
1198
+ id: getTranslation("organizations.detail.members.empty"),
1199
+ defaultMessage: "No members yet."
1200
+ }) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: members.map((member) => /* @__PURE__ */ jsxs(AccountRow, { "data-testid": "member-row", children: [
1201
+ /* @__PURE__ */ jsxs(
1202
+ Flex,
1203
+ {
1204
+ direction: "column",
1205
+ gap: 1,
1206
+ alignItems: "flex-start",
1207
+ flex: 1,
1208
+ children: [
1209
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: member.user?.name ?? formatMessage({
1210
+ id: getTranslation(
1211
+ "organizations.detail.members.unknown"
1212
+ ),
1213
+ defaultMessage: "Unknown"
1214
+ }) }),
1215
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: member.user?.email })
1216
+ ]
1217
+ }
1218
+ ),
1219
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
1220
+ /* @__PURE__ */ jsx(Field.Root, { style: { width: 110 }, children: /* @__PURE__ */ jsx(
1221
+ SingleSelect,
1222
+ {
1223
+ value: member.role,
1224
+ onChange: (role) => updateRoleMutation.mutate({
1225
+ memberId: member.id,
1226
+ role: String(role)
1227
+ }),
1228
+ size: "S",
1229
+ "aria-label": formatMessage({
1230
+ id: getTranslation(
1231
+ "organizations.detail.members.roleLabel"
1232
+ ),
1233
+ defaultMessage: "Member role"
1234
+ }),
1235
+ children: ROLE_OPTIONS.map((option) => /* @__PURE__ */ jsx(
1236
+ SingleSelectOption,
1237
+ {
1238
+ value: option.value,
1239
+ children: formatMessage(option.label)
1240
+ },
1241
+ option.value
1242
+ ))
1243
+ }
1244
+ ) }),
1245
+ /* @__PURE__ */ jsx(
1246
+ IconButton,
1247
+ {
1248
+ label: formatMessage({
1249
+ id: getTranslation(
1250
+ "organizations.detail.members.remove"
1251
+ ),
1252
+ defaultMessage: "Remove member"
1253
+ }),
1254
+ onClick: () => setConfirmRemoveMemberId(member.id),
1255
+ "data-testid": "remove-member-btn",
1256
+ children: /* @__PURE__ */ jsx(Trash, {})
1257
+ }
1258
+ )
1259
+ ] })
1260
+ ] }, member.id)) })
1261
+ ] })
1262
+ ] }) }),
1263
+ teamsEnabled && /* @__PURE__ */ jsx(Tabs.Content, { value: "teams", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, paddingTop: 6, children: [
1264
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1265
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1266
+ id: getTranslation("organizations.detail.teams.create"),
1267
+ defaultMessage: "Create team"
1268
+ }) }),
1269
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-end", children: [
1270
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
1271
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1272
+ id: getTranslation(
1273
+ "organizations.detail.teams.name.label"
1274
+ ),
1275
+ defaultMessage: "Team name"
1276
+ }) }),
1277
+ /* @__PURE__ */ jsx(
1278
+ TextInput,
1279
+ {
1280
+ value: newTeamName,
1281
+ onChange: (e) => setNewTeamName(e.target.value),
1282
+ placeholder: formatMessage({
1283
+ id: getTranslation(
1284
+ "organizations.detail.teams.name.placeholder"
1285
+ ),
1286
+ defaultMessage: "e.g. Engineering"
1287
+ })
1288
+ }
1289
+ )
1290
+ ] }) }),
1291
+ /* @__PURE__ */ jsx(
1292
+ Button,
1293
+ {
1294
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
1295
+ disabled: !newTeamName,
1296
+ loading: createTeamMutation.isLoading,
1297
+ onClick: () => createTeamMutation.mutate(),
1298
+ children: formatMessage({
1299
+ id: getTranslation(
1300
+ "organizations.detail.teams.createSubmit"
1301
+ ),
1302
+ defaultMessage: "Create"
1303
+ })
1304
+ }
1305
+ )
1306
+ ] })
1307
+ ] }),
1308
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1309
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage(
1310
+ {
1311
+ id: getTranslation("organizations.detail.tabs.teams"),
1312
+ defaultMessage: "Teams ({count})"
1313
+ },
1314
+ { count: teams.length }
1315
+ ) }),
1316
+ teamsQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : teams.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
1317
+ id: getTranslation("organizations.detail.teams.empty"),
1318
+ defaultMessage: "No teams yet."
1319
+ }) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: teams.map((team) => /* @__PURE__ */ jsx(
1320
+ TeamRow,
1321
+ {
1322
+ team,
1323
+ organizationId,
1324
+ onDelete: () => setConfirmDeleteTeamId(team.id)
1325
+ },
1326
+ team.id
1327
+ )) })
1328
+ ] })
1329
+ ] }) }),
1330
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "sso", children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 5, paddingTop: 6, children: /* @__PURE__ */ jsxs(FormSection, { children: [
1331
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1332
+ id: getTranslation("organizations.detail.sso.title"),
1333
+ defaultMessage: "SSO providers"
1334
+ }) }),
1335
+ ssoQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : ssoProviders.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
1336
+ id: getTranslation("organizations.detail.sso.empty"),
1337
+ defaultMessage: "No SSO providers configured."
1338
+ }) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: ssoProviders.map((provider) => /* @__PURE__ */ jsxs(
1339
+ AccountRow,
1340
+ {
1341
+ "data-testid": "sso-provider-row",
1342
+ children: [
1343
+ /* @__PURE__ */ jsxs(
1344
+ Flex,
1345
+ {
1346
+ direction: "column",
1347
+ gap: 1,
1348
+ alignItems: "flex-start",
1349
+ flex: 1,
1350
+ children: [
1351
+ /* @__PURE__ */ jsx(ProviderBadge, { children: provider.providerId }),
1352
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: provider.domain }),
1353
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage(
1354
+ {
1355
+ id: getTranslation(
1356
+ "organizations.detail.sso.issuer"
1357
+ ),
1358
+ defaultMessage: "Issuer: {issuer}"
1359
+ },
1360
+ { issuer: provider.issuer }
1361
+ ) })
1362
+ ]
1363
+ }
1364
+ ),
1365
+ /* @__PURE__ */ jsx(
1366
+ IconButton,
1367
+ {
1368
+ label: formatMessage({
1369
+ id: getTranslation(
1370
+ "organizations.detail.sso.delete"
1371
+ ),
1372
+ defaultMessage: "Delete SSO provider"
1373
+ }),
1374
+ onClick: () => setConfirmDeleteSsoId(provider.providerId),
1375
+ children: /* @__PURE__ */ jsx(Trash, {})
1376
+ }
1377
+ )
1378
+ ]
1379
+ },
1380
+ provider.id
1381
+ )) })
1382
+ ] }) }) }),
1383
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "invitations", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, paddingTop: 6, children: [
1384
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1385
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage({
1386
+ id: getTranslation(
1387
+ "organizations.detail.invitations.invite"
1388
+ ),
1389
+ defaultMessage: "Invite member by email"
1390
+ }) }),
1391
+ /* @__PURE__ */ jsxs(Grid.Root, { gap: 3, children: [
1392
+ /* @__PURE__ */ jsx(Grid.Item, { col: 8, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
1393
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1394
+ id: getTranslation(
1395
+ "organizations.detail.invitations.email.label"
1396
+ ),
1397
+ defaultMessage: "Email address"
1398
+ }) }),
1399
+ /* @__PURE__ */ jsx(
1400
+ TextInput,
1401
+ {
1402
+ type: "email",
1403
+ value: inviteEmail,
1404
+ onChange: (e) => setInviteEmail(e.target.value),
1405
+ placeholder: formatMessage({
1406
+ id: getTranslation(
1407
+ "organizations.detail.invitations.email.placeholder"
1408
+ ),
1409
+ defaultMessage: "user@example.com"
1410
+ })
1411
+ }
1412
+ )
1413
+ ] }) }),
1414
+ /* @__PURE__ */ jsx(Grid.Item, { col: 4, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
1415
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
1416
+ id: getTranslation("organizations.common.role"),
1417
+ defaultMessage: "Role"
1418
+ }) }),
1419
+ /* @__PURE__ */ jsx(
1420
+ SingleSelect,
1421
+ {
1422
+ value: inviteRole,
1423
+ onChange: (v) => setInviteRole(String(v)),
1424
+ "aria-label": formatMessage({
1425
+ id: getTranslation(
1426
+ "organizations.detail.invitations.roleLabel"
1427
+ ),
1428
+ defaultMessage: "Invite role"
1429
+ }),
1430
+ children: ROLE_OPTIONS.map((option) => /* @__PURE__ */ jsx(
1431
+ SingleSelectOption,
1432
+ {
1433
+ value: option.value,
1434
+ children: formatMessage(option.label)
1435
+ },
1436
+ option.value
1437
+ ))
1438
+ }
1439
+ )
1440
+ ] }) })
1441
+ ] }),
1442
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
1443
+ Button,
1444
+ {
1445
+ size: "S",
1446
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
1447
+ disabled: !inviteEmail,
1448
+ loading: inviteMemberMutation.isLoading,
1449
+ onClick: () => inviteMemberMutation.mutate(),
1450
+ children: formatMessage({
1451
+ id: getTranslation(
1452
+ "organizations.detail.invitations.send"
1453
+ ),
1454
+ defaultMessage: "Send invitation"
1455
+ })
1456
+ }
1457
+ ) })
1458
+ ] }),
1459
+ /* @__PURE__ */ jsxs(FormSection, { children: [
1460
+ /* @__PURE__ */ jsx(SectionLabel, { children: formatMessage(
1461
+ {
1462
+ id: getTranslation(
1463
+ "organizations.detail.tabs.invitations"
1464
+ ),
1465
+ defaultMessage: "Invitations ({count})"
1466
+ },
1467
+ { count: invitations.length }
1468
+ ) }),
1469
+ invitationsQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : invitations.length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
1470
+ id: getTranslation(
1471
+ "organizations.detail.invitations.empty"
1472
+ ),
1473
+ defaultMessage: "No invitations yet."
1474
+ }) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, children: invitations.map((inv) => {
1475
+ const isPending = inv.status === "pending";
1476
+ return /* @__PURE__ */ jsxs(AccountRow, { children: [
1477
+ /* @__PURE__ */ jsxs(
1478
+ Flex,
1479
+ {
1480
+ direction: "column",
1481
+ gap: 1,
1482
+ alignItems: "flex-start",
1483
+ flex: 1,
1484
+ children: [
1485
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: inv.user?.name ?? inv.email }),
1486
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage(
1487
+ {
1488
+ id: getTranslation(
1489
+ "organizations.detail.invitations.emailRole"
1490
+ ),
1491
+ defaultMessage: "{email} · role: {role}"
1492
+ },
1493
+ { email: inv.email, role: inv.role }
1494
+ ) }),
1495
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage(
1496
+ {
1497
+ id: getTranslation(
1498
+ "organizations.detail.invitations.expires"
1499
+ ),
1500
+ defaultMessage: "Expires {date}"
1501
+ },
1502
+ {
1503
+ date: new Date(
1504
+ inv.expiresAt
1505
+ ).toLocaleDateString()
1506
+ }
1507
+ ) })
1508
+ ]
1509
+ }
1510
+ ),
1511
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
1512
+ /* @__PURE__ */ jsx(
1513
+ Badge,
1514
+ {
1515
+ size: "S",
1516
+ variant: INVITATION_STATUS_VARIANT[inv.status] ?? "neutral",
1517
+ children: INVITATION_STATUS_LABEL[inv.status] ? formatMessage(
1518
+ INVITATION_STATUS_LABEL[inv.status]
1519
+ ) : inv.status
1520
+ }
1521
+ ),
1522
+ isPending && /* @__PURE__ */ jsxs(Fragment, { children: [
1523
+ /* @__PURE__ */ jsx(
1524
+ Button,
1525
+ {
1526
+ size: "S",
1527
+ variant: "secondary",
1528
+ loading: resendInvitationMutation.isLoading,
1529
+ onClick: () => resendInvitationMutation.mutate(inv.id),
1530
+ children: formatMessage({
1531
+ id: getTranslation(
1532
+ "organizations.detail.invitations.resend"
1533
+ ),
1534
+ defaultMessage: "Resend"
1535
+ })
1536
+ }
1537
+ ),
1538
+ /* @__PURE__ */ jsx(
1539
+ IconButton,
1540
+ {
1541
+ label: formatMessage({
1542
+ id: getTranslation(
1543
+ "organizations.detail.invitations.cancel"
1544
+ ),
1545
+ defaultMessage: "Cancel invitation"
1546
+ }),
1547
+ onClick: () => setConfirmCancelInvitationId(inv.id),
1548
+ children: /* @__PURE__ */ jsx(Trash, {})
1549
+ }
1550
+ )
1551
+ ] })
1552
+ ] })
1553
+ ] }, inv.id);
1554
+ }) })
1555
+ ] })
1556
+ ] }) })
1557
+ ] }),
1558
+ confirmRemoveMemberId && /* @__PURE__ */ jsx(
1559
+ ConfirmDialog,
1560
+ {
1561
+ title: formatMessage({
1562
+ id: getTranslation("organizations.detail.members.remove"),
1563
+ defaultMessage: "Remove member"
1564
+ }),
1565
+ message: formatMessage({
1566
+ id: getTranslation(
1567
+ "organizations.detail.members.confirmRemove.message"
1568
+ ),
1569
+ defaultMessage: "Are you sure you want to remove this member from the organization?"
1570
+ }),
1571
+ confirmLabel: formatMessage({
1572
+ id: getTranslation("organizations.common.remove"),
1573
+ defaultMessage: "Remove"
1574
+ }),
1575
+ loading: removeMemberMutation.isLoading,
1576
+ onConfirm: () => removeMemberMutation.mutate(confirmRemoveMemberId),
1577
+ onCancel: () => setConfirmRemoveMemberId(null)
1578
+ }
1579
+ ),
1580
+ confirmDeleteTeamId && /* @__PURE__ */ jsx(
1581
+ ConfirmDialog,
1582
+ {
1583
+ title: formatMessage({
1584
+ id: getTranslation("organizations.detail.teams.delete"),
1585
+ defaultMessage: "Delete team"
1586
+ }),
1587
+ message: formatMessage({
1588
+ id: getTranslation(
1589
+ "organizations.detail.teams.confirmDelete.message"
1590
+ ),
1591
+ defaultMessage: "Are you sure you want to delete this team? All team members will be removed. This action cannot be undone."
1592
+ }),
1593
+ confirmLabel: formatMessage({
1594
+ id: getTranslation("organizations.common.delete"),
1595
+ defaultMessage: "Delete"
1596
+ }),
1597
+ loading: deleteTeamMutation.isLoading,
1598
+ onConfirm: () => deleteTeamMutation.mutate(confirmDeleteTeamId),
1599
+ onCancel: () => setConfirmDeleteTeamId(null)
1600
+ }
1601
+ ),
1602
+ confirmDeleteSsoId && /* @__PURE__ */ jsx(
1603
+ ConfirmDialog,
1604
+ {
1605
+ title: formatMessage({
1606
+ id: getTranslation("organizations.detail.sso.delete"),
1607
+ defaultMessage: "Delete SSO provider"
1608
+ }),
1609
+ message: formatMessage({
1610
+ id: getTranslation(
1611
+ "organizations.detail.sso.confirmDelete.message"
1612
+ ),
1613
+ defaultMessage: "Are you sure you want to delete this SSO provider? Members using this provider will need to authenticate differently."
1614
+ }),
1615
+ confirmLabel: formatMessage({
1616
+ id: getTranslation("organizations.common.delete"),
1617
+ defaultMessage: "Delete"
1618
+ }),
1619
+ loading: deleteSsoMutation.isLoading,
1620
+ onConfirm: () => deleteSsoMutation.mutate(confirmDeleteSsoId),
1621
+ onCancel: () => setConfirmDeleteSsoId(null)
1622
+ }
1623
+ ),
1624
+ confirmCancelInvitationId && /* @__PURE__ */ jsx(
1625
+ ConfirmDialog,
1626
+ {
1627
+ title: formatMessage({
1628
+ id: getTranslation("organizations.detail.invitations.cancel"),
1629
+ defaultMessage: "Cancel invitation"
1630
+ }),
1631
+ message: formatMessage({
1632
+ id: getTranslation(
1633
+ "organizations.detail.invitations.confirmCancel.message"
1634
+ ),
1635
+ defaultMessage: "Are you sure you want to cancel this invitation? The invite link will no longer work."
1636
+ }),
1637
+ confirmLabel: formatMessage({
1638
+ id: getTranslation("organizations.detail.invitations.cancel"),
1639
+ defaultMessage: "Cancel invitation"
1640
+ }),
1641
+ loading: cancelInvitationMutation.isLoading,
1642
+ onConfirm: () => cancelInvitationMutation.mutate(confirmCancelInvitationId),
1643
+ onCancel: () => setConfirmCancelInvitationId(null)
1644
+ }
1645
+ )
1646
+ ]
1647
+ }
1648
+ );
1649
+ }
1650
+ function TeamRow({
1651
+ team,
1652
+ organizationId,
1653
+ onDelete
1654
+ }) {
1655
+ const { formatMessage } = useIntl();
1656
+ const qc = useQueryClient();
1657
+ const [expanded, setExpanded] = useState(false);
1658
+ const [confirmRemoveTeamMemberId, setConfirmRemoveTeamMemberId] = useState(null);
1659
+ const teamMembersQuery = useQuery({
1660
+ queryKey: ["dash-team-members", organizationId, team.id],
1661
+ queryFn: async () => {
1662
+ const result = await client.dash.organization[
1663
+ // @ts-expect-error
1664
+ organizationId
1665
+ ].teams[team.id].members(
1666
+ { params: { orgId: organizationId, teamId: team.id } },
1667
+ withContext({ organizationId }, getAuthHeaders())
1668
+ );
1669
+ if (result.error)
1670
+ throw new Error(
1671
+ result.error.message ?? formatMessage({
1672
+ id: getTranslation("organizations.common.failed"),
1673
+ defaultMessage: "Failed"
1674
+ })
1675
+ );
1676
+ return result.data ?? [];
1677
+ },
1678
+ enabled: expanded
1679
+ });
1680
+ const [addUserId, setAddUserId] = useState("");
1681
+ const addTeamMemberMutation = useMutation({
1682
+ mutationFn: async () => {
1683
+ const result = await client.dash.organization.addTeamMember(
1684
+ { teamId: team.id, userId: addUserId },
1685
+ withContext({ organizationId }, getAuthHeaders())
1686
+ );
1687
+ if (result.error)
1688
+ throw new Error(
1689
+ result.error.message ?? formatMessage({
1690
+ id: getTranslation("organizations.common.failed"),
1691
+ defaultMessage: "Failed"
1692
+ })
1693
+ );
1694
+ return result.data;
1695
+ },
1696
+ onSuccess: () => {
1697
+ qc.invalidateQueries({
1698
+ queryKey: ["dash-team-members", organizationId, team.id]
1699
+ });
1700
+ setAddUserId("");
1701
+ }
1702
+ });
1703
+ const removeTeamMemberMutation = useMutation({
1704
+ mutationFn: async (userId) => {
1705
+ const result = await client.dash.organization.removeTeamMember(
1706
+ { teamId: team.id, userId },
1707
+ withContext({ organizationId }, getAuthHeaders())
1708
+ );
1709
+ if (result.error)
1710
+ throw new Error(
1711
+ result.error.message ?? formatMessage({
1712
+ id: getTranslation("organizations.common.failed"),
1713
+ defaultMessage: "Failed"
1714
+ })
1715
+ );
1716
+ },
1717
+ onSuccess: () => {
1718
+ setConfirmRemoveTeamMemberId(null);
1719
+ qc.invalidateQueries({
1720
+ queryKey: ["dash-team-members", organizationId, team.id]
1721
+ });
1722
+ }
1723
+ });
1724
+ return /* @__PURE__ */ jsxs(Box, { width: "100%", children: [
1725
+ /* @__PURE__ */ jsx(
1726
+ Accordion.Root,
1727
+ {
1728
+ value: expanded ? team.id : "",
1729
+ onValueChange: (v) => setExpanded(v === team.id),
1730
+ collapsible: true,
1731
+ children: /* @__PURE__ */ jsxs(Accordion.Item, { value: team.id, "data-testid": "team-row", children: [
1732
+ /* @__PURE__ */ jsxs(Accordion.Header, { children: [
1733
+ /* @__PURE__ */ jsx(
1734
+ Accordion.Trigger,
1735
+ {
1736
+ description: formatMessage(
1737
+ {
1738
+ id: getTranslation("organizations.detail.teams.memberCount"),
1739
+ defaultMessage: "{count, plural, =-1 {— members} one {# member} other {# members}}"
1740
+ },
1741
+ { count: teamMembersQuery.data?.length ?? -1 }
1742
+ ),
1743
+ children: team.name
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ jsx(Accordion.Actions, { children: /* @__PURE__ */ jsx(
1747
+ IconButton,
1748
+ {
1749
+ label: formatMessage({
1750
+ id: getTranslation("organizations.detail.teams.delete"),
1751
+ defaultMessage: "Delete team"
1752
+ }),
1753
+ variant: "ghost",
1754
+ onClick: onDelete,
1755
+ children: /* @__PURE__ */ jsx(Trash, {})
1756
+ }
1757
+ ) })
1758
+ ] }),
1759
+ /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 3, padding: 4, children: [
1760
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-end", children: [
1761
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(
1762
+ UserCombobox,
1763
+ {
1764
+ label: formatMessage({
1765
+ id: getTranslation(
1766
+ "organizations.detail.teams.addMember"
1767
+ ),
1768
+ defaultMessage: "Add member to team"
1769
+ }),
1770
+ value: addUserId,
1771
+ onChange: setAddUserId
1772
+ }
1773
+ ) }),
1774
+ /* @__PURE__ */ jsx(
1775
+ Button,
1776
+ {
1777
+ size: "S",
1778
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
1779
+ disabled: !addUserId,
1780
+ loading: addTeamMemberMutation.isLoading,
1781
+ onClick: () => addTeamMemberMutation.mutate(),
1782
+ children: formatMessage({
1783
+ id: getTranslation(
1784
+ "organizations.detail.teams.addMemberSubmit"
1785
+ ),
1786
+ defaultMessage: "Add"
1787
+ })
1788
+ }
1789
+ )
1790
+ ] }),
1791
+ teamMembersQuery.isLoading ? /* @__PURE__ */ jsx(InlineLoader, {}) : (teamMembersQuery.data ?? []).length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: formatMessage({
1792
+ id: getTranslation(
1793
+ "organizations.detail.teams.membersEmpty"
1794
+ ),
1795
+ defaultMessage: "No members in this team."
1796
+ }) }) : /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: (teamMembersQuery.data ?? []).map((tm) => /* @__PURE__ */ jsxs(AccountRow, { children: [
1797
+ /* @__PURE__ */ jsxs(
1798
+ Flex,
1799
+ {
1800
+ direction: "column",
1801
+ gap: 1,
1802
+ alignItems: "flex-start",
1803
+ flex: 1,
1804
+ children: [
1805
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: tm.user?.name ?? tm.userId }),
1806
+ tm.user?.email && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: tm.user.email })
1807
+ ]
1808
+ }
1809
+ ),
1810
+ /* @__PURE__ */ jsx(
1811
+ IconButton,
1812
+ {
1813
+ label: formatMessage({
1814
+ id: getTranslation(
1815
+ "organizations.detail.teams.removeMember"
1816
+ ),
1817
+ defaultMessage: "Remove from team"
1818
+ }),
1819
+ onClick: () => setConfirmRemoveTeamMemberId(tm.userId),
1820
+ children: /* @__PURE__ */ jsx(Trash, {})
1821
+ }
1822
+ )
1823
+ ] }, tm.id)) })
1824
+ ] }) })
1825
+ ] })
1826
+ }
1827
+ ),
1828
+ confirmRemoveTeamMemberId && /* @__PURE__ */ jsx(
1829
+ ConfirmDialog,
1830
+ {
1831
+ title: formatMessage({
1832
+ id: getTranslation("organizations.detail.teams.removeMember"),
1833
+ defaultMessage: "Remove from team"
1834
+ }),
1835
+ message: formatMessage({
1836
+ id: getTranslation(
1837
+ "organizations.detail.teams.confirmRemoveMember.message"
1838
+ ),
1839
+ defaultMessage: "Are you sure you want to remove this member from the team?"
1840
+ }),
1841
+ confirmLabel: formatMessage({
1842
+ id: getTranslation("organizations.common.remove"),
1843
+ defaultMessage: "Remove"
1844
+ }),
1845
+ loading: removeTeamMemberMutation.isLoading,
1846
+ onConfirm: () => removeTeamMemberMutation.mutate(confirmRemoveTeamMemberId),
1847
+ onCancel: () => setConfirmRemoveTeamMemberId(null)
1848
+ }
1849
+ )
1850
+ ] });
1851
+ }
1852
+ const PAGE_SIZE = 25;
1853
+ function OrganizationsPage({ teamsEnabled }) {
1854
+ const { formatMessage } = useIntl();
1855
+ const rbac = useRBAC(PERMISSIONS.organization);
1856
+ const qc = useQueryClient();
1857
+ const { toggleNotification } = useNotification();
1858
+ const [page, setPage] = useState(1);
1859
+ const [search, setSearch] = useState("");
1860
+ const [searchInput, setSearchInput] = useState("");
1861
+ const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
1862
+ const [showCreate, setShowCreate] = useState(false);
1863
+ const [detailOrgId, setDetailOrgId] = useState(null);
1864
+ const [confirmDelete, setConfirmDelete] = useState(null);
1865
+ const [confirmDeleteMany, setConfirmDeleteMany] = useState(false);
1866
+ const offset = (page - 1) * PAGE_SIZE;
1867
+ const orgsQuery = useQuery({
1868
+ queryKey: ["dash-organizations", page, search],
1869
+ queryFn: async () => {
1870
+ const result = await client.dash.listOrganizations({
1871
+ query: {
1872
+ limit: PAGE_SIZE,
1873
+ offset,
1874
+ sortBy: "createdAt",
1875
+ sortOrder: "desc",
1876
+ ...search ? { search } : {}
1877
+ }
1878
+ });
1879
+ if (result.error)
1880
+ throw new Error(
1881
+ result.error.message ?? formatMessage({
1882
+ id: getTranslation("organizations.list.error.load"),
1883
+ defaultMessage: "Failed to load organizations"
1884
+ })
1885
+ );
1886
+ return result.data;
1887
+ },
1888
+ keepPreviousData: true
1889
+ });
1890
+ const deleteMutation = useMutation({
1891
+ mutationFn: async (organizationId) => {
1892
+ const result = await client.dash.organization.delete(
1893
+ { organizationId },
1894
+ withContext({ organizationId }, getAuthHeaders())
1895
+ );
1896
+ if (result.error)
1897
+ throw new Error(
1898
+ result.error.message ?? formatMessage({
1899
+ id: getTranslation("organizations.common.deleteFailed"),
1900
+ defaultMessage: "Delete failed"
1901
+ })
1902
+ );
1903
+ },
1904
+ onSuccess: () => {
1905
+ setConfirmDelete(null);
1906
+ qc.invalidateQueries({ queryKey: ["dash-organizations"] });
1907
+ toggleNotification({
1908
+ type: "success",
1909
+ message: formatMessage({
1910
+ id: getTranslation("organizations.list.notification.deleted"),
1911
+ defaultMessage: "Organization deleted"
1912
+ })
1913
+ });
1914
+ },
1915
+ onError: (err) => {
1916
+ toggleNotification({
1917
+ type: "danger",
1918
+ message: err.message ?? formatMessage({
1919
+ id: getTranslation("organizations.list.notification.deleteError"),
1920
+ defaultMessage: "Failed to delete organization"
1921
+ })
1922
+ });
1923
+ }
1924
+ });
1925
+ const deleteManyMutation = useMutation({
1926
+ mutationFn: async (organizationIds) => {
1927
+ const result = await client.dash.organization.deleteMany(
1928
+ {},
1929
+ withContext({ organizationIds }, getAuthHeaders())
1930
+ );
1931
+ if (result.error)
1932
+ throw new Error(
1933
+ result.error.message ?? formatMessage({
1934
+ id: getTranslation("organizations.common.deleteFailed"),
1935
+ defaultMessage: "Delete failed"
1936
+ })
1937
+ );
1938
+ return result.data;
1939
+ },
1940
+ onSuccess: (_data, organizationIds) => {
1941
+ setConfirmDeleteMany(false);
1942
+ setSelected(/* @__PURE__ */ new Set());
1943
+ qc.invalidateQueries({ queryKey: ["dash-organizations"] });
1944
+ toggleNotification({
1945
+ type: "success",
1946
+ message: formatMessage(
1947
+ {
1948
+ id: getTranslation("organizations.list.notification.deletedMany"),
1949
+ defaultMessage: "{count, plural, one {# organization} other {# organizations}} deleted"
1950
+ },
1951
+ { count: organizationIds.length }
1952
+ )
1953
+ });
1954
+ },
1955
+ onError: (err) => {
1956
+ toggleNotification({
1957
+ type: "danger",
1958
+ message: err.message ?? formatMessage({
1959
+ id: getTranslation(
1960
+ "organizations.list.notification.deleteManyError"
1961
+ ),
1962
+ defaultMessage: "Failed to delete organizations"
1963
+ })
1964
+ });
1965
+ }
1966
+ });
1967
+ const orgs = orgsQuery.data && "organizations" in orgsQuery.data ? orgsQuery.data.organizations : [];
1968
+ const total = orgsQuery.data && "total" in orgsQuery.data ? orgsQuery.data.total : 0;
1969
+ const pageCount = Math.ceil(total / PAGE_SIZE);
1970
+ const allSelected = orgs.length > 0 && orgs.every((o) => selected.has(o.id));
1971
+ const someSelected = selected.size > 0;
1972
+ const toggleSelect = (id) => {
1973
+ setSelected((prev) => {
1974
+ const next = new Set(prev);
1975
+ if (next.has(id)) next.delete(id);
1976
+ else next.add(id);
1977
+ return next;
1978
+ });
1979
+ };
1980
+ const handleSelectAll = () => {
1981
+ if (allSelected) setSelected(/* @__PURE__ */ new Set());
1982
+ else setSelected(new Set(orgs.map((o) => o.id)));
1983
+ };
1984
+ const handleSearch = (e) => {
1985
+ e.preventDefault();
1986
+ setSearch(searchInput);
1987
+ setPage(1);
1988
+ };
1989
+ const colCount = rbac.allowedActions.canDelete ? 6 : 5;
1990
+ return /* @__PURE__ */ jsxs(Main, { "data-testid": "organizations-page", children: [
1991
+ /* @__PURE__ */ jsx(
1992
+ Layouts.Header,
1993
+ {
1994
+ title: formatMessage({
1995
+ id: getTranslation("organizations.list.header.title"),
1996
+ defaultMessage: "Organizations"
1997
+ }),
1998
+ subtitle: formatMessage(
1999
+ {
2000
+ id: getTranslation("organizations.list.header.subtitle"),
2001
+ defaultMessage: "{total} total"
2002
+ },
2003
+ { total: total.toLocaleString() }
2004
+ ),
2005
+ primaryAction: rbac.allowedActions.canCreate && /* @__PURE__ */ jsx(
2006
+ Button,
2007
+ {
2008
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
2009
+ onClick: () => setShowCreate(true),
2010
+ "data-testid": "create-org-btn",
2011
+ children: formatMessage({
2012
+ id: getTranslation("organizations.common.createOrganization"),
2013
+ defaultMessage: "Create organization"
2014
+ })
2015
+ }
2016
+ )
2017
+ }
2018
+ ),
2019
+ /* @__PURE__ */ jsx(
2020
+ Layouts.Action,
2021
+ {
2022
+ startActions: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2023
+ /* @__PURE__ */ jsx(SearchForm, { onSubmit: handleSearch, children: /* @__PURE__ */ jsx(
2024
+ Searchbar,
2025
+ {
2026
+ clearLabel: formatMessage({
2027
+ id: getTranslation("organizations.list.search.clear"),
2028
+ defaultMessage: "Clear"
2029
+ }),
2030
+ name: "search",
2031
+ placeholder: formatMessage({
2032
+ id: getTranslation("organizations.list.search.placeholder"),
2033
+ defaultMessage: "Search organizations…"
2034
+ }),
2035
+ value: searchInput,
2036
+ onChange: (e) => setSearchInput(e.target.value),
2037
+ onClear: () => {
2038
+ setSearchInput("");
2039
+ setSearch("");
2040
+ setPage(1);
2041
+ },
2042
+ children: formatMessage({
2043
+ id: getTranslation("organizations.list.search.label"),
2044
+ defaultMessage: "Search organizations"
2045
+ })
2046
+ }
2047
+ ) }),
2048
+ someSelected && rbac.allowedActions.canDelete && /* @__PURE__ */ jsx(
2049
+ Button,
2050
+ {
2051
+ variant: "danger-light",
2052
+ size: "S",
2053
+ onClick: () => setConfirmDeleteMany(true),
2054
+ "data-testid": "delete-selected-orgs-btn",
2055
+ children: formatMessage(
2056
+ {
2057
+ id: getTranslation("organizations.list.deleteSelected"),
2058
+ defaultMessage: "Delete {count} selected"
2059
+ },
2060
+ { count: selected.size }
2061
+ )
2062
+ }
2063
+ )
2064
+ ] })
2065
+ }
2066
+ ),
2067
+ /* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2068
+ orgsQuery.isError && /* @__PURE__ */ jsx(
2069
+ Alert,
2070
+ {
2071
+ closeLabel: formatMessage({
2072
+ id: getTranslation("organizations.common.close"),
2073
+ defaultMessage: "Close"
2074
+ }),
2075
+ title: formatMessage({
2076
+ id: getTranslation("organizations.list.error.title"),
2077
+ defaultMessage: "Error"
2078
+ }),
2079
+ variant: "danger",
2080
+ children: orgsQuery.error instanceof Error ? orgsQuery.error.message : formatMessage({
2081
+ id: getTranslation("organizations.common.errorOccurred"),
2082
+ defaultMessage: "An error occurred"
2083
+ })
2084
+ }
2085
+ ),
2086
+ orgsQuery.isLoading ? /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsx(Loader, { children: formatMessage({
2087
+ id: getTranslation("organizations.list.loading"),
2088
+ defaultMessage: "Loading organizations…"
2089
+ }) }) }) : /* @__PURE__ */ jsxs(Table, { colCount, rowCount: orgs.length + 1, children: [
2090
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
2091
+ rbac.allowedActions.canDelete && /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
2092
+ Checkbox,
2093
+ {
2094
+ checked: allSelected ? true : someSelected ? "indeterminate" : false,
2095
+ onCheckedChange: handleSelectAll,
2096
+ "aria-label": formatMessage({
2097
+ id: getTranslation(
2098
+ "organizations.list.table.selectAll"
2099
+ ),
2100
+ defaultMessage: "Select all"
2101
+ })
2102
+ }
2103
+ ) }),
2104
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: formatMessage({
2105
+ id: getTranslation("organizations.common.name"),
2106
+ defaultMessage: "Name"
2107
+ }) }) }),
2108
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: formatMessage({
2109
+ id: getTranslation("organizations.common.slug"),
2110
+ defaultMessage: "Slug"
2111
+ }) }) }),
2112
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: formatMessage({
2113
+ id: getTranslation("organizations.common.members"),
2114
+ defaultMessage: "Members"
2115
+ }) }) }),
2116
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: formatMessage({
2117
+ id: getTranslation("organizations.common.created"),
2118
+ defaultMessage: "Created"
2119
+ }) }) }),
2120
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(VisuallyHidden, { children: formatMessage({
2121
+ id: getTranslation("organizations.list.table.actions"),
2122
+ defaultMessage: "Actions"
2123
+ }) }) })
2124
+ ] }) }),
2125
+ /* @__PURE__ */ jsx(Tbody, { children: orgs.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: colCount, children: /* @__PURE__ */ jsx(
2126
+ Flex,
2127
+ {
2128
+ justifyContent: "center",
2129
+ padding: 8,
2130
+ "data-testid": "orgs-empty",
2131
+ children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: search ? formatMessage(
2132
+ {
2133
+ id: getTranslation(
2134
+ "organizations.list.empty.search"
2135
+ ),
2136
+ defaultMessage: 'No organizations matching "{search}"'
2137
+ },
2138
+ { search }
2139
+ ) : formatMessage({
2140
+ id: getTranslation(
2141
+ "organizations.list.empty.default"
2142
+ ),
2143
+ defaultMessage: "No organizations found"
2144
+ }) })
2145
+ }
2146
+ ) }) }) : orgs.map((org) => /* @__PURE__ */ jsxs(Tr, { "data-testid": "org-row", children: [
2147
+ rbac.allowedActions.canDelete && /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
2148
+ Checkbox,
2149
+ {
2150
+ checked: selected.has(org.id),
2151
+ onCheckedChange: () => toggleSelect(org.id),
2152
+ "aria-label": formatMessage(
2153
+ {
2154
+ id: getTranslation(
2155
+ "organizations.list.table.selectRow"
2156
+ ),
2157
+ defaultMessage: "Select {name}"
2158
+ },
2159
+ { name: org.name }
2160
+ )
2161
+ }
2162
+ ) }),
2163
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
2164
+ /* @__PURE__ */ jsx(Avatar, { name: org.name, src: org.logo, size: 28 }),
2165
+ /* @__PURE__ */ jsx(
2166
+ Typography,
2167
+ {
2168
+ fontWeight: "semiBold",
2169
+ textColor: "neutral800",
2170
+ children: org.name
2171
+ }
2172
+ )
2173
+ ] }) }),
2174
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Code, { variant: "pi", textColor: "neutral600", children: org.slug }) }),
2175
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { size: "S", children: org.memberCount }) }),
2176
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: new Date(org.createdAt).toLocaleDateString() }) }),
2177
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { gap: 1, justifyContent: "flex-end", children: [
2178
+ rbac.allowedActions.canUpdate && /* @__PURE__ */ jsx(
2179
+ IconButton,
2180
+ {
2181
+ label: formatMessage({
2182
+ id: getTranslation(
2183
+ "organizations.list.table.edit"
2184
+ ),
2185
+ defaultMessage: "Edit organization"
2186
+ }),
2187
+ variant: "ghost",
2188
+ onClick: () => setDetailOrgId(org.id),
2189
+ "data-testid": "edit-org-btn",
2190
+ children: /* @__PURE__ */ jsx(Pencil, {})
2191
+ }
2192
+ ),
2193
+ rbac.allowedActions.canDelete && /* @__PURE__ */ jsx(
2194
+ IconButton,
2195
+ {
2196
+ label: formatMessage({
2197
+ id: getTranslation(
2198
+ "organizations.common.deleteOrganization"
2199
+ ),
2200
+ defaultMessage: "Delete organization"
2201
+ }),
2202
+ variant: "ghost",
2203
+ onClick: () => setConfirmDelete(org.id),
2204
+ "data-testid": "delete-org-btn",
2205
+ children: /* @__PURE__ */ jsx(Trash, {})
2206
+ }
2207
+ )
2208
+ ] }) })
2209
+ ] }, org.id)) })
2210
+ ] }),
2211
+ pageCount > 1 && /* @__PURE__ */ jsxs(Flex, { justifyContent: "flex-end", gap: 2, children: [
2212
+ /* @__PURE__ */ jsx(
2213
+ Button,
2214
+ {
2215
+ variant: "tertiary",
2216
+ size: "S",
2217
+ disabled: page === 1,
2218
+ onClick: () => setPage((p) => p - 1),
2219
+ children: formatMessage({
2220
+ id: getTranslation("organizations.list.pagination.previous"),
2221
+ defaultMessage: "Previous"
2222
+ })
2223
+ }
2224
+ ),
2225
+ /* @__PURE__ */ jsx(
2226
+ Button,
2227
+ {
2228
+ variant: "tertiary",
2229
+ size: "S",
2230
+ disabled: page >= pageCount,
2231
+ onClick: () => setPage((p) => p + 1),
2232
+ children: formatMessage({
2233
+ id: getTranslation("organizations.list.pagination.next"),
2234
+ defaultMessage: "Next"
2235
+ })
2236
+ }
2237
+ )
2238
+ ] })
2239
+ ] }) }),
2240
+ rbac.allowedActions.canCreate && showCreate && /* @__PURE__ */ jsx(
2241
+ CreateOrganizationDialog,
2242
+ {
2243
+ teamsEnabled,
2244
+ onClose: () => setShowCreate(false)
2245
+ }
2246
+ ),
2247
+ rbac.allowedActions.canUpdate && detailOrgId && /* @__PURE__ */ jsx(
2248
+ OrganizationDetail,
2249
+ {
2250
+ organizationId: detailOrgId,
2251
+ teamsEnabled,
2252
+ onClose: () => setDetailOrgId(null)
2253
+ }
2254
+ ),
2255
+ rbac.allowedActions.canDelete && confirmDelete && /* @__PURE__ */ jsx(
2256
+ ConfirmDialog,
2257
+ {
2258
+ title: formatMessage({
2259
+ id: getTranslation("organizations.common.deleteOrganization"),
2260
+ defaultMessage: "Delete organization"
2261
+ }),
2262
+ message: formatMessage({
2263
+ id: getTranslation("organizations.list.confirmDelete.message"),
2264
+ defaultMessage: "Are you sure you want to delete this organization? All members and teams will be removed. This action cannot be undone."
2265
+ }),
2266
+ confirmLabel: formatMessage({
2267
+ id: getTranslation("organizations.common.delete"),
2268
+ defaultMessage: "Delete"
2269
+ }),
2270
+ loading: deleteMutation.isLoading,
2271
+ onConfirm: () => deleteMutation.mutate(confirmDelete),
2272
+ onCancel: () => setConfirmDelete(null)
2273
+ }
2274
+ ),
2275
+ rbac.allowedActions.canDelete && confirmDeleteMany && /* @__PURE__ */ jsx(
2276
+ ConfirmDialog,
2277
+ {
2278
+ title: formatMessage(
2279
+ {
2280
+ id: getTranslation("organizations.list.confirmDeleteMany.title"),
2281
+ defaultMessage: "Delete {count, plural, one {# organization} other {# organizations}}"
2282
+ },
2283
+ { count: selected.size }
2284
+ ),
2285
+ message: formatMessage(
2286
+ {
2287
+ id: getTranslation(
2288
+ "organizations.list.confirmDeleteMany.message"
2289
+ ),
2290
+ defaultMessage: "Are you sure you want to delete {count, plural, one {# organization} other {# organizations}}? This action cannot be undone."
2291
+ },
2292
+ { count: selected.size }
2293
+ ),
2294
+ confirmLabel: formatMessage({
2295
+ id: getTranslation("organizations.list.confirmDeleteMany.confirm"),
2296
+ defaultMessage: "Delete all"
2297
+ }),
2298
+ loading: deleteManyMutation.isLoading,
2299
+ onConfirm: () => deleteManyMutation.mutate([...selected]),
2300
+ onCancel: () => setConfirmDeleteMany(false)
2301
+ }
2302
+ )
2303
+ ] });
2304
+ }
2305
+ function ProtectedOrganizationsPage() {
2306
+ const { data: organizationOptions } = useOrganizationOptions();
2307
+ const teamsEnabled = organizationOptions?.teamsEnabled ?? false;
2308
+ return /* @__PURE__ */ jsx(
2309
+ Page.Protect,
2310
+ {
2311
+ permissions: PERMISSIONS.organization.filter(
2312
+ (p) => p.action === `plugin::${PLUGIN_ID}.organization.read`
2313
+ ),
2314
+ children: /* @__PURE__ */ jsx(OrganizationsPage, { teamsEnabled })
2315
+ }
2316
+ );
2317
+ }
2318
+ export {
2319
+ OrganizationsPage,
2320
+ ProtectedOrganizationsPage as default
2321
+ };