@jskit-ai/users-web 0.1.53 → 0.1.54

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 (70) hide show
  1. package/package.descriptor.mjs +15 -53
  2. package/package.json +16 -11
  3. package/src/client/account-settings/sections.js +74 -0
  4. package/src/client/composables/account-settings/accountSettingsRuntimeHelpers.js +2 -38
  5. package/src/client/composables/crud/crudLookupFieldRuntime.js +2 -2
  6. package/src/client/composables/internal/crudListParentTitleSupport.js +1 -1
  7. package/src/client/composables/internal/useOperationScope.js +12 -12
  8. package/src/client/composables/records/useAddEdit.js +2 -2
  9. package/src/client/composables/records/useList.js +3 -3
  10. package/src/client/composables/records/useView.js +2 -2
  11. package/src/client/composables/support/scopeHelpers.js +19 -19
  12. package/src/client/composables/useAccess.js +3 -3
  13. package/src/client/composables/useAccountSettingsRuntime.js +8 -156
  14. package/src/client/composables/useCommand.js +2 -2
  15. package/src/client/composables/useCrudListParentTitle.js +2 -2
  16. package/src/client/composables/usePaths.js +50 -38
  17. package/src/client/composables/useScopeRuntime.js +55 -27
  18. package/src/client/composables/useSurfaceRouteContext.js +1 -7
  19. package/src/client/index.js +0 -1
  20. package/src/client/lib/bootstrap.js +0 -63
  21. package/src/client/lib/httpClient.js +2 -59
  22. package/src/client/lib/theme.js +12 -189
  23. package/src/client/providers/UsersWebClientProvider.js +2 -25
  24. package/src/client/providers/bootUsersWebClientProvider.js +28 -0
  25. package/src/shared/toolsOutletContracts.js +1 -8
  26. package/templates/src/components/account/settings/AccountSettingsClientElement.vue +33 -21
  27. package/test/accountSettingsSections.test.js +79 -0
  28. package/test/exportsContract.test.js +2 -2
  29. package/test/scopeHelpers.test.js +6 -6
  30. package/test/settingsPlacementContract.test.js +4 -11
  31. package/test/theme.test.js +0 -56
  32. package/src/client/components/MembersAdminClientElement.vue +0 -400
  33. package/src/client/components/UsersProfileSurfaceSwitchMenuItem.vue +0 -39
  34. package/src/client/components/UsersWorkspaceMembersMenuItem.vue +0 -36
  35. package/src/client/components/UsersWorkspacePermissionMenuItem.vue +0 -90
  36. package/src/client/components/UsersWorkspaceSelector.vue +0 -248
  37. package/src/client/components/UsersWorkspaceSettingsMenuItem.vue +0 -39
  38. package/src/client/components/UsersWorkspaceToolsWidget.vue +0 -12
  39. package/src/client/components/WorkspaceMembersClientElement.vue +0 -655
  40. package/src/client/components/WorkspaceProfileClientElement.vue +0 -116
  41. package/src/client/components/WorkspaceSettingsClientElement.vue +0 -102
  42. package/src/client/components/WorkspaceSettingsFieldsClientElement.vue +0 -265
  43. package/src/client/components/WorkspacesClientElement.vue +0 -509
  44. package/src/client/composables/account-settings/accountSettingsInvitesRuntime.js +0 -88
  45. package/src/client/composables/useBootstrapQuery.js +0 -52
  46. package/src/client/composables/useWorkspaceRouteContext.js +0 -28
  47. package/src/client/composables/useWorkspaceSurfaceId.js +0 -43
  48. package/src/client/lib/menuIcons.js +0 -201
  49. package/src/client/lib/profileSurfaceMenuLinks.js +0 -142
  50. package/src/client/lib/surfaceAccessPolicy.js +0 -350
  51. package/src/client/lib/workspaceLinkResolver.js +0 -207
  52. package/src/client/lib/workspaceSurfaceContext.js +0 -82
  53. package/src/client/lib/workspaceSurfacePaths.js +0 -163
  54. package/src/client/providers/UsersWorkspacesClientProvider.js +0 -24
  55. package/src/client/runtime/bootstrapPlacementRouteGuards.js +0 -371
  56. package/src/client/runtime/bootstrapPlacementRuntime.js +0 -463
  57. package/src/client/runtime/bootstrapPlacementRuntimeConstants.js +0 -28
  58. package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +0 -147
  59. package/src/client/support/menuLinkTarget.js +0 -93
  60. package/src/client/support/realtimeWorkspace.js +0 -21
  61. package/src/client/support/runtimeNormalization.js +0 -27
  62. package/src/client/support/workspaceQueryKeys.js +0 -15
  63. package/templates/src/components/account/settings/AccountSettingsInvitesSection.vue +0 -77
  64. package/test/bootstrapPlacementRuntime.test.js +0 -1095
  65. package/test/menuIcons.test.js +0 -34
  66. package/test/menuLinkTarget.test.js +0 -116
  67. package/test/profileSurfaceMenuLinks.test.js +0 -208
  68. package/test/surfaceAccessPolicy.test.js +0 -129
  69. package/test/workspaceLinkResolver.test.js +0 -61
  70. package/test/workspaceSurfacePaths.test.js +0 -39
@@ -1,655 +0,0 @@
1
- <template>
2
- <section class="workspace-members-page">
3
- <p v-if="loadError" class="text-body-2 text-medium-emphasis mb-4">
4
- {{ loadError }}
5
- </p>
6
-
7
- <MembersAdminClientElement
8
- v-else
9
- :forms="forms"
10
- :options="options"
11
- :collections="collections"
12
- :permissions="permissionState"
13
- :revokeInviteId="revokeInviteId"
14
- :removeMemberUserId="removeMemberUserId"
15
- :status="status"
16
- :actions="actions"
17
- />
18
- </section>
19
- </template>
20
-
21
- <script setup>
22
- import { computed, reactive, ref, watch } from "vue";
23
- import { formatDateTime } from "@jskit-ai/kernel/shared/support";
24
- import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
25
- import MembersAdminClientElement from "./MembersAdminClientElement.vue";
26
- import { useCommand } from "../composables/useCommand.js";
27
- import { useList } from "../composables/records/useList.js";
28
- import { useView } from "../composables/records/useView.js";
29
- import { usePaths } from "../composables/usePaths.js";
30
- import { useAccess } from "../composables/useAccess.js";
31
- import { useUiFeedback } from "../composables/runtime/useUiFeedback.js";
32
- import { useWorkspaceRouteContext } from "../composables/useWorkspaceRouteContext.js";
33
- import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
34
- import { createWorkspaceRealtimeMatcher } from "../support/realtimeWorkspace.js";
35
- import { buildWorkspaceQueryKey } from "../support/workspaceQueryKeys.js";
36
- import { USERS_ROUTE_VISIBILITY_WORKSPACE } from "@jskit-ai/users-core/shared/support/usersVisibility";
37
-
38
- const forms = reactive({
39
- invite: {
40
- email: "",
41
- roleSid: "member"
42
- },
43
- workspace: {
44
- invitesEnabled: false,
45
- invitesAvailable: false
46
- }
47
- });
48
-
49
- const options = reactive({
50
- inviteRoleOptions: [],
51
- memberRoleOptions: [],
52
- formatDateTime(value) {
53
- return formatDateTime(value);
54
- }
55
- });
56
-
57
- const collections = reactive({
58
- members: [],
59
- invites: []
60
- });
61
-
62
- const inviteFeedback = useUiFeedback();
63
- const membersFeedback = useUiFeedback();
64
- const teamFeedback = useUiFeedback();
65
- const revokeInviteId = ref("");
66
- const removeMemberUserId = ref("");
67
-
68
- const { route, currentSurfaceId, workspaceSlugFromRoute, mergePlacementContext } =
69
- useWorkspaceRouteContext();
70
- const usersPaths = usePaths();
71
- const errorRuntime = useShellWebErrorRuntime();
72
- const OWNERSHIP_WORKSPACE = USERS_ROUTE_VISIBILITY_WORKSPACE;
73
-
74
- const hasRouteWorkspaceSlug = computed(() => Boolean(workspaceSlugFromRoute.value));
75
- const workspaceMembersApiPath = computed(() =>
76
- usersPaths.api("/members", {
77
- workspaceSlug: workspaceSlugFromRoute.value
78
- })
79
- );
80
- const workspaceInvitesApiPath = computed(() =>
81
- usersPaths.api("/invites", {
82
- workspaceSlug: workspaceSlugFromRoute.value
83
- })
84
- );
85
-
86
- function workspaceMembersPath(memberId) {
87
- const normalizedMemberId = encodeURIComponent(String(memberId || "").trim());
88
- return `${workspaceMembersApiPath.value}/${normalizedMemberId}`;
89
- }
90
-
91
- function workspaceInvitePath(inviteId) {
92
- const encodedInviteId = encodeURIComponent(String(inviteId || ""));
93
- return `${workspaceInvitesApiPath.value}/${encodedInviteId}`;
94
- }
95
-
96
- const access = useAccess({
97
- workspaceSlug: workspaceSlugFromRoute,
98
- enabled: hasRouteWorkspaceSlug,
99
- mergePlacementContext,
100
- placementSource: "users-web.workspace-members-view"
101
- });
102
-
103
- const matchesWorkspaceRealtime = createWorkspaceRealtimeMatcher(workspaceSlugFromRoute);
104
-
105
- const canViewMembers = computed(() => {
106
- return access.canAny(["workspace.members.view", "workspace.members.manage"]);
107
- });
108
-
109
- const canInviteMembers = computed(() => {
110
- return access.can("workspace.members.invite");
111
- });
112
-
113
- const canManageMembers = computed(() => {
114
- return access.can("workspace.members.manage");
115
- });
116
-
117
- const canRevokeInvites = computed(() => {
118
- return access.can("workspace.invites.revoke");
119
- });
120
-
121
- const permissionState = computed(() => {
122
- return {
123
- canViewMembers: canViewMembers.value,
124
- canInviteMembers: canInviteMembers.value,
125
- canManageMembers: canManageMembers.value,
126
- canRevokeInvites: canRevokeInvites.value
127
- };
128
- });
129
-
130
- function resetMessages() {
131
- inviteFeedback.clear();
132
- membersFeedback.clear();
133
- teamFeedback.clear();
134
- }
135
-
136
- function clearRoleOptions() {
137
- options.inviteRoleOptions = [];
138
- options.memberRoleOptions = [];
139
- }
140
-
141
- function resetViewState() {
142
- resetMessages();
143
- forms.invite.email = "";
144
- forms.invite.roleSid = "member";
145
- forms.workspace.invitesEnabled = false;
146
- forms.workspace.invitesAvailable = false;
147
- collections.members = [];
148
- collections.invites = [];
149
- clearRoleOptions();
150
- revokeInviteId.value = "";
151
- removeMemberUserId.value = "";
152
- }
153
-
154
- function toRoleTitle(roleSid) {
155
- const normalizedRoleId = String(roleSid || "").trim();
156
- if (!normalizedRoleId) {
157
- return "";
158
- }
159
- return normalizedRoleId.charAt(0).toUpperCase() + normalizedRoleId.slice(1);
160
- }
161
-
162
- function normalizeRoleCatalog(payload = {}) {
163
- const source =
164
- payload?.roleCatalog && typeof payload.roleCatalog === "object"
165
- ? payload.roleCatalog
166
- : payload && typeof payload === "object"
167
- ? payload
168
- : {};
169
-
170
- const roles = Array.isArray(source.roles) ? source.roles : [];
171
- const assignableRoleIdsFromCatalog = Array.isArray(source.assignableRoleIds)
172
- ? source.assignableRoleIds
173
- : [];
174
-
175
- let assignableRoleIds = assignableRoleIdsFromCatalog
176
- .map((entry) => String(entry || "").trim().toLowerCase())
177
- .filter(Boolean);
178
-
179
- if (assignableRoleIds.length < 1) {
180
- assignableRoleIds = roles
181
- .filter((entry) => entry?.assignable === true)
182
- .map((entry) => String(entry?.id || "").trim().toLowerCase())
183
- .filter(Boolean);
184
- }
185
-
186
- const uniqueRoleIds = Array.from(new Set(assignableRoleIds));
187
- const roleOptions = uniqueRoleIds.map((roleSid) => ({
188
- title: toRoleTitle(roleSid),
189
- value: roleSid
190
- }));
191
-
192
- const defaultInviteRole = String(source.defaultInviteRole || "")
193
- .trim()
194
- .toLowerCase();
195
-
196
- return {
197
- roleOptions,
198
- defaultInviteRole
199
- };
200
- }
201
-
202
- function applyRoleCatalog(payload = {}) {
203
- const normalizedCatalog = normalizeRoleCatalog(payload);
204
- options.inviteRoleOptions = [...normalizedCatalog.roleOptions];
205
- options.memberRoleOptions = [...normalizedCatalog.roleOptions];
206
-
207
- const selectedInviteRole = String(forms.invite.roleSid || "").trim().toLowerCase();
208
- const hasSelectedInviteRole = normalizedCatalog.roleOptions.some((entry) => entry.value === selectedInviteRole);
209
-
210
- if (
211
- normalizedCatalog.defaultInviteRole &&
212
- normalizedCatalog.roleOptions.some((entry) => entry.value === normalizedCatalog.defaultInviteRole)
213
- ) {
214
- forms.invite.roleSid = normalizedCatalog.defaultInviteRole;
215
- return;
216
- }
217
-
218
- if (!hasSelectedInviteRole && normalizedCatalog.roleOptions.length > 0) {
219
- forms.invite.roleSid = normalizedCatalog.roleOptions[0].value;
220
- }
221
- }
222
-
223
- function normalizeMembers(entries) {
224
- const source = Array.isArray(entries) ? entries : [];
225
- return source.map((entry) => {
226
- const value = entry && typeof entry === "object" ? entry : {};
227
- return {
228
- userId: normalizeRecordId(value.userId, { fallback: "" }),
229
- roleSid: String(value.roleSid || "").trim().toLowerCase(),
230
- status: String(value.status || "").trim().toLowerCase(),
231
- displayName: String(value.displayName || "").trim(),
232
- email: String(value.email || "").trim().toLowerCase(),
233
- isOwner: Boolean(value.isOwner)
234
- };
235
- });
236
- }
237
-
238
- function normalizeInvites(entries) {
239
- const source = Array.isArray(entries) ? entries : [];
240
- return source.map((entry) => {
241
- const value = entry && typeof entry === "object" ? entry : {};
242
- return {
243
- id: normalizeRecordId(value.id, { fallback: "" }),
244
- email: String(value.email || "").trim().toLowerCase(),
245
- roleSid: String(value.roleSid || "").trim().toLowerCase(),
246
- status: String(value.status || "").trim().toLowerCase(),
247
- expiresAt: value.expiresAt || "",
248
- invitedByUserId: normalizeRecordId(value.invitedByUserId, { fallback: null })
249
- };
250
- });
251
- }
252
-
253
- function latestPage(pages) {
254
- if (!Array.isArray(pages) || pages.length < 1) {
255
- return null;
256
- }
257
-
258
- return pages[pages.length - 1];
259
- }
260
-
261
- function applyWorkspaceSettingsPolicy(payload = {}) {
262
- const settings = payload?.settings && typeof payload.settings === "object" ? payload.settings : {};
263
- forms.workspace.invitesEnabled = settings.invitesEnabled !== false;
264
- forms.workspace.invitesAvailable = settings.invitesAvailable !== false;
265
- }
266
-
267
- const workspaceSettingsView = useView({
268
- ownershipFilter: OWNERSHIP_WORKSPACE,
269
- apiSuffix: "/settings",
270
- queryKeyFactory: (surfaceId = "", workspaceSlug = "") =>
271
- buildWorkspaceQueryKey("settings", surfaceId, workspaceSlug),
272
- viewPermissions: ["workspace.members.invite"],
273
- realtime: {
274
- event: "workspace.settings.changed",
275
- matches: matchesWorkspaceRealtime
276
- },
277
- fallbackLoadError: "Unable to load workspace settings."
278
- });
279
-
280
- const workspaceRolesView = useView({
281
- ownershipFilter: OWNERSHIP_WORKSPACE,
282
- apiSuffix: "/roles",
283
- queryKeyFactory: (surfaceId = "", workspaceSlug = "") => buildWorkspaceQueryKey("roles", surfaceId, workspaceSlug),
284
- viewPermissions: ["workspace.members.view", "workspace.members.invite", "workspace.members.manage"],
285
- fallbackLoadError: "Unable to load workspace roles."
286
- });
287
-
288
- const workspaceMembersList = useList({
289
- ownershipFilter: OWNERSHIP_WORKSPACE,
290
- apiSuffix: "/members",
291
- queryKeyFactory: (surfaceId = "", workspaceSlug = "") =>
292
- buildWorkspaceQueryKey("members", surfaceId, workspaceSlug),
293
- viewPermissions: ["workspace.members.view", "workspace.members.manage"],
294
- realtime: {
295
- event: "workspace.members.changed",
296
- matches: matchesWorkspaceRealtime
297
- },
298
- selectItems: (payload) => normalizeMembers(payload?.members),
299
- fallbackLoadError: "Unable to load workspace members."
300
- });
301
-
302
- const workspaceInvitesList = useList({
303
- ownershipFilter: OWNERSHIP_WORKSPACE,
304
- apiSuffix: "/invites",
305
- queryKeyFactory: (surfaceId = "", workspaceSlug = "") =>
306
- buildWorkspaceQueryKey("invites", surfaceId, workspaceSlug),
307
- viewPermissions: ["workspace.members.view", "workspace.members.manage"],
308
- realtime: {
309
- event: "workspace.invites.changed",
310
- matches: matchesWorkspaceRealtime
311
- },
312
- selectItems: (payload) => normalizeInvites(payload?.invites),
313
- fallbackLoadError: "Unable to load workspace invites."
314
- });
315
-
316
- const inviteCreateCommand = useCommand({
317
- ownershipFilter: OWNERSHIP_WORKSPACE,
318
- apiSuffix: "/invites",
319
- runPermissions: ["workspace.members.invite"],
320
- writeMethod: "POST",
321
- fallbackRunError: "Unable to send invite.",
322
- buildRawPayload: () => ({
323
- email: forms.invite.email,
324
- roleSid: forms.invite.roleSid
325
- }),
326
- messages: {
327
- success: "Invite sent.",
328
- error: "Unable to send invite."
329
- }
330
- });
331
-
332
- const revokeInviteCommand = useCommand({
333
- ownershipFilter: OWNERSHIP_WORKSPACE,
334
- apiSuffix: "/invites",
335
- runPermissions: ["workspace.invites.revoke"],
336
- writeMethod: "DELETE",
337
- fallbackRunError: "Unable to revoke invite.",
338
- buildCommandOptions: (_parsed, { context }) => {
339
- return {
340
- method: "DELETE",
341
- path: workspaceInvitePath(context?.inviteId)
342
- };
343
- },
344
- messages: {
345
- success: "Invite revoked.",
346
- error: "Unable to revoke invite."
347
- }
348
- });
349
-
350
- const memberRoleCommand = useCommand({
351
- ownershipFilter: OWNERSHIP_WORKSPACE,
352
- apiSuffix: "/members",
353
- runPermissions: ["workspace.members.manage"],
354
- writeMethod: "PATCH",
355
- fallbackRunError: "Unable to update member role.",
356
- buildRawPayload: (_model, { context }) => ({
357
- roleSid: String(context?.roleSid || "").trim().toLowerCase()
358
- }),
359
- buildCommandOptions: (_parsed, { context }) => {
360
- return {
361
- method: "PATCH",
362
- path: `${workspaceMembersPath(context?.memberUserId)}/role`
363
- };
364
- },
365
- messages: {
366
- success: "Member role updated.",
367
- error: "Unable to update member role."
368
- }
369
- });
370
-
371
- const memberRemoveCommand = useCommand({
372
- ownershipFilter: OWNERSHIP_WORKSPACE,
373
- apiSuffix: "/members",
374
- runPermissions: ["workspace.members.manage"],
375
- writeMethod: "DELETE",
376
- fallbackRunError: "Unable to remove member.",
377
- buildCommandOptions: (_parsed, { context }) => {
378
- return {
379
- method: "DELETE",
380
- path: workspaceMembersPath(context?.memberUserId)
381
- };
382
- },
383
- messages: {
384
- success: "Member removed.",
385
- error: "Unable to remove member."
386
- }
387
- });
388
-
389
- const status = computed(() => {
390
- return {
391
- isCreatingInvite: Boolean(inviteCreateCommand.isRunning.value),
392
- isRevokingInvite: Boolean(revokeInviteCommand.isRunning.value),
393
- isRemovingMember: Boolean(memberRemoveCommand.isRunning.value),
394
- hasLoadedWorkspaceSettings: !canInviteMembers.value || !workspaceSettingsView.isLoading,
395
- hasLoadedMembersList: !canViewMembers.value || !workspaceMembersList.isInitialLoading,
396
- hasLoadedInviteList: !canViewMembers.value || !workspaceInvitesList.isInitialLoading,
397
- isRefreshingWorkspaceSettings: canInviteMembers.value && Boolean(workspaceSettingsView.isRefetching),
398
- isRefreshingMembersList: canViewMembers.value && Boolean(workspaceMembersList.isRefetching),
399
- isRefreshingInviteList: canViewMembers.value && Boolean(workspaceInvitesList.isRefetching)
400
- };
401
- });
402
-
403
- const loadError = computed(() => {
404
- if (!hasRouteWorkspaceSlug.value) {
405
- return "Workspace slug is required in the URL.";
406
- }
407
-
408
- return access.bootstrapError.value;
409
- });
410
-
411
- watch(
412
- loadError,
413
- (nextLoadError) => {
414
- if (!nextLoadError) {
415
- return;
416
- }
417
- errorRuntime.report({
418
- source: "users-web.workspace-members-view",
419
- severity: "error",
420
- channel: "banner",
421
- message: String(nextLoadError || "Unable to load workspace members."),
422
- dedupeKey: `users-web.workspace-members-view:bootstrap:${nextLoadError}`,
423
- dedupeWindowMs: 3000
424
- });
425
- },
426
- { immediate: true }
427
- );
428
-
429
- const actions = Object.freeze({
430
- submitInvite,
431
- submitRevokeInvite,
432
- submitMemberRoleUpdate,
433
- submitRemoveMember
434
- });
435
-
436
- watch(
437
- () => `${currentSurfaceId.value}:${workspaceSlugFromRoute.value}`,
438
- () => {
439
- resetViewState();
440
- },
441
- { immediate: true }
442
- );
443
-
444
- watch(
445
- () => workspaceSettingsView.record,
446
- (payload) => {
447
- if (!payload) {
448
- return;
449
- }
450
- applyWorkspaceSettingsPolicy(payload);
451
- },
452
- { immediate: true }
453
- );
454
-
455
- watch(
456
- () => workspaceSettingsView.loadError,
457
- (nextLoadError) => {
458
- if (!nextLoadError) {
459
- return;
460
- }
461
- forms.workspace.invitesEnabled = false;
462
- forms.workspace.invitesAvailable = false;
463
- }
464
- );
465
-
466
- watch(
467
- () => workspaceRolesView.record,
468
- (payload) => {
469
- if (!payload) {
470
- return;
471
- }
472
- applyRoleCatalog(payload);
473
- },
474
- { immediate: true }
475
- );
476
-
477
- watch(
478
- () => workspaceRolesView.loadError,
479
- (nextLoadError) => {
480
- if (!nextLoadError) {
481
- return;
482
- }
483
- clearRoleOptions();
484
- }
485
- );
486
-
487
- watch(
488
- () => workspaceMembersList.items,
489
- (nextMembers) => {
490
- collections.members = Array.isArray(nextMembers) ? [...nextMembers] : [];
491
- },
492
- { immediate: true }
493
- );
494
-
495
- watch(
496
- () => workspaceMembersList.pages,
497
- (pages) => {
498
- const payload = latestPage(pages);
499
- if (!payload) {
500
- return;
501
- }
502
- applyRoleCatalog(payload);
503
- },
504
- { immediate: true }
505
- );
506
-
507
- watch(
508
- () => workspaceMembersList.loadError,
509
- (nextLoadError) => {
510
- if (!nextLoadError) {
511
- membersFeedback.clear();
512
- return;
513
- }
514
- membersFeedback.error(null, nextLoadError);
515
- }
516
- );
517
-
518
- watch(
519
- () => workspaceInvitesList.items,
520
- (nextInvites) => {
521
- collections.invites = Array.isArray(nextInvites) ? [...nextInvites] : [];
522
- },
523
- { immediate: true }
524
- );
525
-
526
- watch(
527
- () => workspaceInvitesList.pages,
528
- (pages) => {
529
- const payload = latestPage(pages);
530
- if (!payload) {
531
- return;
532
- }
533
- applyRoleCatalog(payload);
534
- },
535
- { immediate: true }
536
- );
537
-
538
- watch(
539
- () => workspaceInvitesList.loadError,
540
- (nextLoadError) => {
541
- if (!nextLoadError) {
542
- teamFeedback.clear();
543
- return;
544
- }
545
- teamFeedback.error(null, nextLoadError);
546
- }
547
- );
548
-
549
- watch(
550
- () => route.fullPath,
551
- () => {
552
- resetMessages();
553
- }
554
- );
555
-
556
- async function submitInvite() {
557
- if (inviteCreateCommand.isRunning.value || !canInviteMembers.value) {
558
- return;
559
- }
560
-
561
- inviteFeedback.clear();
562
-
563
- try {
564
- await inviteCreateCommand.run();
565
- forms.invite.email = "";
566
- await Promise.all([
567
- workspaceInvitesList.reload(),
568
- workspaceRolesView.refresh()
569
- ]);
570
- inviteFeedback.success("Invite sent.");
571
- } catch (error) {
572
- inviteFeedback.error(error, "Unable to send invite.");
573
- }
574
- }
575
-
576
- async function submitRevokeInvite(inviteId) {
577
- if (revokeInviteCommand.isRunning.value || !canRevokeInvites.value) {
578
- return;
579
- }
580
-
581
- revokeInviteId.value = normalizeRecordId(inviteId, { fallback: "" });
582
- teamFeedback.clear();
583
-
584
- try {
585
- await revokeInviteCommand.run({
586
- inviteId
587
- });
588
- await Promise.all([
589
- workspaceInvitesList.reload(),
590
- workspaceRolesView.refresh()
591
- ]);
592
- teamFeedback.success("Invite revoked.");
593
- } catch (error) {
594
- teamFeedback.error(error, "Unable to revoke invite.");
595
- } finally {
596
- revokeInviteId.value = "";
597
- }
598
- }
599
-
600
- async function submitMemberRoleUpdate(member, roleSid) {
601
- if (!canManageMembers.value) {
602
- return;
603
- }
604
-
605
- membersFeedback.clear();
606
-
607
- try {
608
- const memberUserId = normalizeRecordId(member?.userId, { fallback: null });
609
- if (!memberUserId) {
610
- throw new Error("Member user id is invalid.");
611
- }
612
-
613
- await memberRoleCommand.run({
614
- memberUserId,
615
- roleSid
616
- });
617
- await Promise.all([
618
- workspaceMembersList.reload(),
619
- workspaceRolesView.refresh()
620
- ]);
621
- membersFeedback.success("Member role updated.");
622
- } catch (error) {
623
- membersFeedback.error(error, "Unable to update member role.");
624
- }
625
- }
626
-
627
- async function submitRemoveMember(member) {
628
- if (memberRemoveCommand.isRunning.value || !canManageMembers.value) {
629
- return;
630
- }
631
-
632
- membersFeedback.clear();
633
-
634
- try {
635
- const memberUserId = normalizeRecordId(member?.userId, { fallback: null });
636
- if (!memberUserId) {
637
- throw new Error("Member user id is invalid.");
638
- }
639
-
640
- removeMemberUserId.value = normalizeRecordId(memberUserId, { fallback: "" });
641
- await memberRemoveCommand.run({
642
- memberUserId
643
- });
644
- await Promise.all([
645
- workspaceMembersList.reload(),
646
- workspaceRolesView.refresh()
647
- ]);
648
- membersFeedback.success("Member removed.");
649
- } catch (error) {
650
- membersFeedback.error(error, "Unable to remove member.");
651
- } finally {
652
- removeMemberUserId.value = "";
653
- }
654
- }
655
- </script>