@jskit-ai/users-web 0.1.37 → 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.
Files changed (87) hide show
  1. package/package.descriptor.mjs +13 -244
  2. package/package.json +17 -13
  3. package/src/client/components/ConsoleSettingsClientElement.vue +1 -1
  4. package/src/client/components/UsersSurfaceAwareMenuLinkItem.vue +14 -25
  5. package/src/client/components/WorkspaceMembersClientElement.vue +3 -3
  6. package/src/client/components/WorkspaceProfileClientElement.vue +1 -1
  7. package/src/client/components/WorkspaceSettingsFieldsClientElement.vue +1 -1
  8. package/src/client/components/WorkspacesClientElement.vue +2 -2
  9. package/src/client/composables/account-settings/accountSettingsAvatarUploadRuntime.js +61 -0
  10. package/src/client/composables/{accountSettingsInvitesRuntime.js → account-settings/accountSettingsInvitesRuntime.js} +1 -1
  11. package/src/client/composables/{accountSettingsRuntimeHelpers.js → account-settings/accountSettingsRuntimeHelpers.js} +1 -1
  12. package/src/client/composables/crud/crudBindingSupport.js +75 -0
  13. package/src/client/composables/{crudLookupFieldLabelSupport.js → crud/crudLookupFieldLabelSupport.js} +1 -1
  14. package/src/client/composables/{crudLookupFieldRuntime.js → crud/crudLookupFieldRuntime.js} +6 -2
  15. package/src/client/composables/{crudSchemaFormHelpers.js → crud/crudSchemaFormHelpers.js} +155 -2
  16. package/src/client/composables/internal/crudListParentTitleSupport.js +168 -0
  17. package/src/client/composables/internal/useOperationScope.js +1 -1
  18. package/src/client/composables/{useAddEdit.js → records/useAddEdit.js} +9 -9
  19. package/src/client/composables/{useCrudSchemaForm.js → records/useCrudAddEdit.js} +32 -15
  20. package/src/client/composables/records/useCrudList.js +83 -0
  21. package/src/client/composables/records/useCrudView.js +35 -0
  22. package/src/client/composables/{useList.js → records/useList.js} +31 -57
  23. package/src/client/composables/{useView.js → records/useView.js} +6 -9
  24. package/src/client/composables/{addEditUiRuntime.js → runtime/addEditUiRuntime.js} +2 -2
  25. package/src/client/composables/{listUiRuntime.js → runtime/listUiRuntime.js} +2 -2
  26. package/src/client/composables/{operationAdapters.js → runtime/operationAdapters.js} +1 -1
  27. package/src/client/composables/{useEndpointResource.js → runtime/useEndpointResource.js} +5 -5
  28. package/src/client/composables/{useListCore.js → runtime/useListCore.js} +4 -4
  29. package/src/client/composables/{useUiFeedback.js → runtime/useUiFeedback.js} +1 -1
  30. package/src/client/composables/{viewUiRuntime.js → runtime/viewUiRuntime.js} +2 -2
  31. package/src/client/composables/useAccess.js +2 -2
  32. package/src/client/composables/useAccountSettingsRuntime.js +6 -6
  33. package/src/client/composables/useBootstrapQuery.js +1 -1
  34. package/src/client/composables/useCommand.js +5 -5
  35. package/src/client/composables/useCrudListParentTitle.js +131 -0
  36. package/src/client/composables/usePagedCollection.js +3 -3
  37. package/src/client/composables/useScopeRuntime.js +1 -1
  38. package/src/client/index.js +1 -0
  39. package/src/client/providers/UsersWebClientProvider.js +0 -12
  40. package/src/client/providers/UsersWorkspacesClientProvider.js +26 -0
  41. package/src/client/support/menuLinkTarget.js +93 -0
  42. package/templates/src/components/account/settings/AccountSettingsClientElement.vue +16 -9
  43. package/templates/src/pages/console/settings/index.vue +1 -0
  44. package/test/addEditUiRuntime.test.js +1 -1
  45. package/test/crudBindingSupport.test.js +110 -0
  46. package/test/crudLookupFieldRuntime.test.js +1 -1
  47. package/test/errorMessageHelpers.test.js +1 -1
  48. package/test/exportsContract.test.js +10 -1
  49. package/test/listQueryParamSupport.test.js +1 -1
  50. package/test/listUiRuntime.test.js +1 -1
  51. package/test/menuLinkTarget.test.js +116 -0
  52. package/test/permissions.test.js +2 -2
  53. package/test/refValueHelpers.test.js +1 -1
  54. package/test/resourceLoadStateHelpers.test.js +1 -1
  55. package/test/routeTemplateHelpers.test.js +1 -1
  56. package/test/scopeHelpers.test.js +1 -1
  57. package/test/settingsPlacementContract.test.js +44 -0
  58. package/test/{useCrudSchemaForm.test.js → useCrudAddEdit.test.js} +81 -1
  59. package/test/useCrudListParentTitle.test.js +143 -0
  60. package/test/useListSearchSupport.test.js +1 -1
  61. package/test/viewCoreLoading.test.js +1 -1
  62. package/test/viewUiRuntime.test.js +1 -1
  63. package/src/client/composables/accountSettingsAvatarUploadRuntime.js +0 -95
  64. package/templates/packages/main/src/client/components/AccountPendingInvitesCue.vue +0 -162
  65. package/templates/src/components/WorkspaceNotFoundCard.vue +0 -34
  66. package/templates/src/composables/useWorkspaceNotFoundState.js +0 -41
  67. package/templates/src/pages/admin/members/index.vue +0 -7
  68. package/templates/src/pages/admin/workspace/settings/index.vue +0 -16
  69. package/templates/src/surfaces/admin/index.vue +0 -29
  70. package/templates/src/surfaces/admin/root.vue +0 -20
  71. package/templates/src/surfaces/app/index.vue +0 -27
  72. package/templates/src/surfaces/app/root.vue +0 -20
  73. /package/src/client/composables/{accountSettingsRuntimeConstants.js → account-settings/accountSettingsRuntimeConstants.js} +0 -0
  74. /package/src/client/composables/{modelStateHelpers.js → runtime/modelStateHelpers.js} +0 -0
  75. /package/src/client/composables/{operationUiHelpers.js → runtime/operationUiHelpers.js} +0 -0
  76. /package/src/client/composables/{operationValidationHelpers.js → runtime/operationValidationHelpers.js} +0 -0
  77. /package/src/client/composables/{useAddEditCore.js → runtime/useAddEditCore.js} +0 -0
  78. /package/src/client/composables/{useCommandCore.js → runtime/useCommandCore.js} +0 -0
  79. /package/src/client/composables/{useFieldErrorBag.js → runtime/useFieldErrorBag.js} +0 -0
  80. /package/src/client/composables/{useViewCore.js → runtime/useViewCore.js} +0 -0
  81. /package/src/client/composables/{errorMessageHelpers.js → support/errorMessageHelpers.js} +0 -0
  82. /package/src/client/composables/{listQueryParamSupport.js → support/listQueryParamSupport.js} +0 -0
  83. /package/src/client/composables/{listSearchSupport.js → support/listSearchSupport.js} +0 -0
  84. /package/src/client/composables/{refValueHelpers.js → support/refValueHelpers.js} +0 -0
  85. /package/src/client/composables/{resourceLoadStateHelpers.js → support/resourceLoadStateHelpers.js} +0 -0
  86. /package/src/client/composables/{routeTemplateHelpers.js → support/routeTemplateHelpers.js} +0 -0
  87. /package/src/client/composables/{scopeHelpers.js → support/scopeHelpers.js} +0 -0
@@ -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.37",
4
+ version: "0.1.40",
5
5
  kind: "runtime",
6
- description: "Users web module: workspace selector shell element plus workspace/profile/members UI elements.",
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: "workspace-tools",
102
+ host: "console-settings",
121
103
  position: "primary-menu",
122
- surfaces: ["admin"],
123
- source: "src/client/components/UsersWorkspaceToolsWidget.vue"
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.22",
235
- "@jskit-ai/realtime": "0.1.22",
236
- "@jskit-ai/kernel": "0.1.23",
237
- "@jskit-ai/shell-web": "0.1.22",
238
- "@jskit-ai/uploads-image-web": "0.1.1",
239
- "@jskit-ai/users-core": "0.1.32",
240
- "vuetify": "^4.0.0"
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,33 +1,37 @@
1
1
  {
2
2
  "name": "@jskit-ai/users-web",
3
- "version": "0.1.37",
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
- "./client/composables/useAddEdit": "./src/client/composables/useAddEdit.js",
12
- "./client/composables/useCrudSchemaForm": "./src/client/composables/useCrudSchemaForm.js",
13
- "./client/composables/crudLookupFieldRuntime": "./src/client/composables/crudLookupFieldRuntime.js",
14
- "./client/composables/useList": "./src/client/composables/useList.js",
15
- "./client/composables/useView": "./src/client/composables/useView.js",
12
+ "./client/composables/useAddEdit": "./src/client/composables/records/useAddEdit.js",
13
+ "./client/composables/useCrudAddEdit": "./src/client/composables/records/useCrudAddEdit.js",
14
+ "./client/composables/crudLookupFieldRuntime": "./src/client/composables/crud/crudLookupFieldRuntime.js",
15
+ "./client/composables/useList": "./src/client/composables/records/useList.js",
16
+ "./client/composables/useCrudList": "./src/client/composables/records/useCrudList.js",
17
+ "./client/composables/useCrudListParentTitle": "./src/client/composables/useCrudListParentTitle.js",
18
+ "./client/composables/useView": "./src/client/composables/records/useView.js",
19
+ "./client/composables/useCrudView": "./src/client/composables/records/useCrudView.js",
16
20
  "./client/composables/usePagedCollection": "./src/client/composables/usePagedCollection.js",
17
21
  "./client/composables/useAccountSettingsRuntime": "./src/client/composables/useAccountSettingsRuntime.js",
18
22
  "./client/composables/usePaths": "./src/client/composables/usePaths.js",
19
23
  "./client/composables/useWorkspaceRouteContext": "./src/client/composables/useWorkspaceRouteContext.js",
20
- "./client/support/realtimeWorkspace": "./src/client/support/realtimeWorkspace.js"
24
+ "./client/support/menuLinkTarget": "./src/client/support/menuLinkTarget.js"
21
25
  },
22
26
  "dependencies": {
23
27
  "@tanstack/vue-query": "5.92.12",
24
28
  "@mdi/js": "^7.4.47",
25
- "@jskit-ai/http-runtime": "0.1.22",
26
- "@jskit-ai/kernel": "0.1.23",
27
- "@jskit-ai/realtime": "0.1.22",
28
- "@jskit-ai/shell-web": "0.1.22",
29
- "@jskit-ai/uploads-image-web": "0.1.1",
30
- "@jskit-ai/users-core": "0.1.32",
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",
31
35
  "vuetify": "^4.0.0"
32
36
  }
33
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.settings.forms</code>.
9
+ forms to <code>console-settings:forms</code>.
10
10
  </p>
11
11
  </v-sheet>
12
12
  </v-col>
@@ -1,9 +1,10 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
+ import { useRoute } from "vue-router";
3
4
  import { useWebPlacementContext } from "@jskit-ai/shell-web/client/placement";
4
5
  import { usePaths } from "../composables/usePaths.js";
5
- import { surfaceRequiresWorkspaceFromPlacementContext } from "../lib/workspaceSurfaceContext.js";
6
6
  import { resolveMenuLinkIcon } from "../lib/menuIcons.js";
7
+ import { resolveMenuLinkTarget } from "../support/menuLinkTarget.js";
7
8
 
8
9
  const props = defineProps({
9
10
  label: {
@@ -36,34 +37,22 @@ const props = defineProps({
36
37
  }
37
38
  });
38
39
 
40
+ const route = useRoute();
39
41
  const paths = usePaths();
40
42
  const { context: placementContext } = useWebPlacementContext();
41
43
 
42
- const targetSurfaceId = computed(() => {
43
- const explicitSurface = String(props.surface || "").trim().toLowerCase();
44
- if (explicitSurface && explicitSurface !== "*") {
45
- return explicitSurface;
46
- }
47
-
48
- return String(paths.currentSurfaceId.value || "").trim().toLowerCase();
49
- });
50
-
51
44
  const resolvedTo = computed(() => {
52
- const explicitTo = String(props.to || "").trim();
53
- if (explicitTo) {
54
- return explicitTo;
55
- }
56
-
57
- const workspaceRequired = surfaceRequiresWorkspaceFromPlacementContext(
58
- placementContext.value,
59
- targetSurfaceId.value
60
- );
61
- const suffix = workspaceRequired ? props.workspaceSuffix : props.nonWorkspaceSuffix;
62
- const normalizedSuffix = String(suffix || "/").trim() || "/";
63
-
64
- return paths.page(normalizedSuffix, {
65
- surface: targetSurfaceId.value,
66
- mode: "auto"
45
+ return resolveMenuLinkTarget({
46
+ to: props.to,
47
+ surface: props.surface,
48
+ currentSurfaceId: paths.currentSurfaceId.value,
49
+ placementContext: placementContext.value,
50
+ workspaceSuffix: props.workspaceSuffix,
51
+ nonWorkspaceSuffix: props.nonWorkspaceSuffix,
52
+ routeParams: route.params || {},
53
+ resolvePagePath(relativePath, options = {}) {
54
+ return paths.page(relativePath, options);
55
+ }
67
56
  });
68
57
  });
69
58
 
@@ -23,11 +23,11 @@ import { computed, reactive, ref, watch } from "vue";
23
23
  import { formatDateTime } from "@jskit-ai/kernel/shared/support";
24
24
  import MembersAdminClientElement from "./MembersAdminClientElement.vue";
25
25
  import { useCommand } from "../composables/useCommand.js";
26
- import { useList } from "../composables/useList.js";
27
- import { useView } from "../composables/useView.js";
26
+ import { useList } from "../composables/records/useList.js";
27
+ import { useView } from "../composables/records/useView.js";
28
28
  import { usePaths } from "../composables/usePaths.js";
29
29
  import { useAccess } from "../composables/useAccess.js";
30
- import { useUiFeedback } from "../composables/useUiFeedback.js";
30
+ import { useUiFeedback } from "../composables/runtime/useUiFeedback.js";
31
31
  import { useWorkspaceRouteContext } from "../composables/useWorkspaceRouteContext.js";
32
32
  import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
33
33
  import { createWorkspaceRealtimeMatcher } from "../support/realtimeWorkspace.js";
@@ -71,7 +71,7 @@ import { computed, reactive } from "vue";
71
71
  import { validateOperationSection } from "@jskit-ai/http-runtime/shared/validators/operationValidation";
72
72
  import { workspaceResource } from "@jskit-ai/users-core/shared/resources/workspaceResource";
73
73
  import { USERS_ROUTE_VISIBILITY_WORKSPACE } from "@jskit-ai/users-core/shared/support/usersVisibility";
74
- import { useAddEdit } from "../composables/useAddEdit.js";
74
+ import { useAddEdit } from "../composables/records/useAddEdit.js";
75
75
  import { buildWorkspaceQueryKey } from "../support/workspaceQueryKeys.js";
76
76
 
77
77
  const emit = defineEmits(["saved"]);
@@ -176,7 +176,7 @@ import {
176
176
  DEFAULT_WORKSPACE_LIGHT_PALETTE,
177
177
  resolveWorkspaceThemePalettes
178
178
  } from "@jskit-ai/users-core/shared/settings";
179
- import { useAddEdit } from "../composables/useAddEdit.js";
179
+ import { useAddEdit } from "../composables/records/useAddEdit.js";
180
180
  import { useWorkspaceRouteContext } from "../composables/useWorkspaceRouteContext.js";
181
181
  import { createWorkspaceRealtimeMatcher } from "../support/realtimeWorkspace.js";
182
182
  import { buildWorkspaceQueryKey } from "../support/workspaceQueryKeys.js";
@@ -8,12 +8,12 @@ import {
8
8
  import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
9
9
  import { normalizeWorkspaceList } from "../lib/bootstrap.js";
10
10
  import { useCommand } from "../composables/useCommand.js";
11
- import { useView } from "../composables/useView.js";
11
+ import { useView } from "../composables/records/useView.js";
12
12
  import { usePaths } from "../composables/usePaths.js";
13
13
  import { useRealtimeQueryInvalidation } from "../composables/useRealtimeQueryInvalidation.js";
14
14
  import { useWorkspaceSurfaceId } from "../composables/useWorkspaceSurfaceId.js";
15
15
  import { USERS_ROUTE_VISIBILITY_PUBLIC } from "@jskit-ai/users-core/shared/support/usersVisibility";
16
- import { normalizePendingInvite } from "../composables/accountSettingsRuntimeHelpers.js";
16
+ import { normalizePendingInvite } from "../composables/account-settings/accountSettingsRuntimeHelpers.js";
17
17
 
18
18
  const route = useRoute();
19
19
  const router = useRouter();
@@ -0,0 +1,61 @@
1
+ import "@jskit-ai/uploads-image-web/client/styles";
2
+ import { createManagedImageAssetRuntime } from "@jskit-ai/uploads-image-web/client/composables/createManagedImageAssetRuntime";
3
+ import { resolveFieldErrors } from "@jskit-ai/http-runtime/client";
4
+ import { usersWebHttpClient } from "../../lib/httpClient.js";
5
+
6
+ function createAccountSettingsAvatarUploadRuntime({
7
+ queryClient,
8
+ sessionQueryKey,
9
+ accountSettingsQueryKey,
10
+ selectedAvatarFileName,
11
+ applySettingsData,
12
+ reportAccountFeedback
13
+ } = {}) {
14
+ async function resolveCsrfToken() {
15
+ const sessionPayload = await queryClient.fetchQuery({
16
+ queryKey: sessionQueryKey,
17
+ queryFn: () =>
18
+ usersWebHttpClient.request("/api/session", {
19
+ method: "GET"
20
+ }),
21
+ staleTime: 60_000
22
+ });
23
+
24
+ const csrfToken = String(sessionPayload?.csrfToken || "");
25
+ if (!csrfToken) {
26
+ throw new Error("Unable to prepare secure avatar upload request.");
27
+ }
28
+
29
+ return csrfToken;
30
+ }
31
+
32
+ return createManagedImageAssetRuntime({
33
+ uploadEndpoint: "/api/settings/profile/avatar",
34
+ fieldName: "avatar",
35
+ selectedFileName: selectedAvatarFileName,
36
+ resolveRequestHeaders: async () => ({
37
+ "csrf-token": await resolveCsrfToken()
38
+ }),
39
+ onUploadSuccess: ({ data }) => {
40
+ applySettingsData(data);
41
+ queryClient.setQueryData(accountSettingsQueryKey, data);
42
+ },
43
+ reportFeedback: reportAccountFeedback,
44
+ resolveUploadErrorMessage: ({ error, response, defaultMessage }) => {
45
+ const body = response?.body && typeof response.body === "object" ? response.body : {};
46
+ const fieldErrors = resolveFieldErrors(body);
47
+ return String(fieldErrors.avatar || body?.error || error?.message || defaultMessage);
48
+ },
49
+ messages: {
50
+ uploadSuccess: "Avatar uploaded.",
51
+ uploadInvalidResponse: "Avatar uploaded, but the response payload was invalid.",
52
+ uploadError: "Unable to upload avatar.",
53
+ uploadRestriction: "Selected avatar file does not meet upload restrictions.",
54
+ editorUnavailable: "Avatar editor is unavailable in this environment.",
55
+ changeError: "Avatar uploaded, but the settings view could not refresh."
56
+ },
57
+ source: "users-web.account-settings-runtime:avatar"
58
+ });
59
+ }
60
+
61
+ export { createAccountSettingsAvatarUploadRuntime };
@@ -1,4 +1,4 @@
1
- import { resolveErrorStatusCode } from "../support/runtimeNormalization.js";
1
+ import { resolveErrorStatusCode } from "../../support/runtimeNormalization.js";
2
2
 
3
3
  function createAccountSettingsInvitesRuntime({
4
4
  invitesAvailable,
@@ -3,7 +3,7 @@ import {
3
3
  normalizeReturnToPath as normalizeSharedReturnToPath,
4
4
  resolveAllowedOriginsFromPlacementContext
5
5
  } from "@jskit-ai/kernel/shared/support";
6
- import { normalizeRecord } from "../support/runtimeNormalization.js";
6
+ import { normalizeRecord } from "../../support/runtimeNormalization.js";
7
7
 
8
8
  function normalizeReturnToPath(value, { fallback = "/", accountSettingsPath = "/account", allowedOrigins = [] } = {}) {
9
9
  return normalizeSharedReturnToPath(value, {