@jskit-ai/users-web 0.1.38 → 0.1.40
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.descriptor.mjs +13 -244
- package/package.json +9 -9
- package/src/client/components/ConsoleSettingsClientElement.vue +1 -1
- package/src/client/index.js +1 -0
- package/src/client/providers/UsersWebClientProvider.js +0 -12
- package/src/client/providers/UsersWorkspacesClientProvider.js +26 -0
- package/templates/src/components/account/settings/AccountSettingsClientElement.vue +16 -9
- package/templates/src/pages/console/settings/index.vue +1 -0
- package/test/settingsPlacementContract.test.js +44 -0
- package/templates/packages/main/src/client/components/AccountPendingInvitesCue.vue +0 -162
- package/templates/src/components/WorkspaceNotFoundCard.vue +0 -34
- package/templates/src/composables/useWorkspaceNotFoundState.js +0 -41
- package/templates/src/pages/admin/members/index.vue +0 -7
- package/templates/src/pages/admin/workspace/settings/index.vue +0 -16
- package/templates/src/surfaces/admin/index.vue +0 -29
- package/templates/src/surfaces/admin/root.vue +0 -20
- package/templates/src/surfaces/app/index.vue +0 -27
- package/templates/src/surfaces/app/root.vue +0 -20
package/package.descriptor.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/users-web",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.40",
|
|
5
5
|
kind: "runtime",
|
|
6
|
-
description: "Users web module:
|
|
6
|
+
description: "Users web module: account/profile UI plus shared shell link components.",
|
|
7
7
|
dependsOn: [
|
|
8
8
|
"@jskit-ai/http-runtime",
|
|
9
9
|
"@jskit-ai/shell-web",
|
|
@@ -47,14 +47,6 @@ export default Object.freeze({
|
|
|
47
47
|
subpath: "./client/components/ProfileClientElement",
|
|
48
48
|
summary: "Exports profile settings client element scaffold component."
|
|
49
49
|
},
|
|
50
|
-
{
|
|
51
|
-
subpath: "./client/components/WorkspacesClientElement",
|
|
52
|
-
summary: "Exports workspace chooser client element component."
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
subpath: "./client/components/WorkspaceMembersClientElement",
|
|
56
|
-
summary: "Exports workspace members admin client element component."
|
|
57
|
-
},
|
|
58
50
|
{
|
|
59
51
|
subpath: "./client/composables/useAddEdit",
|
|
60
52
|
summary: "Exports add/edit operation composable."
|
|
@@ -91,24 +83,14 @@ export default Object.freeze({
|
|
|
91
83
|
subpath: "./client/composables/useWorkspaceRouteContext",
|
|
92
84
|
summary: "Exports workspace route context composable."
|
|
93
85
|
},
|
|
94
|
-
{
|
|
95
|
-
subpath: "./client/support/realtimeWorkspace",
|
|
96
|
-
summary: "Exports workspace realtime event helpers."
|
|
97
|
-
}
|
|
98
86
|
],
|
|
99
87
|
containerTokens: {
|
|
100
88
|
server: [],
|
|
101
89
|
client: [
|
|
102
|
-
"users.web.workspace.selector",
|
|
103
|
-
"users.web.workspace.tools.widget",
|
|
104
90
|
"users.web.shell.menu-link-item",
|
|
105
91
|
"users.web.shell.surface-aware-menu-link-item",
|
|
106
92
|
"users.web.profile.menu.surface-switch-item",
|
|
107
|
-
"users.web.workspace-settings.menu-item",
|
|
108
|
-
"users.web.workspace-members.menu-item",
|
|
109
93
|
"users.web.profile.element",
|
|
110
|
-
"users.web.members-admin.element",
|
|
111
|
-
"users.web.workspace-settings.element",
|
|
112
94
|
"users.web.bootstrap-placement.runtime"
|
|
113
95
|
]
|
|
114
96
|
}
|
|
@@ -117,16 +99,10 @@ export default Object.freeze({
|
|
|
117
99
|
placements: {
|
|
118
100
|
outlets: [
|
|
119
101
|
{
|
|
120
|
-
host: "
|
|
102
|
+
host: "console-settings",
|
|
121
103
|
position: "primary-menu",
|
|
122
|
-
surfaces: ["
|
|
123
|
-
source: "src/
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
host: "workspace-settings",
|
|
127
|
-
position: "forms",
|
|
128
|
-
surfaces: ["admin"],
|
|
129
|
-
source: "templates/src/pages/admin/workspace/settings/index.vue"
|
|
104
|
+
surfaces: ["console"],
|
|
105
|
+
source: "templates/src/pages/console/settings/index.vue"
|
|
130
106
|
},
|
|
131
107
|
{
|
|
132
108
|
host: "console-settings",
|
|
@@ -136,26 +112,6 @@ export default Object.freeze({
|
|
|
136
112
|
}
|
|
137
113
|
],
|
|
138
114
|
contributions: [
|
|
139
|
-
{
|
|
140
|
-
id: "users.workspace.selector",
|
|
141
|
-
host: "shell-layout",
|
|
142
|
-
position: "top-left",
|
|
143
|
-
surfaces: ["*"],
|
|
144
|
-
order: 200,
|
|
145
|
-
componentToken: "users.web.workspace.selector",
|
|
146
|
-
when: "auth.authenticated === true",
|
|
147
|
-
source: "mutations.text#users-web-placement-block"
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: "users.account.invites.cue",
|
|
151
|
-
host: "shell-layout",
|
|
152
|
-
position: "top-right",
|
|
153
|
-
surfaces: ["*"],
|
|
154
|
-
order: 850,
|
|
155
|
-
componentToken: "local.main.account.pending-invites.cue",
|
|
156
|
-
when: "auth.authenticated === true",
|
|
157
|
-
source: "mutations.text#users-web-placement-block"
|
|
158
|
-
},
|
|
159
115
|
{
|
|
160
116
|
id: "users.profile.menu.surface-switch",
|
|
161
117
|
host: "auth-profile-menu",
|
|
@@ -176,33 +132,6 @@ export default Object.freeze({
|
|
|
176
132
|
when: "auth.authenticated === true",
|
|
177
133
|
source: "mutations.text#users-web-profile-settings-placement"
|
|
178
134
|
},
|
|
179
|
-
{
|
|
180
|
-
id: "users.workspace.tools.widget",
|
|
181
|
-
host: "shell-layout",
|
|
182
|
-
position: "top-right",
|
|
183
|
-
surfaces: ["admin"],
|
|
184
|
-
order: 900,
|
|
185
|
-
componentToken: "users.web.workspace.tools.widget",
|
|
186
|
-
source: "mutations.text#users-web-placement-block"
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
id: "users.workspace.menu.workspace-settings",
|
|
190
|
-
host: "workspace-tools",
|
|
191
|
-
position: "primary-menu",
|
|
192
|
-
surfaces: ["admin"],
|
|
193
|
-
order: 100,
|
|
194
|
-
componentToken: "users.web.workspace-settings.menu-item",
|
|
195
|
-
source: "mutations.text#users-web-placement-block"
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
id: "users.workspace.menu.members",
|
|
199
|
-
host: "workspace-tools",
|
|
200
|
-
position: "primary-menu",
|
|
201
|
-
surfaces: ["admin"],
|
|
202
|
-
order: 200,
|
|
203
|
-
componentToken: "users.web.workspace-members.menu-item",
|
|
204
|
-
source: "mutations.text#users-web-placement-block"
|
|
205
|
-
},
|
|
206
135
|
{
|
|
207
136
|
id: "users.console.menu.settings",
|
|
208
137
|
host: "shell-layout",
|
|
@@ -212,15 +141,6 @@ export default Object.freeze({
|
|
|
212
141
|
componentToken: "users.web.shell.menu-link-item",
|
|
213
142
|
when: "auth.authenticated === true",
|
|
214
143
|
source: "mutations.text#users-web-console-settings-placement"
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
id: "users.workspace.settings.form",
|
|
218
|
-
host: "workspace-settings",
|
|
219
|
-
position: "forms",
|
|
220
|
-
surfaces: ["admin"],
|
|
221
|
-
order: 100,
|
|
222
|
-
componentToken: "users.web.workspace-settings.element",
|
|
223
|
-
source: "mutations.text#users-web-workspace-settings-form-placement"
|
|
224
144
|
}
|
|
225
145
|
]
|
|
226
146
|
}
|
|
@@ -231,13 +151,13 @@ export default Object.freeze({
|
|
|
231
151
|
runtime: {
|
|
232
152
|
"@tanstack/vue-query": "5.92.12",
|
|
233
153
|
"@mdi/js": "^7.4.47",
|
|
234
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
235
|
-
"@jskit-ai/realtime": "0.1.
|
|
236
|
-
"@jskit-ai/kernel": "0.1.
|
|
237
|
-
"@jskit-ai/shell-web": "0.1.
|
|
238
|
-
"@jskit-ai/uploads-image-web": "0.1.
|
|
239
|
-
"@jskit-ai/users-core": "0.1.
|
|
240
|
-
|
|
154
|
+
"@jskit-ai/http-runtime": "0.1.24",
|
|
155
|
+
"@jskit-ai/realtime": "0.1.24",
|
|
156
|
+
"@jskit-ai/kernel": "0.1.25",
|
|
157
|
+
"@jskit-ai/shell-web": "0.1.24",
|
|
158
|
+
"@jskit-ai/uploads-image-web": "0.1.3",
|
|
159
|
+
"@jskit-ai/users-core": "0.1.35",
|
|
160
|
+
vuetify: "^4.0.0"
|
|
241
161
|
},
|
|
242
162
|
dev: {}
|
|
243
163
|
},
|
|
@@ -292,107 +212,6 @@ export default Object.freeze({
|
|
|
292
212
|
category: "users-web",
|
|
293
213
|
id: "users-web-component-account-settings-invites"
|
|
294
214
|
},
|
|
295
|
-
{
|
|
296
|
-
from: "templates/packages/main/src/client/components/AccountPendingInvitesCue.vue",
|
|
297
|
-
to: "packages/main/src/client/components/AccountPendingInvitesCue.vue",
|
|
298
|
-
reason: "Install app-owned account pending invites cue component scaffold.",
|
|
299
|
-
category: "users-web",
|
|
300
|
-
id: "users-web-main-component-account-pending-invites-cue"
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
from: "templates/src/components/WorkspaceNotFoundCard.vue",
|
|
304
|
-
to: "src/components/WorkspaceNotFoundCard.vue",
|
|
305
|
-
reason: "Install app-owned workspace not-found card component used by workspace-dependent surfaces.",
|
|
306
|
-
category: "users-web",
|
|
307
|
-
id: "users-web-component-workspace-not-found-card",
|
|
308
|
-
when: {
|
|
309
|
-
config: "tenancyMode",
|
|
310
|
-
in: ["personal", "workspaces"]
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
from: "templates/src/composables/useWorkspaceNotFoundState.js",
|
|
315
|
-
to: "src/composables/useWorkspaceNotFoundState.js",
|
|
316
|
-
reason: "Install app-owned workspace bootstrap status composable for workspace-dependent surfaces.",
|
|
317
|
-
category: "users-web",
|
|
318
|
-
id: "users-web-composable-workspace-not-found-state",
|
|
319
|
-
when: {
|
|
320
|
-
config: "tenancyMode",
|
|
321
|
-
in: ["personal", "workspaces"]
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
from: "templates/src/surfaces/app/root.vue",
|
|
326
|
-
toSurface: "app",
|
|
327
|
-
toSurfaceRoot: true,
|
|
328
|
-
reason: "Install workspace app surface wrapper shell for users-web.",
|
|
329
|
-
category: "users-web",
|
|
330
|
-
id: "users-web-page-app-wrapper",
|
|
331
|
-
when: {
|
|
332
|
-
config: "tenancyMode",
|
|
333
|
-
in: ["personal", "workspaces"]
|
|
334
|
-
}
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
from: "templates/src/surfaces/app/index.vue",
|
|
338
|
-
toSurface: "app",
|
|
339
|
-
toSurfacePath: "index.vue",
|
|
340
|
-
reason: "Install workspace app surface starter page scaffold for users-web.",
|
|
341
|
-
category: "users-web",
|
|
342
|
-
id: "users-web-page-app-index",
|
|
343
|
-
when: {
|
|
344
|
-
config: "tenancyMode",
|
|
345
|
-
in: ["personal", "workspaces"]
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
from: "templates/src/surfaces/admin/root.vue",
|
|
350
|
-
toSurface: "admin",
|
|
351
|
-
toSurfaceRoot: true,
|
|
352
|
-
reason: "Install workspace admin surface wrapper shell for users-web.",
|
|
353
|
-
category: "users-web",
|
|
354
|
-
id: "users-web-page-admin-wrapper",
|
|
355
|
-
when: {
|
|
356
|
-
config: "tenancyMode",
|
|
357
|
-
in: ["personal", "workspaces"]
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
from: "templates/src/surfaces/admin/index.vue",
|
|
362
|
-
toSurface: "admin",
|
|
363
|
-
toSurfacePath: "index.vue",
|
|
364
|
-
reason: "Install workspace admin surface starter page scaffold for users-web.",
|
|
365
|
-
category: "users-web",
|
|
366
|
-
id: "users-web-page-admin-index",
|
|
367
|
-
when: {
|
|
368
|
-
config: "tenancyMode",
|
|
369
|
-
in: ["personal", "workspaces"]
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
from: "templates/src/pages/admin/members/index.vue",
|
|
374
|
-
toSurface: "admin",
|
|
375
|
-
toSurfacePath: "members/index.vue",
|
|
376
|
-
reason: "Install admin members starter page scaffold for users-web members UI.",
|
|
377
|
-
category: "users-web",
|
|
378
|
-
id: "users-web-page-admin-members",
|
|
379
|
-
when: {
|
|
380
|
-
config: "tenancyMode",
|
|
381
|
-
in: ["personal", "workspaces"]
|
|
382
|
-
}
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
from: "templates/src/pages/admin/workspace/settings/index.vue",
|
|
386
|
-
toSurface: "admin",
|
|
387
|
-
toSurfacePath: "workspace/settings/index.vue",
|
|
388
|
-
reason: "Install workspace settings page scaffold for users-web workspace admin UI.",
|
|
389
|
-
category: "users-web",
|
|
390
|
-
id: "users-web-page-admin-workspace-settings",
|
|
391
|
-
when: {
|
|
392
|
-
config: "tenancyMode",
|
|
393
|
-
in: ["personal", "workspaces"]
|
|
394
|
-
}
|
|
395
|
-
},
|
|
396
215
|
{
|
|
397
216
|
from: "templates/src/pages/console/settings/index.vue",
|
|
398
217
|
toSurface: "console",
|
|
@@ -400,7 +219,7 @@ export default Object.freeze({
|
|
|
400
219
|
reason: "Install console settings page scaffold for users-web console UI.",
|
|
401
220
|
category: "users-web",
|
|
402
221
|
id: "users-web-page-console-settings"
|
|
403
|
-
}
|
|
222
|
+
}
|
|
404
223
|
],
|
|
405
224
|
text: [
|
|
406
225
|
{
|
|
@@ -414,41 +233,6 @@ export default Object.freeze({
|
|
|
414
233
|
category: "users-web",
|
|
415
234
|
id: "users-web-surface-config-account"
|
|
416
235
|
},
|
|
417
|
-
{
|
|
418
|
-
op: "append-text",
|
|
419
|
-
file: "src/placement.js",
|
|
420
|
-
position: "bottom",
|
|
421
|
-
skipIfContains: "id: \"users.workspace.selector\"",
|
|
422
|
-
value: "\naddPlacement({\n id: \"users.workspace.selector\",\n host: \"shell-layout\",\n position: \"top-left\",\n surfaces: [\"*\"],\n order: 200,\n componentToken: \"users.web.workspace.selector\",\n props: {\n allowOnNonWorkspaceSurface: true,\n targetSurfaceId: \"app\"\n },\n when: ({ auth }) => {\n return Boolean(auth?.authenticated);\n }\n});\n\naddPlacement({\n id: \"users.account.invites.cue\",\n host: \"shell-layout\",\n position: \"top-right\",\n surfaces: [\"*\"],\n order: 850,\n componentToken: \"local.main.account.pending-invites.cue\",\n when: ({ auth }) => Boolean(auth?.authenticated)\n});\n\naddPlacement({\n id: \"users.workspace.tools.widget\",\n host: \"shell-layout\",\n position: \"top-right\",\n surfaces: [\"admin\"],\n order: 900,\n componentToken: \"users.web.workspace.tools.widget\"\n});\n\naddPlacement({\n id: \"users.workspace.menu.workspace-settings\",\n host: \"workspace-tools\",\n position: \"primary-menu\",\n surfaces: [\"admin\"],\n order: 100,\n componentToken: \"users.web.workspace-settings.menu-item\"\n});\n\naddPlacement({\n id: \"users.workspace.menu.members\",\n host: \"workspace-tools\",\n position: \"primary-menu\",\n surfaces: [\"admin\"],\n order: 200,\n componentToken: \"users.web.workspace-members.menu-item\"\n});\n",
|
|
423
|
-
reason: "Append users-web placement entries into app-owned placement registry.",
|
|
424
|
-
category: "users-web",
|
|
425
|
-
id: "users-web-placement-block",
|
|
426
|
-
when: {
|
|
427
|
-
config: "tenancyMode",
|
|
428
|
-
in: ["personal", "workspaces"]
|
|
429
|
-
}
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
op: "append-text",
|
|
433
|
-
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
434
|
-
position: "top",
|
|
435
|
-
skipIfContains: "import AccountPendingInvitesCue from \"../components/AccountPendingInvitesCue.vue\";",
|
|
436
|
-
value: "import AccountPendingInvitesCue from \"../components/AccountPendingInvitesCue.vue\";\n",
|
|
437
|
-
reason: "Bind app-owned account pending invites cue component into local main client provider imports.",
|
|
438
|
-
category: "users-web",
|
|
439
|
-
id: "users-web-main-client-provider-account-invites-import"
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
op: "append-text",
|
|
443
|
-
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
444
|
-
position: "bottom",
|
|
445
|
-
skipIfContains: "registerMainClientComponent(\"local.main.account.pending-invites.cue\", () => AccountPendingInvitesCue);",
|
|
446
|
-
value:
|
|
447
|
-
"\nregisterMainClientComponent(\"local.main.account.pending-invites.cue\", () => AccountPendingInvitesCue);\n",
|
|
448
|
-
reason: "Bind app-owned account pending invites cue component token into local main client provider registry.",
|
|
449
|
-
category: "users-web",
|
|
450
|
-
id: "users-web-main-client-provider-account-invites-register"
|
|
451
|
-
},
|
|
452
236
|
{
|
|
453
237
|
op: "append-text",
|
|
454
238
|
file: "src/placement.js",
|
|
@@ -481,21 +265,6 @@ export default Object.freeze({
|
|
|
481
265
|
reason: "Append users-web console settings menu placement into app-owned placement registry.",
|
|
482
266
|
category: "users-web",
|
|
483
267
|
id: "users-web-console-settings-placement"
|
|
484
|
-
},
|
|
485
|
-
{
|
|
486
|
-
op: "append-text",
|
|
487
|
-
file: "src/placement.js",
|
|
488
|
-
position: "bottom",
|
|
489
|
-
skipIfContains: "id: \"users.workspace.settings.form\"",
|
|
490
|
-
value:
|
|
491
|
-
"\naddPlacement({\n id: \"users.workspace.settings.form\",\n host: \"workspace-settings\",\n position: \"forms\",\n surfaces: [\"admin\"],\n order: 100,\n componentToken: \"users.web.workspace-settings.element\"\n});\n",
|
|
492
|
-
reason: "Append users-web workspace settings form placement into app-owned placement registry.",
|
|
493
|
-
category: "users-web",
|
|
494
|
-
id: "users-web-workspace-settings-form-placement",
|
|
495
|
-
when: {
|
|
496
|
-
config: "tenancyMode",
|
|
497
|
-
in: ["personal", "workspaces"]
|
|
498
|
-
}
|
|
499
268
|
}
|
|
500
269
|
]
|
|
501
270
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
"./client": "./src/client/index.js",
|
|
10
|
+
"./client/providers/UsersWorkspacesClientProvider": "./src/client/providers/UsersWorkspacesClientProvider.js",
|
|
10
11
|
"./client/components/WorkspaceMembersClientElement": "./src/client/components/WorkspaceMembersClientElement.vue",
|
|
11
12
|
"./client/composables/useAddEdit": "./src/client/composables/records/useAddEdit.js",
|
|
12
13
|
"./client/composables/useCrudAddEdit": "./src/client/composables/records/useCrudAddEdit.js",
|
|
@@ -20,18 +21,17 @@
|
|
|
20
21
|
"./client/composables/useAccountSettingsRuntime": "./src/client/composables/useAccountSettingsRuntime.js",
|
|
21
22
|
"./client/composables/usePaths": "./src/client/composables/usePaths.js",
|
|
22
23
|
"./client/composables/useWorkspaceRouteContext": "./src/client/composables/useWorkspaceRouteContext.js",
|
|
23
|
-
"./client/support/menuLinkTarget": "./src/client/support/menuLinkTarget.js"
|
|
24
|
-
"./client/support/realtimeWorkspace": "./src/client/support/realtimeWorkspace.js"
|
|
24
|
+
"./client/support/menuLinkTarget": "./src/client/support/menuLinkTarget.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@tanstack/vue-query": "5.92.12",
|
|
28
28
|
"@mdi/js": "^7.4.47",
|
|
29
|
-
"@jskit-ai/http-runtime": "0.1.
|
|
30
|
-
"@jskit-ai/kernel": "0.1.
|
|
31
|
-
"@jskit-ai/realtime": "0.1.
|
|
32
|
-
"@jskit-ai/shell-web": "0.1.
|
|
33
|
-
"@jskit-ai/uploads-image-web": "0.1.
|
|
34
|
-
"@jskit-ai/users-core": "0.1.
|
|
29
|
+
"@jskit-ai/http-runtime": "0.1.24",
|
|
30
|
+
"@jskit-ai/kernel": "0.1.25",
|
|
31
|
+
"@jskit-ai/realtime": "0.1.24",
|
|
32
|
+
"@jskit-ai/shell-web": "0.1.24",
|
|
33
|
+
"@jskit-ai/uploads-image-web": "0.1.3",
|
|
34
|
+
"@jskit-ai/users-core": "0.1.35",
|
|
35
35
|
"vuetify": "^4.0.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<h1 class="text-h5 text-sm-h4 mb-3">Console settings</h1>
|
|
7
7
|
<p class="text-body-2 text-sm-body-1 mb-0">
|
|
8
8
|
No console settings are provided by <code>@jskit-ai/users-web</code>. Install a module that contributes
|
|
9
|
-
forms to <code>console
|
|
9
|
+
forms to <code>console-settings:forms</code>.
|
|
10
10
|
</p>
|
|
11
11
|
</v-sheet>
|
|
12
12
|
</v-col>
|
package/src/client/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UsersWebClientProvider } from "./providers/UsersWebClientProvider.js";
|
|
2
2
|
|
|
3
3
|
export { UsersWebClientProvider } from "./providers/UsersWebClientProvider.js";
|
|
4
|
+
export { UsersWorkspacesClientProvider } from "./providers/UsersWorkspacesClientProvider.js";
|
|
4
5
|
|
|
5
6
|
const clientProviders = Object.freeze([UsersWebClientProvider]);
|
|
6
7
|
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import UsersWorkspaceSelector from "../components/UsersWorkspaceSelector.vue";
|
|
2
|
-
import UsersWorkspaceToolsWidget from "../components/UsersWorkspaceToolsWidget.vue";
|
|
3
1
|
import UsersShellMenuLinkItem from "../components/UsersShellMenuLinkItem.vue";
|
|
4
2
|
import UsersSurfaceAwareMenuLinkItem from "../components/UsersSurfaceAwareMenuLinkItem.vue";
|
|
5
3
|
import UsersProfileSurfaceSwitchMenuItem from "../components/UsersProfileSurfaceSwitchMenuItem.vue";
|
|
6
|
-
import UsersWorkspaceSettingsMenuItem from "../components/UsersWorkspaceSettingsMenuItem.vue";
|
|
7
|
-
import UsersWorkspaceMembersMenuItem from "../components/UsersWorkspaceMembersMenuItem.vue";
|
|
8
4
|
import ProfileClientElement from "../components/ProfileClientElement.vue";
|
|
9
|
-
import MembersAdminClientElement from "../components/MembersAdminClientElement.vue";
|
|
10
|
-
import WorkspaceSettingsClientElement from "../components/WorkspaceSettingsClientElement.vue";
|
|
11
5
|
import {
|
|
12
6
|
createBootstrapPlacementRuntime
|
|
13
7
|
} from "../runtime/bootstrapPlacementRuntime.js";
|
|
@@ -21,16 +15,10 @@ class UsersWebClientProvider {
|
|
|
21
15
|
throw new Error("UsersWebClientProvider requires application singleton().");
|
|
22
16
|
}
|
|
23
17
|
|
|
24
|
-
app.singleton("users.web.workspace.selector", () => UsersWorkspaceSelector);
|
|
25
|
-
app.singleton("users.web.workspace.tools.widget", () => UsersWorkspaceToolsWidget);
|
|
26
18
|
app.singleton("users.web.shell.menu-link-item", () => UsersShellMenuLinkItem);
|
|
27
19
|
app.singleton("users.web.shell.surface-aware-menu-link-item", () => UsersSurfaceAwareMenuLinkItem);
|
|
28
20
|
app.singleton("users.web.profile.menu.surface-switch-item", () => UsersProfileSurfaceSwitchMenuItem);
|
|
29
|
-
app.singleton("users.web.workspace-settings.menu-item", () => UsersWorkspaceSettingsMenuItem);
|
|
30
|
-
app.singleton("users.web.workspace-members.menu-item", () => UsersWorkspaceMembersMenuItem);
|
|
31
21
|
app.singleton("users.web.profile.element", () => ProfileClientElement);
|
|
32
|
-
app.singleton("users.web.members-admin.element", () => MembersAdminClientElement);
|
|
33
|
-
app.singleton("users.web.workspace-settings.element", () => WorkspaceSettingsClientElement);
|
|
34
22
|
app.singleton("users.web.bootstrap-placement.runtime", (scope) => createBootstrapPlacementRuntime({ app: scope }));
|
|
35
23
|
}
|
|
36
24
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import UsersWorkspaceSelector from "../components/UsersWorkspaceSelector.vue";
|
|
2
|
+
import UsersWorkspaceToolsWidget from "../components/UsersWorkspaceToolsWidget.vue";
|
|
3
|
+
import UsersWorkspaceSettingsMenuItem from "../components/UsersWorkspaceSettingsMenuItem.vue";
|
|
4
|
+
import UsersWorkspaceMembersMenuItem from "../components/UsersWorkspaceMembersMenuItem.vue";
|
|
5
|
+
import MembersAdminClientElement from "../components/MembersAdminClientElement.vue";
|
|
6
|
+
import WorkspaceSettingsClientElement from "../components/WorkspaceSettingsClientElement.vue";
|
|
7
|
+
|
|
8
|
+
class UsersWorkspacesClientProvider {
|
|
9
|
+
static id = "workspaces.web.client";
|
|
10
|
+
static dependsOn = ["users.web.client"];
|
|
11
|
+
|
|
12
|
+
register(app) {
|
|
13
|
+
if (!app || typeof app.singleton !== "function") {
|
|
14
|
+
throw new Error("UsersWorkspacesClientProvider requires application singleton().");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
app.singleton("users.web.workspace.selector", () => UsersWorkspaceSelector);
|
|
18
|
+
app.singleton("users.web.workspace.tools.widget", () => UsersWorkspaceToolsWidget);
|
|
19
|
+
app.singleton("users.web.workspace-settings.menu-item", () => UsersWorkspaceSettingsMenuItem);
|
|
20
|
+
app.singleton("users.web.workspace-members.menu-item", () => UsersWorkspaceMembersMenuItem);
|
|
21
|
+
app.singleton("users.web.members-admin.element", () => MembersAdminClientElement);
|
|
22
|
+
app.singleton("users.web.workspace-settings.element", () => WorkspaceSettingsClientElement);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { UsersWorkspacesClientProvider };
|
|
@@ -12,17 +12,24 @@ const runtime = useAccountSettingsRuntime();
|
|
|
12
12
|
const route = useRoute();
|
|
13
13
|
const router = useRouter();
|
|
14
14
|
|
|
15
|
-
const sections =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
]
|
|
21
|
-
|
|
15
|
+
const sections = computed(() => {
|
|
16
|
+
const nextSections = [
|
|
17
|
+
{ title: "Profile", value: "profile" },
|
|
18
|
+
{ title: "Preferences", value: "preferences" },
|
|
19
|
+
{ title: "Notifications", value: "notifications" }
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
if (runtime.invites.isAvailable.value) {
|
|
23
|
+
nextSections.push({ title: "Invites", value: "invites" });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Object.freeze(nextSections);
|
|
27
|
+
});
|
|
28
|
+
const sectionValues = computed(() => Object.freeze(sections.value.map((section) => section.value)));
|
|
22
29
|
|
|
23
30
|
function normalizeSection(value) {
|
|
24
31
|
const source = Array.isArray(value) ? value[0] : value;
|
|
25
|
-
return normalizeOneOf(source, sectionValues, "profile");
|
|
32
|
+
return normalizeOneOf(source, sectionValues.value, "profile");
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
function readRouteSection() {
|
|
@@ -61,7 +68,7 @@ const activeTab = computed({
|
|
|
61
68
|
<v-card class="panel-card" rounded="lg" elevation="1" border>
|
|
62
69
|
<v-card-item>
|
|
63
70
|
<v-card-title class="panel-title">Account settings</v-card-title>
|
|
64
|
-
<v-card-subtitle>Global profile, preferences, notifications, and
|
|
71
|
+
<v-card-subtitle>Global profile, preferences, notifications, and account controls.</v-card-subtitle>
|
|
65
72
|
<template #append>
|
|
66
73
|
<v-btn
|
|
67
74
|
variant="text"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import descriptor from "../package.descriptor.mjs";
|
|
7
|
+
|
|
8
|
+
const TEST_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const PACKAGE_DIR = path.resolve(TEST_DIRECTORY, "..");
|
|
10
|
+
|
|
11
|
+
function readSettingsOutlets() {
|
|
12
|
+
const outlets = descriptor?.metadata?.ui?.placements?.outlets;
|
|
13
|
+
return Array.isArray(outlets)
|
|
14
|
+
? outlets.filter((entry) => String(entry?.host || "").trim() === "console-settings")
|
|
15
|
+
: [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
test("users-web console settings template exposes surface-derived settings outlets", async () => {
|
|
19
|
+
const source = await readFile(path.join(PACKAGE_DIR, "templates", "src", "pages", "console", "settings", "index.vue"), "utf8");
|
|
20
|
+
|
|
21
|
+
assert.match(source, /<ShellOutlet host="console-settings" position="primary-menu" \/>/);
|
|
22
|
+
assert.match(source, /<ShellOutlet host="console-settings" position="forms" \/>/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("users-web descriptor metadata advertises console settings outlets with standard positions", () => {
|
|
26
|
+
const outlets = readSettingsOutlets();
|
|
27
|
+
assert.deepEqual(
|
|
28
|
+
outlets,
|
|
29
|
+
[
|
|
30
|
+
{
|
|
31
|
+
host: "console-settings",
|
|
32
|
+
position: "primary-menu",
|
|
33
|
+
surfaces: ["console"],
|
|
34
|
+
source: "templates/src/pages/console/settings/index.vue"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
host: "console-settings",
|
|
38
|
+
position: "forms",
|
|
39
|
+
surfaces: ["console"],
|
|
40
|
+
source: "templates/src/pages/console/settings/index.vue"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
);
|
|
44
|
+
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { computed } from "vue";
|
|
3
|
-
import { useRoute } from "vue-router";
|
|
4
|
-
import { useQuery } from "@tanstack/vue-query";
|
|
5
|
-
import { mdiEmailAlertOutline } from "@mdi/js";
|
|
6
|
-
import { appendQueryString } from "@jskit-ai/kernel/shared/support";
|
|
7
|
-
import {
|
|
8
|
-
useWebPlacementContext,
|
|
9
|
-
resolveSurfaceDefinitionFromPlacementContext,
|
|
10
|
-
resolveSurfacePathFromPlacementContext,
|
|
11
|
-
resolveSurfaceNavigationTargetFromPlacementContext
|
|
12
|
-
} from "@jskit-ai/shell-web/client/placement";
|
|
13
|
-
|
|
14
|
-
const { context: placementContext } = useWebPlacementContext();
|
|
15
|
-
const route = useRoute();
|
|
16
|
-
|
|
17
|
-
function normalizePendingInvitesCount(value) {
|
|
18
|
-
const numeric = Number(value);
|
|
19
|
-
if (!Number.isInteger(numeric) || numeric < 1) {
|
|
20
|
-
return 0;
|
|
21
|
-
}
|
|
22
|
-
return numeric;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function resolveReturnTo() {
|
|
26
|
-
const fullPath = String(route?.fullPath || "").trim();
|
|
27
|
-
if (fullPath.startsWith("/") && !fullPath.startsWith("//")) {
|
|
28
|
-
return fullPath;
|
|
29
|
-
}
|
|
30
|
-
const path = String(route?.path || "").trim();
|
|
31
|
-
if (path.startsWith("/") && !path.startsWith("//")) {
|
|
32
|
-
return path;
|
|
33
|
-
}
|
|
34
|
-
return "/";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function resolveReturnToHref() {
|
|
38
|
-
if (typeof window === "object" && window?.location?.href) {
|
|
39
|
-
return String(window.location.href || "").trim() || resolveReturnTo();
|
|
40
|
-
}
|
|
41
|
-
return resolveReturnTo();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function countPendingInvites(entries = []) {
|
|
45
|
-
if (!Array.isArray(entries)) {
|
|
46
|
-
return 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let total = 0;
|
|
50
|
-
for (const entry of entries) {
|
|
51
|
-
if (!entry || typeof entry !== "object") {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
total += 1;
|
|
55
|
-
}
|
|
56
|
-
return total;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const authenticated = computed(() => placementContext.value?.auth?.authenticated === true);
|
|
60
|
-
|
|
61
|
-
const bootstrapSummaryQuery = useQuery({
|
|
62
|
-
queryKey: ["local-main", "account", "invites-cue", "bootstrap"],
|
|
63
|
-
enabled: authenticated,
|
|
64
|
-
staleTime: 5_000,
|
|
65
|
-
refetchInterval: 15_000,
|
|
66
|
-
queryFn: async () => {
|
|
67
|
-
const response = await fetch("/api/bootstrap", {
|
|
68
|
-
method: "GET",
|
|
69
|
-
credentials: "include",
|
|
70
|
-
headers: {
|
|
71
|
-
accept: "application/json"
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
if (!response.ok) {
|
|
75
|
-
throw new Error(`Bootstrap request failed with status ${response.status}.`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return response.json();
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const placementPendingInvitesCount = computed(() =>
|
|
83
|
-
normalizePendingInvitesCount(placementContext.value?.pendingInvitesCount)
|
|
84
|
-
);
|
|
85
|
-
const bootstrapPendingInvitesCount = computed(() => {
|
|
86
|
-
const payload = bootstrapSummaryQuery.data.value;
|
|
87
|
-
const invitesEnabled = payload?.app?.features?.workspaceInvites === true;
|
|
88
|
-
if (!invitesEnabled) {
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return countPendingInvites(payload?.pendingInvites);
|
|
93
|
-
});
|
|
94
|
-
const pendingInvitesCount = computed(() =>
|
|
95
|
-
Math.max(placementPendingInvitesCount.value, bootstrapPendingInvitesCount.value)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const placementWorkspaceInvitesEnabled = computed(() => placementContext.value?.workspaceInvitesEnabled === true);
|
|
99
|
-
const bootstrapWorkspaceInvitesEnabled = computed(() => {
|
|
100
|
-
const payload = bootstrapSummaryQuery.data.value;
|
|
101
|
-
return payload?.app?.features?.workspaceInvites === true;
|
|
102
|
-
});
|
|
103
|
-
const workspaceInvitesEnabled = computed(
|
|
104
|
-
() => placementWorkspaceInvitesEnabled.value || bootstrapWorkspaceInvitesEnabled.value
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const isVisible = computed(() => {
|
|
108
|
-
return (
|
|
109
|
-
authenticated.value &&
|
|
110
|
-
workspaceInvitesEnabled.value &&
|
|
111
|
-
pendingInvitesCount.value > 0
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const resolvedTo = computed(() => {
|
|
116
|
-
const hasAccountSurface = Boolean(resolveSurfaceDefinitionFromPlacementContext(placementContext.value, "account"));
|
|
117
|
-
const accountSettingsPath = hasAccountSurface
|
|
118
|
-
? resolveSurfacePathFromPlacementContext(placementContext.value, "account", "/")
|
|
119
|
-
: "/account";
|
|
120
|
-
const accountSettingsNavigation = resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
121
|
-
path: accountSettingsPath,
|
|
122
|
-
surfaceId: "account"
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const query = new URLSearchParams({
|
|
126
|
-
section: "invites",
|
|
127
|
-
returnTo: accountSettingsNavigation.sameOrigin ? resolveReturnTo() : resolveReturnToHref()
|
|
128
|
-
});
|
|
129
|
-
return appendQueryString(accountSettingsPath, query.toString());
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const resolvedNavigationTarget = computed(() =>
|
|
133
|
-
resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
134
|
-
path: resolvedTo.value,
|
|
135
|
-
surfaceId: "account"
|
|
136
|
-
})
|
|
137
|
-
);
|
|
138
|
-
</script>
|
|
139
|
-
|
|
140
|
-
<template>
|
|
141
|
-
<v-badge
|
|
142
|
-
v-if="isVisible"
|
|
143
|
-
color="error"
|
|
144
|
-
:content="pendingInvitesCount"
|
|
145
|
-
:model-value="pendingInvitesCount > 0"
|
|
146
|
-
bordered
|
|
147
|
-
offset-x="6"
|
|
148
|
-
offset-y="8"
|
|
149
|
-
>
|
|
150
|
-
<v-btn
|
|
151
|
-
:to="resolvedNavigationTarget.sameOrigin ? resolvedNavigationTarget.href : undefined"
|
|
152
|
-
:href="resolvedNavigationTarget.sameOrigin ? undefined : resolvedNavigationTarget.href"
|
|
153
|
-
variant="tonal"
|
|
154
|
-
color="warning"
|
|
155
|
-
:prepend-icon="mdiEmailAlertOutline"
|
|
156
|
-
size="small"
|
|
157
|
-
class="text-none"
|
|
158
|
-
>
|
|
159
|
-
Invites
|
|
160
|
-
</v-btn>
|
|
161
|
-
</v-badge>
|
|
162
|
-
</template>
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { mdiAlertCircleOutline } from "@mdi/js";
|
|
3
|
-
import { computed } from "vue";
|
|
4
|
-
|
|
5
|
-
const props = defineProps({
|
|
6
|
-
surfaceLabel: {
|
|
7
|
-
type: String,
|
|
8
|
-
default: "Workspace"
|
|
9
|
-
},
|
|
10
|
-
message: {
|
|
11
|
-
type: String,
|
|
12
|
-
default: "Workspace is currently unavailable."
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const normalizedSurfaceLabel = computed(() => String(props.surfaceLabel || "").trim() || "Workspace");
|
|
17
|
-
const normalizedMessage = computed(() => String(props.message || "").trim() || "Workspace is currently unavailable.");
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<template>
|
|
21
|
-
<v-card rounded="lg" elevation="1" border>
|
|
22
|
-
<v-card-item>
|
|
23
|
-
<template #prepend>
|
|
24
|
-
<v-icon :icon="mdiAlertCircleOutline" color="error" />
|
|
25
|
-
</template>
|
|
26
|
-
<v-card-title class="text-h5">Unavailable</v-card-title>
|
|
27
|
-
<v-card-subtitle>{{ normalizedSurfaceLabel }} surface.</v-card-subtitle>
|
|
28
|
-
</v-card-item>
|
|
29
|
-
<v-divider />
|
|
30
|
-
<v-card-text class="d-flex flex-column ga-4">
|
|
31
|
-
<p class="text-medium-emphasis mb-0">{{ normalizedMessage }}</p>
|
|
32
|
-
</v-card-text>
|
|
33
|
-
</v-card>
|
|
34
|
-
</template>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { computed } from "vue";
|
|
2
|
-
import { useRoute } from "vue-router";
|
|
3
|
-
import { normalizeLowerText, normalizeObject } from "@jskit-ai/kernel/shared/support/normalize";
|
|
4
|
-
import { useWebPlacementContext } from "@jskit-ai/shell-web/client/placement";
|
|
5
|
-
|
|
6
|
-
const STATUS_MESSAGES = {
|
|
7
|
-
not_found: "The requested workspace was not found.",
|
|
8
|
-
forbidden: "You do not have access to this workspace.",
|
|
9
|
-
unauthenticated: "You need to sign in to access this workspace.",
|
|
10
|
-
error: "Workspace data could not be loaded right now."
|
|
11
|
-
};
|
|
12
|
-
const DEFAULT_WORKSPACE_UNAVAILABLE_MESSAGE = "Workspace is currently unavailable.";
|
|
13
|
-
const RESOLVED_WORKSPACE_STATUS = "resolved";
|
|
14
|
-
|
|
15
|
-
function useWorkspaceNotFoundState() {
|
|
16
|
-
const route = useRoute();
|
|
17
|
-
const { context: placementContext } = useWebPlacementContext();
|
|
18
|
-
|
|
19
|
-
const routeWorkspaceSlug = computed(() => normalizeLowerText(route?.params?.workspaceSlug));
|
|
20
|
-
|
|
21
|
-
const workspaceBootstrapStatus = computed(() => {
|
|
22
|
-
const statuses = normalizeObject(placementContext.value?.workspaceBootstrapStatuses);
|
|
23
|
-
return normalizeLowerText(statuses[routeWorkspaceSlug.value]);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const workspaceUnavailable = computed(
|
|
27
|
-
() => Boolean(workspaceBootstrapStatus.value) && workspaceBootstrapStatus.value !== RESOLVED_WORKSPACE_STATUS
|
|
28
|
-
);
|
|
29
|
-
const workspaceUnavailableMessage = computed(
|
|
30
|
-
() => STATUS_MESSAGES[workspaceBootstrapStatus.value] || DEFAULT_WORKSPACE_UNAVAILABLE_MESSAGE
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
return Object.freeze({
|
|
34
|
-
routeWorkspaceSlug,
|
|
35
|
-
workspaceBootstrapStatus,
|
|
36
|
-
workspaceUnavailable,
|
|
37
|
-
workspaceUnavailableMessage
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { useWorkspaceNotFoundState };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<section class="settings-page">
|
|
3
|
-
<ShellOutlet host="workspace-settings" position="forms" />
|
|
4
|
-
</section>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup>
|
|
8
|
-
import ShellOutlet from "@jskit-ai/shell-web/client/components/ShellOutlet";
|
|
9
|
-
</script>
|
|
10
|
-
|
|
11
|
-
<style scoped>
|
|
12
|
-
.settings-page {
|
|
13
|
-
display: grid;
|
|
14
|
-
gap: 1rem;
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import WorkspaceNotFoundCard from "@/components/WorkspaceNotFoundCard.vue";
|
|
3
|
-
import { useWorkspaceNotFoundState } from "@/composables/useWorkspaceNotFoundState";
|
|
4
|
-
|
|
5
|
-
const { workspaceUnavailable, workspaceUnavailableMessage } = useWorkspaceNotFoundState();
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<WorkspaceNotFoundCard
|
|
10
|
-
v-if="workspaceUnavailable"
|
|
11
|
-
:message="workspaceUnavailableMessage"
|
|
12
|
-
surface-label="Admin"
|
|
13
|
-
/>
|
|
14
|
-
<v-card v-else rounded="lg" elevation="1" border>
|
|
15
|
-
<v-card-item>
|
|
16
|
-
<template #prepend>
|
|
17
|
-
<v-chip color="primary" size="small" label>Admin</v-chip>
|
|
18
|
-
</template>
|
|
19
|
-
<v-card-title class="text-h5">Workspace Admin</v-card-title>
|
|
20
|
-
<v-card-subtitle>Privileged workspace workflows.</v-card-subtitle>
|
|
21
|
-
</v-card-item>
|
|
22
|
-
<v-divider />
|
|
23
|
-
<v-card-text class="d-flex flex-column ga-4">
|
|
24
|
-
<p class="text-medium-emphasis mb-0">
|
|
25
|
-
Use this area for workspace administration modules.
|
|
26
|
-
</p>
|
|
27
|
-
</v-card-text>
|
|
28
|
-
</v-card>
|
|
29
|
-
</template>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<route lang="json">
|
|
2
|
-
{
|
|
3
|
-
"meta": {
|
|
4
|
-
"jskit": {
|
|
5
|
-
"surface": "admin"
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
</route>
|
|
10
|
-
|
|
11
|
-
<script setup>
|
|
12
|
-
import ShellLayout from "@/components/ShellLayout.vue";
|
|
13
|
-
import { RouterView } from "vue-router";
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<ShellLayout title="" subtitle="">
|
|
18
|
-
<RouterView />
|
|
19
|
-
</ShellLayout>
|
|
20
|
-
</template>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import WorkspaceNotFoundCard from "@/components/WorkspaceNotFoundCard.vue";
|
|
3
|
-
import { useWorkspaceNotFoundState } from "@/composables/useWorkspaceNotFoundState";
|
|
4
|
-
|
|
5
|
-
const { workspaceUnavailable, workspaceUnavailableMessage } = useWorkspaceNotFoundState();
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<WorkspaceNotFoundCard
|
|
10
|
-
v-if="workspaceUnavailable"
|
|
11
|
-
:message="workspaceUnavailableMessage"
|
|
12
|
-
surface-label="App"
|
|
13
|
-
/>
|
|
14
|
-
<v-card v-else rounded="lg" elevation="1" border>
|
|
15
|
-
<v-card-item>
|
|
16
|
-
<template #prepend>
|
|
17
|
-
<v-chip color="primary" size="small" label>App</v-chip>
|
|
18
|
-
</template>
|
|
19
|
-
<v-card-title class="text-h5">Workspace Home</v-card-title>
|
|
20
|
-
<v-card-subtitle>Primary in-workspace surface.</v-card-subtitle>
|
|
21
|
-
</v-card-item>
|
|
22
|
-
<v-divider />
|
|
23
|
-
<v-card-text class="d-flex flex-column ga-4">
|
|
24
|
-
<p class="text-medium-emphasis mb-0">Replace this page with your workspace dashboard modules.</p>
|
|
25
|
-
</v-card-text>
|
|
26
|
-
</v-card>
|
|
27
|
-
</template>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<route lang="json">
|
|
2
|
-
{
|
|
3
|
-
"meta": {
|
|
4
|
-
"jskit": {
|
|
5
|
-
"surface": "app"
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
</route>
|
|
10
|
-
|
|
11
|
-
<script setup>
|
|
12
|
-
import ShellLayout from "@/components/ShellLayout.vue";
|
|
13
|
-
import { RouterView } from "vue-router";
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<ShellLayout title="" subtitle="">
|
|
18
|
-
<RouterView />
|
|
19
|
-
</ShellLayout>
|
|
20
|
-
</template>
|