@jskit-ai/users-web 0.1.79 → 0.1.81

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.
@@ -3,7 +3,7 @@ import { HOME_COG_OUTLET } from "./src/shared/toolsOutletContracts.js";
3
3
  export default Object.freeze({
4
4
  packageVersion: 1,
5
5
  packageId: "@jskit-ai/users-web",
6
- version: "0.1.79",
6
+ version: "0.1.81",
7
7
  kind: "runtime",
8
8
  description: "Users web module: account/profile UI plus shared users web widgets.",
9
9
  dependsOn: [
@@ -112,7 +112,6 @@ export default Object.freeze({
112
112
  outlets: [
113
113
  {
114
114
  target: HOME_COG_OUTLET.target,
115
- defaultLinkComponentToken: HOME_COG_OUTLET.defaultLinkComponentToken,
116
115
  surfaces: ["home"],
117
116
  source: "src/client/components/UsersHomeToolsWidget.vue"
118
117
  },
@@ -122,19 +121,66 @@ export default Object.freeze({
122
121
  source: "src/client/components/AccountSettingsClientElement.vue"
123
122
  }
124
123
  ],
124
+ topology: {
125
+ placements: [
126
+ {
127
+ id: "home.tools-menu",
128
+ description: "Home surface tools menu actions.",
129
+ surfaces: ["home"],
130
+ variants: {
131
+ compact: {
132
+ outlet: HOME_COG_OUTLET.target,
133
+ renderers: {
134
+ link: "local.main.ui.surface-aware-menu-link-item"
135
+ }
136
+ },
137
+ medium: {
138
+ outlet: HOME_COG_OUTLET.target,
139
+ renderers: {
140
+ link: "local.main.ui.surface-aware-menu-link-item"
141
+ }
142
+ },
143
+ expanded: {
144
+ outlet: HOME_COG_OUTLET.target,
145
+ renderers: {
146
+ link: "local.main.ui.surface-aware-menu-link-item"
147
+ }
148
+ }
149
+ }
150
+ },
151
+ {
152
+ id: "settings.sections",
153
+ owner: "account-settings",
154
+ description: "Account settings content sections.",
155
+ surfaces: ["account"],
156
+ variants: {
157
+ compact: {
158
+ outlet: "account-settings:sections"
159
+ },
160
+ medium: {
161
+ outlet: "account-settings:sections"
162
+ },
163
+ expanded: {
164
+ outlet: "account-settings:sections"
165
+ }
166
+ }
167
+ }
168
+ ]
169
+ },
125
170
  contributions: [
126
171
  {
127
172
  id: "users.profile.menu.settings",
128
- target: "auth-profile-menu:primary-menu",
173
+ target: "auth.profile-menu",
174
+ kind: "link",
129
175
  surfaces: ["*"],
130
176
  order: 500,
131
- componentToken: "auth.web.profile.menu.link-item",
132
177
  when: "auth.authenticated === true",
133
178
  source: "mutations.text#users-web-profile-settings-placement"
134
179
  },
135
180
  {
136
181
  id: "users.home.tools.widget",
137
- target: "shell-layout:top-right",
182
+ target: "shell.status",
183
+ kind: "component",
138
184
  surfaces: ["home"],
139
185
  order: 900,
140
186
  componentToken: "users.web.home.tools.widget",
@@ -143,16 +189,18 @@ export default Object.freeze({
143
189
  },
144
190
  {
145
191
  id: "users.home.menu.settings",
146
- target: "home-cog:primary-menu",
192
+ target: "home.tools-menu",
193
+ kind: "link",
147
194
  surfaces: ["home"],
148
195
  order: 100,
149
- componentToken: "local.main.ui.surface-aware-menu-link-item",
150
196
  when: "auth.authenticated === true",
151
197
  source: "mutations.text#users-web-home-tools-placement"
152
198
  },
153
199
  {
154
200
  id: "users.account.settings.profile",
155
- target: "account-settings:sections",
201
+ target: "settings.sections",
202
+ owner: "account-settings",
203
+ kind: "component",
156
204
  surfaces: ["account"],
157
205
  order: 100,
158
206
  componentToken: "local.main.account-settings.section.profile",
@@ -160,7 +208,9 @@ export default Object.freeze({
160
208
  },
161
209
  {
162
210
  id: "users.account.settings.preferences",
163
- target: "account-settings:sections",
211
+ target: "settings.sections",
212
+ owner: "account-settings",
213
+ kind: "component",
164
214
  surfaces: ["account"],
165
215
  order: 200,
166
216
  componentToken: "local.main.account-settings.section.preferences",
@@ -168,7 +218,9 @@ export default Object.freeze({
168
218
  },
169
219
  {
170
220
  id: "users.account.settings.notifications",
171
- target: "account-settings:sections",
221
+ target: "settings.sections",
222
+ owner: "account-settings",
223
+ kind: "component",
172
224
  surfaces: ["account"],
173
225
  order: 300,
174
226
  componentToken: "local.main.account-settings.section.notifications",
@@ -183,12 +235,12 @@ export default Object.freeze({
183
235
  runtime: {
184
236
  "@tanstack/vue-query": "5.92.12",
185
237
  "@mdi/js": "^7.4.47",
186
- "@jskit-ai/http-runtime": "0.1.63",
187
- "@jskit-ai/realtime": "0.1.63",
188
- "@jskit-ai/kernel": "0.1.64",
189
- "@jskit-ai/shell-web": "0.1.63",
190
- "@jskit-ai/uploads-image-web": "0.1.42",
191
- "@jskit-ai/users-core": "0.1.74",
238
+ "@jskit-ai/http-runtime": "0.1.65",
239
+ "@jskit-ai/realtime": "0.1.65",
240
+ "@jskit-ai/kernel": "0.1.66",
241
+ "@jskit-ai/shell-web": "0.1.65",
242
+ "@jskit-ai/uploads-image-web": "0.1.44",
243
+ "@jskit-ai/users-core": "0.1.76",
192
244
  vuetify: "^4.0.0"
193
245
  },
194
246
  dev: {}
@@ -249,7 +301,7 @@ export default Object.freeze({
249
301
  position: "bottom",
250
302
  skipIfContains: "id: \"users.profile.menu.settings\"",
251
303
  value:
252
- "\naddPlacement({\n id: \"users.profile.menu.settings\",\n target: \"auth-profile-menu:primary-menu\",\n surfaces: [\"*\"],\n order: 500,\n componentToken: \"auth.web.profile.menu.link-item\",\n props: {\n label: \"Settings\",\n to: \"/account\"\n },\n when: ({ auth }) => auth?.authenticated === true\n});\n",
304
+ "\naddPlacement({\n id: \"users.profile.menu.settings\",\n target: \"auth.profile-menu\",\n kind: \"link\",\n surfaces: [\"*\"],\n order: 500,\n props: {\n label: \"Settings\",\n to: \"/account\"\n },\n when: ({ auth }) => auth?.authenticated === true\n});\n",
253
305
  reason: "Append users-web profile settings menu placement into app-owned placement registry.",
254
306
  category: "users-web",
255
307
  id: "users-web-profile-settings-placement"
@@ -260,22 +312,44 @@ export default Object.freeze({
260
312
  position: "bottom",
261
313
  skipIfContains: "id: \"users.home.tools.widget\"",
262
314
  value:
263
- "\naddPlacement({\n id: \"users.home.tools.widget\",\n target: \"shell-layout:top-right\",\n surfaces: [\"home\"],\n order: 900,\n componentToken: \"users.web.home.tools.widget\",\n when: ({ auth }) => auth?.authenticated === true\n});\n\naddPlacement({\n id: \"users.home.menu.settings\",\n target: \"home-cog:primary-menu\",\n surfaces: [\"home\"],\n order: 100,\n componentToken: \"local.main.ui.surface-aware-menu-link-item\",\n props: {\n label: \"Settings\",\n surface: \"home\",\n scopedSuffix: \"/settings\",\n unscopedSuffix: \"/settings\"\n },\n when: ({ auth }) => auth?.authenticated === true\n});\n",
315
+ "\naddPlacement({\n id: \"users.home.tools.widget\",\n target: \"shell.status\",\n kind: \"component\",\n surfaces: [\"home\"],\n order: 900,\n componentToken: \"users.web.home.tools.widget\",\n when: ({ auth }) => auth?.authenticated === true\n});\n\naddPlacement({\n id: \"users.home.menu.settings\",\n target: \"home.tools-menu\",\n kind: \"link\",\n surfaces: [\"home\"],\n order: 100,\n props: {\n label: \"Settings\",\n surface: \"home\",\n scopedSuffix: \"/settings\",\n unscopedSuffix: \"/settings\"\n },\n when: ({ auth }) => auth?.authenticated === true\n});\n",
264
316
  reason: "Append users-web home tools widget and settings menu placements into app-owned placement registry.",
265
317
  category: "users-web",
266
318
  id: "users-web-home-tools-placement"
267
319
  },
320
+ {
321
+ op: "append-text",
322
+ file: "src/placementTopology.js",
323
+ position: "bottom",
324
+ skipIfContains: "id: \"home.tools-menu\"",
325
+ value:
326
+ "\naddPlacementTopology({\n id: \"home.tools-menu\",\n description: \"Home surface tools menu actions.\",\n surfaces: [\"home\"],\n variants: {\n compact: {\n outlet: \"home-cog:primary-menu\",\n renderers: {\n link: \"local.main.ui.surface-aware-menu-link-item\"\n }\n },\n medium: {\n outlet: \"home-cog:primary-menu\",\n renderers: {\n link: \"local.main.ui.surface-aware-menu-link-item\"\n }\n },\n expanded: {\n outlet: \"home-cog:primary-menu\",\n renderers: {\n link: \"local.main.ui.surface-aware-menu-link-item\"\n }\n }\n }\n});\n",
327
+ reason: "Append users-web home tools semantic topology into app-owned placement topology.",
328
+ category: "users-web",
329
+ id: "users-web-home-tools-topology"
330
+ },
268
331
  {
269
332
  op: "append-text",
270
333
  file: "src/placement.js",
271
334
  position: "bottom",
272
335
  skipIfContains: "id: \"users.account.settings.profile\"",
273
336
  value:
274
- "\naddPlacement({\n id: \"users.account.settings.profile\",\n target: \"account-settings:sections\",\n surfaces: [\"account\"],\n order: 100,\n componentToken: \"local.main.account-settings.section.profile\",\n props: {\n title: \"Profile\",\n value: \"profile\",\n usesSharedRuntime: true\n }\n});\n\naddPlacement({\n id: \"users.account.settings.preferences\",\n target: \"account-settings:sections\",\n surfaces: [\"account\"],\n order: 200,\n componentToken: \"local.main.account-settings.section.preferences\",\n props: {\n title: \"Preferences\",\n value: \"preferences\",\n usesSharedRuntime: true\n }\n});\n\naddPlacement({\n id: \"users.account.settings.notifications\",\n target: \"account-settings:sections\",\n surfaces: [\"account\"],\n order: 300,\n componentToken: \"local.main.account-settings.section.notifications\",\n props: {\n title: \"Notifications\",\n value: \"notifications\",\n usesSharedRuntime: true\n }\n});\n",
337
+ "\naddPlacement({\n id: \"users.account.settings.profile\",\n target: \"settings.sections\",\n owner: \"account-settings\",\n kind: \"component\",\n surfaces: [\"account\"],\n order: 100,\n componentToken: \"local.main.account-settings.section.profile\",\n props: {\n title: \"Profile\",\n value: \"profile\",\n usesSharedRuntime: true\n }\n});\n\naddPlacement({\n id: \"users.account.settings.preferences\",\n target: \"settings.sections\",\n owner: \"account-settings\",\n kind: \"component\",\n surfaces: [\"account\"],\n order: 200,\n componentToken: \"local.main.account-settings.section.preferences\",\n props: {\n title: \"Preferences\",\n value: \"preferences\",\n usesSharedRuntime: true\n }\n});\n\naddPlacement({\n id: \"users.account.settings.notifications\",\n target: \"settings.sections\",\n owner: \"account-settings\",\n kind: \"component\",\n surfaces: [\"account\"],\n order: 300,\n componentToken: \"local.main.account-settings.section.notifications\",\n props: {\n title: \"Notifications\",\n value: \"notifications\",\n usesSharedRuntime: true\n }\n});\n",
275
338
  reason: "Append users-web account settings section placements into the app-owned placement registry.",
276
339
  category: "users-web",
277
340
  id: "users-web-account-settings-sections-placement"
278
341
  },
342
+ {
343
+ op: "append-text",
344
+ file: "src/placementTopology.js",
345
+ position: "bottom",
346
+ skipIfContains: "id: \"settings.sections\"",
347
+ value:
348
+ "\naddPlacementTopology({\n id: \"settings.sections\",\n owner: \"account-settings\",\n description: \"Account settings content sections.\",\n surfaces: [\"account\"],\n variants: {\n compact: {\n outlet: \"account-settings:sections\"\n },\n medium: {\n outlet: \"account-settings:sections\"\n },\n expanded: {\n outlet: \"account-settings:sections\"\n }\n }\n});\n",
349
+ reason: "Append users-web account settings semantic topology into app-owned placement topology.",
350
+ category: "users-web",
351
+ id: "users-web-account-settings-topology"
352
+ },
279
353
  {
280
354
  op: "append-text",
281
355
  file: "packages/main/src/client/providers/MainClientProvider.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/users-web",
3
- "version": "0.1.79",
3
+ "version": "0.1.81",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -34,12 +34,12 @@
34
34
  "dependencies": {
35
35
  "@tanstack/vue-query": "5.92.12",
36
36
  "@mdi/js": "^7.4.47",
37
- "@jskit-ai/http-runtime": "0.1.63",
38
- "@jskit-ai/kernel": "0.1.64",
39
- "@jskit-ai/realtime": "0.1.63",
40
- "@jskit-ai/shell-web": "0.1.63",
41
- "@jskit-ai/uploads-image-web": "0.1.42",
42
- "@jskit-ai/users-core": "0.1.74",
37
+ "@jskit-ai/http-runtime": "0.1.65",
38
+ "@jskit-ai/kernel": "0.1.66",
39
+ "@jskit-ai/realtime": "0.1.65",
40
+ "@jskit-ai/shell-web": "0.1.65",
41
+ "@jskit-ai/uploads-image-web": "0.1.44",
42
+ "@jskit-ai/users-core": "0.1.76",
43
43
  "vuetify": "^4.0.0"
44
44
  },
45
45
  "peerDependencies": {
@@ -6,7 +6,6 @@ import { HOME_COG_OUTLET } from "../../shared/toolsOutletContracts.js";
6
6
  <template>
7
7
  <ShellOutletMenuWidget
8
8
  :target="HOME_COG_OUTLET.target"
9
- :default-link-component-token="HOME_COG_OUTLET.defaultLinkComponentToken"
10
9
  :aria-label="HOME_COG_OUTLET.ariaLabel"
11
10
  />
12
11
  </template>
@@ -1,12 +1,8 @@
1
- const DEFAULT_COG_LINK_COMPONENT_TOKEN = "local.main.ui.surface-aware-menu-link-item";
2
-
3
1
  const HOME_COG_OUTLET = Object.freeze({
4
2
  target: "home-cog:primary-menu",
5
- defaultLinkComponentToken: DEFAULT_COG_LINK_COMPONENT_TOKEN,
6
3
  ariaLabel: "Home cog"
7
4
  });
8
5
 
9
6
  export {
10
- DEFAULT_COG_LINK_COMPONENT_TOKEN,
11
7
  HOME_COG_OUTLET
12
8
  };
@@ -16,6 +16,19 @@ function readOutlets(host = "") {
16
16
  : [];
17
17
  }
18
18
 
19
+ function findTopology(id, owner = "") {
20
+ const placements = descriptor?.metadata?.ui?.placements?.topology?.placements;
21
+ const normalizedId = String(id || "").trim();
22
+ const normalizedOwner = String(owner || "").trim();
23
+ return Array.isArray(placements)
24
+ ? placements.find((entry) => {
25
+ const entryId = String(entry?.id || "").trim();
26
+ const entryOwner = String(entry?.owner || "").trim();
27
+ return entryId === normalizedId && entryOwner === normalizedOwner;
28
+ }) || null
29
+ : null;
30
+ }
31
+
19
32
  function findContribution(id) {
20
33
  const contributions = descriptor?.metadata?.ui?.placements?.contributions;
21
34
  return Array.isArray(contributions)
@@ -77,7 +90,8 @@ test("users-web home tools widget exposes home-cog outlet", async () => {
77
90
  assert.match(source, /import \{ HOME_COG_OUTLET \} from "\.\.\/\.\.\/shared\/toolsOutletContracts\.js";/);
78
91
  assert.match(source, /<ShellOutletMenuWidget/);
79
92
  assert.match(source, /:target="HOME_COG_OUTLET\.target"/);
80
- assert.match(source, /:default-link-component-token="HOME_COG_OUTLET\.defaultLinkComponentToken"/);
93
+ assert.match(source, /:aria-label="HOME_COG_OUTLET\.ariaLabel"/);
94
+ assert.doesNotMatch(source, /default-link-component-token/);
81
95
  });
82
96
 
83
97
  test("users-web account page template uses the package-owned account settings host", async () => {
@@ -108,7 +122,6 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
108
122
  [
109
123
  {
110
124
  target: "home-cog:primary-menu",
111
- defaultLinkComponentToken: "local.main.ui.surface-aware-menu-link-item",
112
125
  surfaces: ["home"],
113
126
  source: "src/client/components/UsersHomeToolsWidget.vue"
114
127
  }
@@ -124,18 +137,61 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
124
137
  }
125
138
  ]
126
139
  );
140
+ assert.deepEqual(findTopology("home.tools-menu"), {
141
+ id: "home.tools-menu",
142
+ description: "Home surface tools menu actions.",
143
+ surfaces: ["home"],
144
+ variants: {
145
+ compact: {
146
+ outlet: "home-cog:primary-menu",
147
+ renderers: {
148
+ link: "local.main.ui.surface-aware-menu-link-item"
149
+ }
150
+ },
151
+ medium: {
152
+ outlet: "home-cog:primary-menu",
153
+ renderers: {
154
+ link: "local.main.ui.surface-aware-menu-link-item"
155
+ }
156
+ },
157
+ expanded: {
158
+ outlet: "home-cog:primary-menu",
159
+ renderers: {
160
+ link: "local.main.ui.surface-aware-menu-link-item"
161
+ }
162
+ }
163
+ }
164
+ });
165
+ assert.deepEqual(findTopology("settings.sections", "account-settings"), {
166
+ id: "settings.sections",
167
+ owner: "account-settings",
168
+ description: "Account settings content sections.",
169
+ surfaces: ["account"],
170
+ variants: {
171
+ compact: {
172
+ outlet: "account-settings:sections"
173
+ },
174
+ medium: {
175
+ outlet: "account-settings:sections"
176
+ },
177
+ expanded: {
178
+ outlet: "account-settings:sections"
179
+ }
180
+ }
181
+ });
127
182
 
128
183
  expectContribution("users.profile.menu.settings", {
129
- target: "auth-profile-menu:primary-menu",
184
+ target: "auth.profile-menu",
185
+ kind: "link",
130
186
  surfaces: ["*"],
131
187
  order: 500,
132
- componentToken: "auth.web.profile.menu.link-item",
133
188
  when: "auth.authenticated === true",
134
189
  source: "mutations.text#users-web-profile-settings-placement"
135
190
  });
136
191
 
137
192
  expectContribution("users.home.tools.widget", {
138
- target: "shell-layout:top-right",
193
+ target: "shell.status",
194
+ kind: "component",
139
195
  surfaces: ["home"],
140
196
  order: 900,
141
197
  componentToken: "users.web.home.tools.widget",
@@ -144,30 +200,36 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
144
200
  });
145
201
 
146
202
  expectContribution("users.home.menu.settings", {
147
- target: "home-cog:primary-menu",
203
+ target: "home.tools-menu",
204
+ kind: "link",
148
205
  surfaces: ["home"],
149
206
  order: 100,
150
- componentToken: "local.main.ui.surface-aware-menu-link-item",
151
207
  when: "auth.authenticated === true",
152
208
  source: "mutations.text#users-web-home-tools-placement"
153
209
  });
154
210
  assert.equal(findContribution("users.home.settings.general"), null);
155
211
  expectContribution("users.account.settings.profile", {
156
- target: "account-settings:sections",
212
+ target: "settings.sections",
213
+ owner: "account-settings",
214
+ kind: "component",
157
215
  surfaces: ["account"],
158
216
  order: 100,
159
217
  componentToken: "local.main.account-settings.section.profile",
160
218
  source: "mutations.text#users-web-account-settings-sections-placement"
161
219
  });
162
220
  expectContribution("users.account.settings.preferences", {
163
- target: "account-settings:sections",
221
+ target: "settings.sections",
222
+ owner: "account-settings",
223
+ kind: "component",
164
224
  surfaces: ["account"],
165
225
  order: 200,
166
226
  componentToken: "local.main.account-settings.section.preferences",
167
227
  source: "mutations.text#users-web-account-settings-sections-placement"
168
228
  });
169
229
  expectContribution("users.account.settings.notifications", {
170
- target: "account-settings:sections",
230
+ target: "settings.sections",
231
+ owner: "account-settings",
232
+ kind: "component",
171
233
  surfaces: ["account"],
172
234
  order: 300,
173
235
  componentToken: "local.main.account-settings.section.notifications",
@@ -182,18 +244,23 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
182
244
  'id: "users.home.tools.widget"',
183
245
  'componentToken: "users.web.home.tools.widget"',
184
246
  'id: "users.home.menu.settings"',
185
- 'target: "home-cog:primary-menu"',
186
- 'componentToken: "local.main.ui.surface-aware-menu-link-item"',
247
+ 'target: "home.tools-menu"',
248
+ 'kind: "link"',
187
249
  'scopedSuffix: "/settings"',
188
250
  'unscopedSuffix: "/settings"'
189
251
  ]
190
252
  });
253
+ assert.equal(findTextMutation("users-web-home-tools-topology")?.file, "src/placementTopology.js");
254
+ assert.match(findTextMutation("users-web-home-tools-topology")?.value || "", /id: "home\.tools-menu"/);
255
+ assert.match(findTextMutation("users-web-home-tools-topology")?.value || "", /outlet: "home-cog:primary-menu"/);
191
256
  expectTextMutation("users-web-account-settings-sections-placement", {
192
257
  reason: "Append users-web account settings section placements into the app-owned placement registry.",
193
258
  category: "users-web",
194
259
  skipIfContains: 'id: "users.account.settings.profile"',
195
260
  snippets: [
196
261
  'id: "users.account.settings.profile"',
262
+ 'target: "settings.sections"',
263
+ 'owner: "account-settings"',
197
264
  'componentToken: "local.main.account-settings.section.profile"',
198
265
  'value: "profile"',
199
266
  'id: "users.account.settings.preferences"',
@@ -204,6 +271,10 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
204
271
  'value: "notifications"'
205
272
  ]
206
273
  });
274
+ assert.equal(findTextMutation("users-web-account-settings-topology")?.file, "src/placementTopology.js");
275
+ assert.match(findTextMutation("users-web-account-settings-topology")?.value || "", /id: "settings\.sections"/);
276
+ assert.match(findTextMutation("users-web-account-settings-topology")?.value || "", /owner: "account-settings"/);
277
+ assert.match(findTextMutation("users-web-account-settings-topology")?.value || "", /outlet: "account-settings:sections"/);
207
278
 
208
279
  expectTextMutation("users-web-profile-settings-placement", {
209
280
  reason: "Append users-web profile settings menu placement into app-owned placement registry.",
@@ -211,8 +282,8 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
211
282
  skipIfContains: 'id: "users.profile.menu.settings"',
212
283
  snippets: [
213
284
  'id: "users.profile.menu.settings"',
214
- 'target: "auth-profile-menu:primary-menu"',
215
- 'componentToken: "auth.web.profile.menu.link-item"',
285
+ 'target: "auth.profile-menu"',
286
+ 'kind: "link"',
216
287
  'label: "Settings"',
217
288
  'to: "/account"'
218
289
  ]