@jskit-ai/workspaces-web 0.1.134 → 0.1.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +29 -27
- package/src/client/account-settings/accountSettingsInvitesRuntime.js +2 -2
- package/src/client/account-settings/useAccountSettingsInvitesSectionRuntime.js +2 -2
- package/src/client/components/MembersAdminClientElement.vue +1 -1
- package/src/client/components/WorkspaceInviteLanding.vue +4 -4
- package/src/client/components/WorkspaceMembersClientElement.vue +5 -5
- package/src/client/components/{UsersWorkspaceMembersMenuItem.vue → WorkspaceMembersMenuItem.vue} +2 -2
- package/src/client/components/{UsersWorkspacePermissionMenuItem.vue → WorkspacePermissionMenuItem.vue} +1 -1
- package/src/client/components/{UsersWorkspaceSettingsMenuItem.vue → WorkspaceSettingsMenuItem.vue} +2 -2
- package/src/client/components/WorkspacesClientElement.vue +12 -12
- package/src/client/lib/surfaceAccessPolicy.js +4 -1
- package/src/client/providers/WorkspacesWebClientProvider.js +10 -10
- package/src/client/runtime/bootstrapPlacementRuntime.js +1 -1
- package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +2 -2
- package/test/settingsPlacementContract.test.js +12 -12
- package/test/{usersWorkspaceSelectorContract.test.js → workspaceSelectorContract.test.js} +3 -3
- package/src/client/lib/httpClient.js +0 -10
- package/src/client/lib/permissions.js +0 -27
- /package/src/client/components/{UsersProfileSurfaceSwitchMenuItem.vue → WorkspaceProfileSurfaceSwitchMenuItem.vue} +0 -0
- /package/src/client/components/{UsersWorkspaceSelector.vue → WorkspaceSelector.vue} +0 -0
- /package/src/client/components/{UsersWorkspaceToolsWidget.vue → WorkspaceToolsWidget.vue} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/workspaces-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.135",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"./client/composables/useWorkspaceRouteContext": "./src/client/composables/useWorkspaceRouteContext.js"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@jskit-ai/auth-web": "0.1.
|
|
18
|
-
"@jskit-ai/http-
|
|
19
|
-
"@jskit-ai/kernel": "0.1.
|
|
20
|
-
"@jskit-ai/shell-web": "0.1.
|
|
21
|
-
"@jskit-ai/users-core": "0.1.
|
|
22
|
-
"@jskit-ai/users-web": "0.1.
|
|
23
|
-
"@jskit-ai/workspaces-core": "0.1.
|
|
17
|
+
"@jskit-ai/auth-web": "0.1.156",
|
|
18
|
+
"@jskit-ai/http-web": "0.1.1",
|
|
19
|
+
"@jskit-ai/kernel": "0.1.156",
|
|
20
|
+
"@jskit-ai/shell-web": "0.1.160",
|
|
21
|
+
"@jskit-ai/users-core": "0.1.169",
|
|
22
|
+
"@jskit-ai/users-web": "0.1.174",
|
|
23
|
+
"@jskit-ai/workspaces-core": "0.1.134",
|
|
24
24
|
"@mdi/js": "^7.4.47"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"workspaces.web"
|
|
38
38
|
],
|
|
39
39
|
"requires": [
|
|
40
|
+
"runtime.http-web",
|
|
40
41
|
"users.web",
|
|
41
42
|
"workspaces.core"
|
|
42
43
|
]
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
"surfaces": [
|
|
108
109
|
"admin"
|
|
109
110
|
],
|
|
110
|
-
"source": "src/client/components/
|
|
111
|
+
"source": "src/client/components/WorkspaceToolsWidget.vue"
|
|
111
112
|
}
|
|
112
113
|
],
|
|
113
114
|
"topology": {
|
|
@@ -281,9 +282,10 @@
|
|
|
281
282
|
"mutations": {
|
|
282
283
|
"dependencies": {
|
|
283
284
|
"runtime": {
|
|
284
|
-
"@jskit-ai/auth-web": "0.1.
|
|
285
|
-
"@jskit-ai/
|
|
286
|
-
"@jskit-ai/
|
|
285
|
+
"@jskit-ai/auth-web": "0.1.156",
|
|
286
|
+
"@jskit-ai/http-web": "0.1.1",
|
|
287
|
+
"@jskit-ai/workspaces-core": "0.1.134",
|
|
288
|
+
"@jskit-ai/users-web": "0.1.174"
|
|
287
289
|
},
|
|
288
290
|
"dev": {}
|
|
289
291
|
},
|
|
@@ -303,7 +305,7 @@
|
|
|
303
305
|
"ownership": "app",
|
|
304
306
|
"reason": "Install app-owned account pending invites cue component scaffold.",
|
|
305
307
|
"category": "workspaces-web",
|
|
306
|
-
"id": "
|
|
308
|
+
"id": "workspaces-web-main-component-account-pending-invites-cue"
|
|
307
309
|
},
|
|
308
310
|
{
|
|
309
311
|
"from": "templates/packages/main/src/client/components/AccountSettingsInvitesSection.vue",
|
|
@@ -311,7 +313,7 @@
|
|
|
311
313
|
"ownership": "app",
|
|
312
314
|
"reason": "Install app-owned account invites section scaffold for multihoming account settings.",
|
|
313
315
|
"category": "workspaces-web",
|
|
314
|
-
"id": "
|
|
316
|
+
"id": "workspaces-web-main-component-account-settings-invites-section"
|
|
315
317
|
},
|
|
316
318
|
{
|
|
317
319
|
"from": "templates/src/pages/invite/[token].vue",
|
|
@@ -327,7 +329,7 @@
|
|
|
327
329
|
"ownership": "app",
|
|
328
330
|
"reason": "Install app-owned workspace not-found card component used by workspace-dependent surfaces.",
|
|
329
331
|
"category": "workspaces-web",
|
|
330
|
-
"id": "
|
|
332
|
+
"id": "workspaces-web-component-workspace-not-found-card",
|
|
331
333
|
"when": {
|
|
332
334
|
"config": "tenancyMode",
|
|
333
335
|
"in": [
|
|
@@ -342,7 +344,7 @@
|
|
|
342
344
|
"ownership": "app",
|
|
343
345
|
"reason": "Install app-owned workspace bootstrap status composable for workspace-dependent surfaces.",
|
|
344
346
|
"category": "workspaces-web",
|
|
345
|
-
"id": "
|
|
347
|
+
"id": "workspaces-web-composable-workspace-not-found-state",
|
|
346
348
|
"when": {
|
|
347
349
|
"config": "tenancyMode",
|
|
348
350
|
"in": [
|
|
@@ -358,7 +360,7 @@
|
|
|
358
360
|
"ownership": "app",
|
|
359
361
|
"reason": "Install workspace app surface wrapper shell for workspaces-web.",
|
|
360
362
|
"category": "workspaces-web",
|
|
361
|
-
"id": "
|
|
363
|
+
"id": "workspaces-web-page-app-wrapper",
|
|
362
364
|
"when": {
|
|
363
365
|
"config": "tenancyMode",
|
|
364
366
|
"in": [
|
|
@@ -374,7 +376,7 @@
|
|
|
374
376
|
"ownership": "app",
|
|
375
377
|
"reason": "Install workspace app surface starter page scaffold for workspaces-web.",
|
|
376
378
|
"category": "workspaces-web",
|
|
377
|
-
"id": "
|
|
379
|
+
"id": "workspaces-web-page-app-index",
|
|
378
380
|
"when": {
|
|
379
381
|
"config": "tenancyMode",
|
|
380
382
|
"in": [
|
|
@@ -390,7 +392,7 @@
|
|
|
390
392
|
"ownership": "app",
|
|
391
393
|
"reason": "Install workspace admin surface wrapper shell for workspaces-web.",
|
|
392
394
|
"category": "workspaces-web",
|
|
393
|
-
"id": "
|
|
395
|
+
"id": "workspaces-web-page-admin-wrapper",
|
|
394
396
|
"when": {
|
|
395
397
|
"config": "tenancyMode",
|
|
396
398
|
"in": [
|
|
@@ -406,7 +408,7 @@
|
|
|
406
408
|
"ownership": "app",
|
|
407
409
|
"reason": "Install workspace admin surface starter page scaffold for workspaces-web.",
|
|
408
410
|
"category": "workspaces-web",
|
|
409
|
-
"id": "
|
|
411
|
+
"id": "workspaces-web-page-admin-index",
|
|
410
412
|
"when": {
|
|
411
413
|
"config": "tenancyMode",
|
|
412
414
|
"in": [
|
|
@@ -422,7 +424,7 @@
|
|
|
422
424
|
"ownership": "app",
|
|
423
425
|
"reason": "Install admin members starter page scaffold for workspaces-web members UI.",
|
|
424
426
|
"category": "workspaces-web",
|
|
425
|
-
"id": "
|
|
427
|
+
"id": "workspaces-web-page-admin-members",
|
|
426
428
|
"when": {
|
|
427
429
|
"config": "tenancyMode",
|
|
428
430
|
"in": [
|
|
@@ -438,7 +440,7 @@
|
|
|
438
440
|
"ownership": "app",
|
|
439
441
|
"reason": "Install workspace settings shell route scaffold for workspaces-web workspace admin UI.",
|
|
440
442
|
"category": "workspaces-web",
|
|
441
|
-
"id": "
|
|
443
|
+
"id": "workspaces-web-page-admin-workspace-settings-shell",
|
|
442
444
|
"when": {
|
|
443
445
|
"config": "tenancyMode",
|
|
444
446
|
"in": [
|
|
@@ -454,7 +456,7 @@
|
|
|
454
456
|
"ownership": "app",
|
|
455
457
|
"reason": "Install workspace settings index stub scaffold for app-owned landing or redirect behavior.",
|
|
456
458
|
"category": "workspaces-web",
|
|
457
|
-
"id": "
|
|
459
|
+
"id": "workspaces-web-page-admin-workspace-settings",
|
|
458
460
|
"when": {
|
|
459
461
|
"config": "tenancyMode",
|
|
460
462
|
"in": [
|
|
@@ -542,7 +544,7 @@
|
|
|
542
544
|
"from": "../components/AccountPendingInvitesCue.vue",
|
|
543
545
|
"reason": "Bind app-owned account pending invites cue component into local main client provider imports.",
|
|
544
546
|
"category": "workspaces-web",
|
|
545
|
-
"id": "
|
|
547
|
+
"id": "workspaces-web-main-client-provider-account-invites-import"
|
|
546
548
|
},
|
|
547
549
|
{
|
|
548
550
|
"op": "ensure-import",
|
|
@@ -551,7 +553,7 @@
|
|
|
551
553
|
"from": "../components/AccountSettingsInvitesSection.vue",
|
|
552
554
|
"reason": "Bind app-owned account invites section component into local main client provider imports.",
|
|
553
555
|
"category": "workspaces-web",
|
|
554
|
-
"id": "
|
|
556
|
+
"id": "workspaces-web-main-client-provider-account-settings-section-import"
|
|
555
557
|
},
|
|
556
558
|
{
|
|
557
559
|
"op": "ensure-call",
|
|
@@ -564,7 +566,7 @@
|
|
|
564
566
|
"beforeClass": "MainClientProvider",
|
|
565
567
|
"reason": "Bind app-owned account pending invites cue component token into local main client provider registry.",
|
|
566
568
|
"category": "workspaces-web",
|
|
567
|
-
"id": "
|
|
569
|
+
"id": "workspaces-web-main-client-provider-account-invites-register"
|
|
568
570
|
},
|
|
569
571
|
{
|
|
570
572
|
"op": "ensure-call",
|
|
@@ -577,7 +579,7 @@
|
|
|
577
579
|
"beforeClass": "MainClientProvider",
|
|
578
580
|
"reason": "Bind app-owned account invites section component token into local main client provider registry.",
|
|
579
581
|
"category": "workspaces-web",
|
|
580
|
-
"id": "
|
|
582
|
+
"id": "workspaces-web-main-client-provider-account-settings-section-register"
|
|
581
583
|
}
|
|
582
584
|
]
|
|
583
585
|
}
|
|
@@ -50,7 +50,7 @@ function createAccountSettingsInvitesRuntime({
|
|
|
50
50
|
message: normalizedDecision === "accept" ? "Invitation accepted." : "Invitation refused.",
|
|
51
51
|
severity: "success",
|
|
52
52
|
channel: "snackbar",
|
|
53
|
-
dedupeKey: `
|
|
53
|
+
dedupeKey: `workspaces-web.account-settings-runtime:invite-${normalizedDecision}:${token}`
|
|
54
54
|
});
|
|
55
55
|
} catch (error) {
|
|
56
56
|
const statusCode = resolveErrorStatusCode(error);
|
|
@@ -63,7 +63,7 @@ function createAccountSettingsInvitesRuntime({
|
|
|
63
63
|
: String(error?.message || fallbackMessage),
|
|
64
64
|
severity: "error",
|
|
65
65
|
channel: "banner",
|
|
66
|
-
dedupeKey: `
|
|
66
|
+
dedupeKey: `workspaces-web.account-settings-runtime:invite-${normalizedDecision}-error:${token}`
|
|
67
67
|
});
|
|
68
68
|
} finally {
|
|
69
69
|
inviteAction.value = {
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
} from "@jskit-ai/shell-web/client/placement";
|
|
7
7
|
import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
|
|
8
8
|
import { ROUTE_VISIBILITY_PUBLIC } from "@jskit-ai/kernel/shared/support/visibility";
|
|
9
|
-
import { useCommand } from "@jskit-ai/
|
|
9
|
+
import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
|
|
10
10
|
import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
|
|
11
|
-
import { useView } from "@jskit-ai/
|
|
11
|
+
import { useView } from "@jskit-ai/http-web/client/composables/useView";
|
|
12
12
|
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
13
13
|
import { WORKSPACE_INVITE_REDEEM_TRANSPORT } from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
|
|
14
14
|
import { useWorkspaceSurfaceId } from "../composables/useWorkspaceSurfaceId.js";
|
|
@@ -195,7 +195,7 @@ import { computed, toRefs, unref } from "vue";
|
|
|
195
195
|
import { mdiContentCopy } from "@mdi/js";
|
|
196
196
|
import { formatDateTime as formatKernelDateTime } from "@jskit-ai/kernel/shared/support";
|
|
197
197
|
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
198
|
-
import { requireBoolean, requireFunction, requireRecord } from "@jskit-ai/
|
|
198
|
+
import { requireBoolean, requireFunction, requireRecord } from "@jskit-ai/http-web/client/support/contractGuards";
|
|
199
199
|
|
|
200
200
|
const props = defineProps({
|
|
201
201
|
forms: {
|
|
@@ -62,12 +62,12 @@
|
|
|
62
62
|
import { computed, onMounted } from "vue";
|
|
63
63
|
import { useRoute, useRouter } from "vue-router";
|
|
64
64
|
import { useAuthStore } from "@jskit-ai/auth-web/client";
|
|
65
|
-
import { useEndpointResource } from "@jskit-ai/
|
|
65
|
+
import { useEndpointResource } from "@jskit-ai/http-web/client/composables/useEndpointResource";
|
|
66
66
|
import {
|
|
67
67
|
WORKSPACE_INVITATION_RESOLVE_TRANSPORT,
|
|
68
68
|
WORKSPACE_INVITE_REDEEM_TRANSPORT
|
|
69
69
|
} from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
|
|
70
|
-
import {
|
|
70
|
+
import { httpWebClient } from "@jskit-ai/http-web/client/lib/httpClient";
|
|
71
71
|
|
|
72
72
|
const route = useRoute();
|
|
73
73
|
const router = useRouter();
|
|
@@ -84,7 +84,7 @@ const inviteResource = useEndpointResource({
|
|
|
84
84
|
queryKey: computed(() => ["workspaces-web", "invite-landing", token.value]),
|
|
85
85
|
path: "/api/workspace/invitations/resolve",
|
|
86
86
|
enabled: computed(() => Boolean(token.value)),
|
|
87
|
-
client:
|
|
87
|
+
client: httpWebClient,
|
|
88
88
|
readQuery: inviteQuery,
|
|
89
89
|
transport: WORKSPACE_INVITATION_RESOLVE_TRANSPORT,
|
|
90
90
|
fallbackLoadError: "Unable to load invitation."
|
|
@@ -94,7 +94,7 @@ const redeemResource = useEndpointResource({
|
|
|
94
94
|
queryKey: computed(() => ["workspaces-web", "invite-landing", "redeem", token.value]),
|
|
95
95
|
path: "/api/workspace/invitations/redeem",
|
|
96
96
|
enabled: false,
|
|
97
|
-
client:
|
|
97
|
+
client: httpWebClient,
|
|
98
98
|
writeMethod: "POST",
|
|
99
99
|
transport: WORKSPACE_INVITE_REDEEM_TRANSPORT,
|
|
100
100
|
fallbackSaveError: "Unable to accept invitation."
|
|
@@ -41,12 +41,12 @@ import {
|
|
|
41
41
|
WORKSPACE_SETTINGS_TRANSPORT
|
|
42
42
|
} from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
|
|
43
43
|
import MembersAdminClientElement from "./MembersAdminClientElement.vue";
|
|
44
|
-
import { useCommand } from "@jskit-ai/
|
|
45
|
-
import { useList } from "@jskit-ai/
|
|
46
|
-
import { useView } from "@jskit-ai/
|
|
44
|
+
import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
|
|
45
|
+
import { useList } from "@jskit-ai/http-web/client/composables/useList";
|
|
46
|
+
import { useView } from "@jskit-ai/http-web/client/composables/useView";
|
|
47
47
|
import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
|
|
48
|
-
import { useAccess } from "@jskit-ai/
|
|
49
|
-
import { useUiFeedback } from "@jskit-ai/
|
|
48
|
+
import { useAccess } from "@jskit-ai/http-web/client/composables/useAccess";
|
|
49
|
+
import { useUiFeedback } from "@jskit-ai/http-web/client/composables/useUiFeedback";
|
|
50
50
|
import { useWorkspaceRouteContext } from "../composables/useWorkspaceRouteContext.js";
|
|
51
51
|
import { createWorkspaceRealtimeMatcher } from "../support/realtimeWorkspace.js";
|
|
52
52
|
import { buildWorkspaceQueryKey } from "../support/workspaceQueryKeys.js";
|
package/src/client/components/{UsersWorkspaceMembersMenuItem.vue → WorkspaceMembersMenuItem.vue}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { mdiAccountGroupOutline } from "@mdi/js";
|
|
3
|
-
import
|
|
3
|
+
import WorkspacePermissionMenuItem from "./WorkspacePermissionMenuItem.vue";
|
|
4
4
|
|
|
5
5
|
const props = defineProps({
|
|
6
6
|
label: {
|
|
@@ -25,7 +25,7 @@ const MEMBERS_MENU_PERMISSIONS = Object.freeze(["workspace.members.view", "works
|
|
|
25
25
|
</script>
|
|
26
26
|
|
|
27
27
|
<template>
|
|
28
|
-
<
|
|
28
|
+
<WorkspacePermissionMenuItem
|
|
29
29
|
:label="props.label"
|
|
30
30
|
:to="props.to"
|
|
31
31
|
:icon="props.icon"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
import { useSurfaceRouteContext } from "@jskit-ai/shell-web/client/navigation/useSurfaceRouteContext";
|
|
4
|
-
import { hasPermission, normalizePermissionList } from "@jskit-ai/
|
|
4
|
+
import { hasPermission, normalizePermissionList } from "@jskit-ai/http-web/client/lib/permissions";
|
|
5
5
|
import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
|
|
6
6
|
|
|
7
7
|
const props = defineProps({
|
package/src/client/components/{UsersWorkspaceSettingsMenuItem.vue → WorkspaceSettingsMenuItem.vue}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { mdiCogOutline } from "@mdi/js";
|
|
3
|
-
import
|
|
3
|
+
import WorkspacePermissionMenuItem from "./WorkspacePermissionMenuItem.vue";
|
|
4
4
|
|
|
5
5
|
const props = defineProps({
|
|
6
6
|
label: {
|
|
@@ -28,7 +28,7 @@ const WORKSPACE_SETTINGS_MENU_PERMISSIONS = Object.freeze([
|
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<template>
|
|
31
|
-
<
|
|
31
|
+
<WorkspacePermissionMenuItem
|
|
32
32
|
:label="props.label"
|
|
33
33
|
:to="props.to"
|
|
34
34
|
:icon="props.icon"
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
WORKSPACES_TRANSPORT,
|
|
13
13
|
WORKSPACE_INVITE_REDEEM_TRANSPORT
|
|
14
14
|
} from "@jskit-ai/workspaces-core/shared/jsonApiTransports";
|
|
15
|
-
import { useCommand } from "@jskit-ai/
|
|
16
|
-
import { useView } from "@jskit-ai/
|
|
15
|
+
import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
|
|
16
|
+
import { useView } from "@jskit-ai/http-web/client/composables/useView";
|
|
17
17
|
import { usePaths } from "@jskit-ai/shell-web/client/navigation/usePaths";
|
|
18
|
-
import { useRealtimeQueryInvalidation } from "@jskit-ai/
|
|
18
|
+
import { useRealtimeQueryInvalidation } from "@jskit-ai/http-web/client/composables/useRealtimeQueryInvalidation";
|
|
19
19
|
import { useWorkspaceSurfaceId } from "../composables/useWorkspaceSurfaceId.js";
|
|
20
20
|
import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
21
21
|
|
|
@@ -76,7 +76,7 @@ const redeemInviteModel = reactive({
|
|
|
76
76
|
token: "",
|
|
77
77
|
decision: ""
|
|
78
78
|
});
|
|
79
|
-
const bootstrapQueryKey = Object.freeze(["
|
|
79
|
+
const bootstrapQueryKey = Object.freeze(["workspaces-web", "bootstrap", "__none__"]);
|
|
80
80
|
const OWNERSHIP_PUBLIC = ROUTE_VISIBILITY_PUBLIC;
|
|
81
81
|
|
|
82
82
|
const bootstrapView = useView({
|
|
@@ -179,12 +179,12 @@ function reportFeedback({
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
errorRuntime.report({
|
|
182
|
-
source: "
|
|
182
|
+
source: "workspaces-web.workspaces-view",
|
|
183
183
|
message: normalizedMessage,
|
|
184
184
|
intent: "action-feedback",
|
|
185
185
|
severity,
|
|
186
186
|
channel,
|
|
187
|
-
dedupeKey: dedupeKey || `
|
|
187
|
+
dedupeKey: dedupeKey || `workspaces-web.workspaces-view:${severity}:${normalizedMessage}`,
|
|
188
188
|
dedupeWindowMs: 3000
|
|
189
189
|
});
|
|
190
190
|
}
|
|
@@ -235,7 +235,7 @@ async function openWorkspace(workspaceSlug) {
|
|
|
235
235
|
reportFeedback({
|
|
236
236
|
message: "Workspace surface is not configured.",
|
|
237
237
|
severity: "error",
|
|
238
|
-
dedupeKey: "
|
|
238
|
+
dedupeKey: "workspaces-web.workspaces-view:workspace-surface-missing"
|
|
239
239
|
});
|
|
240
240
|
return;
|
|
241
241
|
}
|
|
@@ -259,7 +259,7 @@ async function openWorkspace(workspaceSlug) {
|
|
|
259
259
|
reportFeedback({
|
|
260
260
|
message: String(error?.message || "Unable to open workspace."),
|
|
261
261
|
severity: "error",
|
|
262
|
-
dedupeKey: `
|
|
262
|
+
dedupeKey: `workspaces-web.workspaces-view:open-workspace:${normalizedSlug}`
|
|
263
263
|
});
|
|
264
264
|
} finally {
|
|
265
265
|
selectingWorkspaceSlug.value = "";
|
|
@@ -301,7 +301,7 @@ async function respondToInvite(invite, decision) {
|
|
|
301
301
|
reportFeedback({
|
|
302
302
|
message: "Invitation refused.",
|
|
303
303
|
severity: "success",
|
|
304
|
-
dedupeKey: `
|
|
304
|
+
dedupeKey: `workspaces-web.workspaces-view:invite-refused:${token}`
|
|
305
305
|
});
|
|
306
306
|
} catch (error) {
|
|
307
307
|
reportFeedback({
|
|
@@ -309,7 +309,7 @@ async function respondToInvite(invite, decision) {
|
|
|
309
309
|
error?.message || (normalizedDecision === "accept" ? "Unable to accept invite." : "Unable to refuse invite.")
|
|
310
310
|
),
|
|
311
311
|
severity: "error",
|
|
312
|
-
dedupeKey: `
|
|
312
|
+
dedupeKey: `workspaces-web.workspaces-view:invite-${normalizedDecision}:${token}`
|
|
313
313
|
});
|
|
314
314
|
} finally {
|
|
315
315
|
inviteAction.value = {
|
|
@@ -339,7 +339,7 @@ async function createWorkspace() {
|
|
|
339
339
|
reportFeedback({
|
|
340
340
|
message: "Workspace name is required.",
|
|
341
341
|
severity: "error",
|
|
342
|
-
dedupeKey: "
|
|
342
|
+
dedupeKey: "workspaces-web.workspaces-view:create-workspace-name-required"
|
|
343
343
|
});
|
|
344
344
|
return;
|
|
345
345
|
}
|
|
@@ -358,7 +358,7 @@ async function createWorkspace() {
|
|
|
358
358
|
reportFeedback({
|
|
359
359
|
message: String(error?.message || "Unable to create workspace."),
|
|
360
360
|
severity: "error",
|
|
361
|
-
dedupeKey: "
|
|
361
|
+
dedupeKey: "workspaces-web.workspaces-view:create-workspace-error"
|
|
362
362
|
});
|
|
363
363
|
}
|
|
364
364
|
}
|
|
@@ -4,7 +4,10 @@ import {
|
|
|
4
4
|
normalizeRecord,
|
|
5
5
|
normalizeWorkspaceBootstrapStatusValue
|
|
6
6
|
} from "../support/runtimeNormalization.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
hasPermission,
|
|
9
|
+
normalizePermissionList
|
|
10
|
+
} from "@jskit-ai/http-web/client/lib/permissions";
|
|
8
11
|
|
|
9
12
|
const WORKSPACE_BOOTSTRAP_STATUS_NOT_FOUND = "not_found";
|
|
10
13
|
const WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN = "forbidden";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import WorkspaceProfileSurfaceSwitchMenuItem from "../components/WorkspaceProfileSurfaceSwitchMenuItem.vue";
|
|
2
|
+
import WorkspaceSelector from "../components/WorkspaceSelector.vue";
|
|
3
|
+
import WorkspaceToolsWidget from "../components/WorkspaceToolsWidget.vue";
|
|
4
|
+
import WorkspaceSettingsMenuItem from "../components/WorkspaceSettingsMenuItem.vue";
|
|
5
|
+
import WorkspaceMembersMenuItem from "../components/WorkspaceMembersMenuItem.vue";
|
|
6
6
|
import MembersAdminClientElement from "../components/MembersAdminClientElement.vue";
|
|
7
7
|
import { registerBootstrapPayloadHandler } from "@jskit-ai/shell-web/client/bootstrap";
|
|
8
8
|
import { createBootstrapPlacementRuntime } from "../runtime/bootstrapPlacementRuntime.js";
|
|
@@ -20,11 +20,11 @@ class WorkspacesWebClientProvider {
|
|
|
20
20
|
throw new Error("WorkspacesWebClientProvider requires application singleton()/tag().");
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
app.singleton("workspaces.web.profile.menu.surface-switch-item", () =>
|
|
24
|
-
app.singleton("workspaces.web.workspace.selector", () =>
|
|
25
|
-
app.singleton("workspaces.web.workspace.tools.widget", () =>
|
|
26
|
-
app.singleton("workspaces.web.workspace-settings.menu-item", () =>
|
|
27
|
-
app.singleton("workspaces.web.workspace-members.menu-item", () =>
|
|
23
|
+
app.singleton("workspaces.web.profile.menu.surface-switch-item", () => WorkspaceProfileSurfaceSwitchMenuItem);
|
|
24
|
+
app.singleton("workspaces.web.workspace.selector", () => WorkspaceSelector);
|
|
25
|
+
app.singleton("workspaces.web.workspace.tools.widget", () => WorkspaceToolsWidget);
|
|
26
|
+
app.singleton("workspaces.web.workspace-settings.menu-item", () => WorkspaceSettingsMenuItem);
|
|
27
|
+
app.singleton("workspaces.web.workspace-members.menu-item", () => WorkspaceMembersMenuItem);
|
|
28
28
|
app.singleton("workspaces.web.members-admin.element", () => MembersAdminClientElement);
|
|
29
29
|
app.singleton("workspaces.web.bootstrap-placement.runtime", (scope) => createBootstrapPlacementRuntime({ app: scope }));
|
|
30
30
|
registerBootstrapPayloadHandler(app, "workspaces.web.bootstrap.handler", (scope) => {
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
findWorkspaceBySlug,
|
|
3
3
|
normalizeWorkspaceList
|
|
4
4
|
} from "../lib/bootstrap.js";
|
|
5
|
-
import { normalizePermissionList } from "
|
|
5
|
+
import { normalizePermissionList } from "@jskit-ai/http-web/client/lib/permissions";
|
|
6
6
|
import {
|
|
7
7
|
persistBootstrapThemePreference,
|
|
8
8
|
resolveBootstrapThemeName,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "@jskit-ai/shell-web/client/placement";
|
|
8
8
|
import { parseWorkspacePathname } from "@jskit-ai/workspaces-core/shared/support/workspacePathModel";
|
|
9
9
|
import { extractWorkspaceSlugFromSurfacePathname } from "../lib/workspaceSurfacePaths.js";
|
|
10
|
-
import {
|
|
10
|
+
import { httpWebClient } from "@jskit-ai/http-web/client/lib/httpClient";
|
|
11
11
|
import { buildBootstrapApiPath } from "../lib/bootstrap.js";
|
|
12
12
|
import {
|
|
13
13
|
normalizeWorkspaceBootstrapStatusValue
|
|
@@ -127,7 +127,7 @@ function countPendingInvites(entries = []) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
async function fetchBootstrapPayload(workspaceSlug = "") {
|
|
130
|
-
return
|
|
130
|
+
return httpWebClient.request(buildBootstrapApiPath(workspaceSlug), {
|
|
131
131
|
method: "GET"
|
|
132
132
|
});
|
|
133
133
|
}
|
|
@@ -98,13 +98,13 @@ test("workspaces-web installs an app-owned account invites section wrapper", asy
|
|
|
98
98
|
source,
|
|
99
99
|
/@jskit-ai\/workspaces-web\/client\/components\/AccountSettingsInvitesSection/
|
|
100
100
|
);
|
|
101
|
-
assert.deepEqual(findFileMutation("
|
|
101
|
+
assert.deepEqual(findFileMutation("workspaces-web-main-component-account-settings-invites-section"), {
|
|
102
102
|
from: "templates/packages/main/src/client/components/AccountSettingsInvitesSection.vue",
|
|
103
103
|
to: "packages/main/src/client/components/AccountSettingsInvitesSection.vue",
|
|
104
104
|
ownership: "app",
|
|
105
105
|
reason: "Install app-owned account invites section scaffold for multihoming account settings.",
|
|
106
106
|
category: "workspaces-web",
|
|
107
|
-
id: "
|
|
107
|
+
id: "workspaces-web-main-component-account-settings-invites-section"
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -158,7 +158,7 @@ test("workspaces-web resource load states expose local retry actions", async ()
|
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
test("workspaces-web command loading state uses
|
|
161
|
+
test("workspaces-web command loading state uses http-web proxyRefs contract", async () => {
|
|
162
162
|
const expectations = new Map([
|
|
163
163
|
[
|
|
164
164
|
"src/client/components/WorkspaceMembersClientElement.vue",
|
|
@@ -204,13 +204,13 @@ test("workspaces-web installs an account invites cue scaffold that reads placeme
|
|
|
204
204
|
assert.doesNotMatch(source, /\buseQuery\b/);
|
|
205
205
|
assert.match(source, /placementContext\.value\?\.pendingInvitesCount/);
|
|
206
206
|
assert.match(source, /placementContext\.value\?\.workspaceInvitesEnabled/);
|
|
207
|
-
assert.deepEqual(findFileMutation("
|
|
207
|
+
assert.deepEqual(findFileMutation("workspaces-web-main-component-account-pending-invites-cue"), {
|
|
208
208
|
from: "templates/packages/main/src/client/components/AccountPendingInvitesCue.vue",
|
|
209
209
|
to: "packages/main/src/client/components/AccountPendingInvitesCue.vue",
|
|
210
210
|
ownership: "app",
|
|
211
211
|
reason: "Install app-owned account pending invites cue component scaffold.",
|
|
212
212
|
category: "workspaces-web",
|
|
213
|
-
id: "
|
|
213
|
+
id: "workspaces-web-main-component-account-pending-invites-cue"
|
|
214
214
|
});
|
|
215
215
|
});
|
|
216
216
|
|
|
@@ -301,7 +301,7 @@ test("workspaces-web packageMetadata metadata advertises admin settings outlets"
|
|
|
301
301
|
{
|
|
302
302
|
target: "admin-cog:primary-menu",
|
|
303
303
|
surfaces: ["admin"],
|
|
304
|
-
source: "src/client/components/
|
|
304
|
+
source: "src/client/components/WorkspaceToolsWidget.vue"
|
|
305
305
|
}
|
|
306
306
|
]
|
|
307
307
|
);
|
|
@@ -418,29 +418,29 @@ test("workspaces-web packageMetadata metadata advertises admin settings outlets"
|
|
|
418
418
|
assert.match(findTextMutation("workspaces-web-admin-placement-topology")?.value || "", /outlet: "admin-settings:primary-menu"/);
|
|
419
419
|
assert.match(findTextMutation("workspaces-web-admin-placement-topology")?.value || "", /id: "admin\.tools-menu"/);
|
|
420
420
|
assert.match(findTextMutation("workspaces-web-admin-placement-topology")?.value || "", /outlet: "admin-cog:primary-menu"/);
|
|
421
|
-
assert.deepEqual(findFileMutation("
|
|
421
|
+
assert.deepEqual(findFileMutation("workspaces-web-page-admin-workspace-settings"), {
|
|
422
422
|
from: "templates/src/pages/admin/workspace/settings/index.vue",
|
|
423
423
|
toSurface: "admin",
|
|
424
424
|
toSurfacePath: "workspace/settings/index.vue",
|
|
425
425
|
ownership: "app",
|
|
426
426
|
reason: "Install workspace settings index stub scaffold for app-owned landing or redirect behavior.",
|
|
427
427
|
category: "workspaces-web",
|
|
428
|
-
id: "
|
|
428
|
+
id: "workspaces-web-page-admin-workspace-settings",
|
|
429
429
|
when: {
|
|
430
430
|
config: "tenancyMode",
|
|
431
431
|
in: ["personal", "workspaces"]
|
|
432
432
|
}
|
|
433
433
|
});
|
|
434
|
-
assert.deepEqual(findSourceMutation("
|
|
434
|
+
assert.deepEqual(findSourceMutation("workspaces-web-main-client-provider-account-settings-section-import"), {
|
|
435
435
|
op: "ensure-import",
|
|
436
436
|
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
437
437
|
defaultImport: "AccountSettingsInvitesSection",
|
|
438
438
|
from: "../components/AccountSettingsInvitesSection.vue",
|
|
439
439
|
reason: "Bind app-owned account invites section component into local main client provider imports.",
|
|
440
440
|
category: "workspaces-web",
|
|
441
|
-
id: "
|
|
441
|
+
id: "workspaces-web-main-client-provider-account-settings-section-import"
|
|
442
442
|
});
|
|
443
|
-
assert.deepEqual(findSourceMutation("
|
|
443
|
+
assert.deepEqual(findSourceMutation("workspaces-web-main-client-provider-account-settings-section-register"), {
|
|
444
444
|
op: "ensure-call",
|
|
445
445
|
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
446
446
|
callee: "registerMainClientComponent",
|
|
@@ -448,6 +448,6 @@ test("workspaces-web packageMetadata metadata advertises admin settings outlets"
|
|
|
448
448
|
beforeClass: "MainClientProvider",
|
|
449
449
|
reason: "Bind app-owned account invites section component token into local main client provider registry.",
|
|
450
450
|
category: "workspaces-web",
|
|
451
|
-
id: "
|
|
451
|
+
id: "workspaces-web-main-client-provider-account-settings-section-register"
|
|
452
452
|
});
|
|
453
453
|
});
|
|
@@ -6,9 +6,9 @@ import { readFile } from "node:fs/promises";
|
|
|
6
6
|
|
|
7
7
|
const TEST_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const PACKAGE_DIR = path.resolve(TEST_DIRECTORY, "..");
|
|
9
|
-
const COMPONENT_PATH = path.join(PACKAGE_DIR, "src", "client", "components", "
|
|
9
|
+
const COMPONENT_PATH = path.join(PACKAGE_DIR, "src", "client", "components", "WorkspaceSelector.vue");
|
|
10
10
|
|
|
11
|
-
test("
|
|
11
|
+
test("WorkspaceSelector passes workspaceSlug through generic page params", async () => {
|
|
12
12
|
const source = await readFile(COMPONENT_PATH, "utf8");
|
|
13
13
|
|
|
14
14
|
assert.match(
|
|
@@ -18,7 +18,7 @@ test("UsersWorkspaceSelector passes workspaceSlug through generic page params",
|
|
|
18
18
|
assert.doesNotMatch(source, /workspaceSlug:\s*normalizedSlug,\s*mode:\s*"workspace"/s);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
test("
|
|
21
|
+
test("WorkspaceSelector activator preserves the generated tap-target contract", async () => {
|
|
22
22
|
const source = await readFile(COMPONENT_PATH, "utf8");
|
|
23
23
|
|
|
24
24
|
assert.match(source, /class="users-workspace-selector__activator text-none"/);
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { createTransientRetryHttpClient } from "@jskit-ai/http-runtime/client";
|
|
2
|
-
|
|
3
|
-
const workspacesWebHttpClient = createTransientRetryHttpClient({
|
|
4
|
-
credentials: "include",
|
|
5
|
-
csrf: {
|
|
6
|
-
sessionPath: "/api/session"
|
|
7
|
-
}
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
export { workspacesWebHttpClient };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { hasPermission, normalizePermissionList } from "@jskit-ai/kernel/shared/support";
|
|
2
|
-
|
|
3
|
-
function toPermissionSet(values) {
|
|
4
|
-
const normalized = normalizePermissionList(values);
|
|
5
|
-
if (normalized.length < 1) {
|
|
6
|
-
return new Set();
|
|
7
|
-
}
|
|
8
|
-
return new Set(normalized);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function arePermissionListsEqual(left, right) {
|
|
12
|
-
const leftSet = toPermissionSet(left);
|
|
13
|
-
const rightSet = toPermissionSet(right);
|
|
14
|
-
if (leftSet.size !== rightSet.size) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
for (const permission of leftSet) {
|
|
19
|
-
if (!rightSet.has(permission)) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { normalizePermissionList, arePermissionListsEqual, hasPermission };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|