@jskit-ai/users-web 0.1.51 → 0.1.53
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 +7 -71
- package/package.json +7 -7
- package/src/client/lib/menuIcons.js +1 -10
- package/test/bootstrapPlacementRuntime.test.js +10 -10
- package/test/menuIcons.test.js +1 -2
- package/test/profileSurfaceMenuLinks.test.js +16 -15
- package/test/settingsPlacementContract.test.js +0 -63
- package/test/surfaceAccessPolicy.test.js +11 -11
- package/test/workspaceLinkResolver.test.js +2 -2
- package/test/workspaceSurfacePaths.test.js +2 -2
- package/src/client/components/ConsoleSettingsClientElement.vue +0 -24
- package/templates/src/pages/console/settings/index.vue +0 -8
- package/templates/src/pages/console/settings.vue +0 -32
package/package.descriptor.mjs
CHANGED
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
export default Object.freeze({
|
|
7
7
|
packageVersion: 1,
|
|
8
8
|
packageId: "@jskit-ai/users-web",
|
|
9
|
-
version: "0.1.
|
|
9
|
+
version: "0.1.53",
|
|
10
10
|
kind: "runtime",
|
|
11
11
|
description: "Users web module: account/profile UI plus shared users web widgets.",
|
|
12
12
|
dependsOn: [
|
|
13
13
|
"@jskit-ai/auth-web",
|
|
14
|
-
"@jskit-ai/console-web",
|
|
15
14
|
"@jskit-ai/http-runtime",
|
|
16
15
|
"@jskit-ai/shell-web",
|
|
17
16
|
"@jskit-ai/uploads-image-web",
|
|
@@ -116,12 +115,6 @@ export default Object.freeze({
|
|
|
116
115
|
surfaces: ["admin"],
|
|
117
116
|
source: "src/client/components/UsersWorkspaceToolsWidget.vue"
|
|
118
117
|
},
|
|
119
|
-
{
|
|
120
|
-
target: "console-settings:primary-menu",
|
|
121
|
-
defaultLinkComponentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
122
|
-
surfaces: ["console"],
|
|
123
|
-
source: "templates/src/pages/console/settings.vue"
|
|
124
|
-
}
|
|
125
118
|
],
|
|
126
119
|
contributions: [
|
|
127
120
|
{
|
|
@@ -142,24 +135,6 @@ export default Object.freeze({
|
|
|
142
135
|
when: "auth.authenticated === true",
|
|
143
136
|
source: "mutations.text#users-web-profile-settings-placement"
|
|
144
137
|
},
|
|
145
|
-
{
|
|
146
|
-
id: "users.home.menu.home",
|
|
147
|
-
target: "shell-layout:primary-menu",
|
|
148
|
-
surfaces: ["*"],
|
|
149
|
-
order: 50,
|
|
150
|
-
componentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
151
|
-
when: "auth.authenticated === true",
|
|
152
|
-
source: "mutations.text#users-web-home-shell-menu-placement"
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
id: "users.console.menu.settings",
|
|
156
|
-
target: "shell-layout:primary-menu",
|
|
157
|
-
surfaces: ["console"],
|
|
158
|
-
order: 100,
|
|
159
|
-
componentToken: "local.main.ui.menu-link-item",
|
|
160
|
-
when: "auth.authenticated === true",
|
|
161
|
-
source: "mutations.text#users-web-console-settings-placement"
|
|
162
|
-
},
|
|
163
138
|
{
|
|
164
139
|
id: "users.home.tools.widget",
|
|
165
140
|
target: "shell-layout:top-right",
|
|
@@ -187,13 +162,12 @@ export default Object.freeze({
|
|
|
187
162
|
runtime: {
|
|
188
163
|
"@tanstack/vue-query": "5.92.12",
|
|
189
164
|
"@mdi/js": "^7.4.47",
|
|
190
|
-
"@jskit-ai/
|
|
191
|
-
"@jskit-ai/
|
|
192
|
-
"@jskit-ai/
|
|
193
|
-
"@jskit-ai/
|
|
194
|
-
"@jskit-ai/
|
|
195
|
-
"@jskit-ai/
|
|
196
|
-
"@jskit-ai/users-core": "0.1.46",
|
|
165
|
+
"@jskit-ai/http-runtime": "0.1.37",
|
|
166
|
+
"@jskit-ai/realtime": "0.1.37",
|
|
167
|
+
"@jskit-ai/kernel": "0.1.38",
|
|
168
|
+
"@jskit-ai/shell-web": "0.1.37",
|
|
169
|
+
"@jskit-ai/uploads-image-web": "0.1.16",
|
|
170
|
+
"@jskit-ai/users-core": "0.1.48",
|
|
197
171
|
vuetify: "^4.0.0"
|
|
198
172
|
},
|
|
199
173
|
dev: {}
|
|
@@ -248,22 +222,6 @@ export default Object.freeze({
|
|
|
248
222
|
reason: "Install app-owned account settings invites section scaffold.",
|
|
249
223
|
category: "users-web",
|
|
250
224
|
id: "users-web-component-account-settings-invites"
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
from: "templates/src/pages/console/settings.vue",
|
|
254
|
-
toSurface: "console",
|
|
255
|
-
toSurfacePath: "settings.vue",
|
|
256
|
-
reason: "Install console settings shell route scaffold for users-web console UI.",
|
|
257
|
-
category: "users-web",
|
|
258
|
-
id: "users-web-page-console-settings-shell"
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
from: "templates/src/pages/console/settings/index.vue",
|
|
262
|
-
toSurface: "console",
|
|
263
|
-
toSurfacePath: "settings/index.vue",
|
|
264
|
-
reason: "Install console settings index stub scaffold for app-owned landing or redirect behavior.",
|
|
265
|
-
category: "users-web",
|
|
266
|
-
id: "users-web-page-console-settings"
|
|
267
225
|
}
|
|
268
226
|
],
|
|
269
227
|
text: [
|
|
@@ -300,28 +258,6 @@ export default Object.freeze({
|
|
|
300
258
|
category: "users-web",
|
|
301
259
|
id: "users-web-profile-settings-placement"
|
|
302
260
|
},
|
|
303
|
-
{
|
|
304
|
-
op: "append-text",
|
|
305
|
-
file: "src/placement.js",
|
|
306
|
-
position: "bottom",
|
|
307
|
-
skipIfContains: "id: \"users.home.menu.home\"",
|
|
308
|
-
value:
|
|
309
|
-
"\naddPlacement({\n id: \"users.home.menu.home\",\n target: \"shell-layout:primary-menu\",\n surfaces: [\"*\"],\n order: 50,\n componentToken: \"local.main.ui.surface-aware-menu-link-item\",\n props: {\n label: \"Home\",\n surface: \"home\",\n workspaceSuffix: \"/\",\n nonWorkspaceSuffix: \"/\",\n exact: true\n },\n when: ({ auth }) => Boolean(auth?.authenticated)\n});\n",
|
|
310
|
-
reason: "Append users-web home shell menu placement into app-owned placement registry.",
|
|
311
|
-
category: "users-web",
|
|
312
|
-
id: "users-web-home-shell-menu-placement"
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
op: "append-text",
|
|
316
|
-
file: "src/placement.js",
|
|
317
|
-
position: "bottom",
|
|
318
|
-
skipIfContains: "id: \"users.console.menu.settings\"",
|
|
319
|
-
value:
|
|
320
|
-
"\naddPlacement({\n id: \"users.console.menu.settings\",\n target: \"shell-layout:primary-menu\",\n surfaces: [\"console\"],\n order: 100,\n componentToken: \"local.main.ui.menu-link-item\",\n props: {\n label: \"Settings\",\n to: \"/console/settings\",\n icon: \"mdi-cog-outline\"\n },\n when: ({ auth }) => Boolean(auth?.authenticated)\n});\n",
|
|
321
|
-
reason: "Append users-web console settings menu placement into app-owned placement registry.",
|
|
322
|
-
category: "users-web",
|
|
323
|
-
id: "users-web-console-settings-placement"
|
|
324
|
-
},
|
|
325
261
|
{
|
|
326
262
|
op: "append-text",
|
|
327
263
|
file: "src/placement.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -26,12 +26,12 @@
|
|
|
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.37",
|
|
30
|
+
"@jskit-ai/kernel": "0.1.38",
|
|
31
|
+
"@jskit-ai/realtime": "0.1.37",
|
|
32
|
+
"@jskit-ai/shell-web": "0.1.37",
|
|
33
|
+
"@jskit-ai/uploads-image-web": "0.1.16",
|
|
34
|
+
"@jskit-ai/users-core": "0.1.48",
|
|
35
35
|
"vuetify": "^4.0.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
mdiArrowRightCircleOutline,
|
|
7
7
|
mdiClipboardListOutline,
|
|
8
8
|
mdiCogOutline,
|
|
9
|
-
mdiConsoleNetworkOutline,
|
|
10
9
|
mdiFolderOutline,
|
|
11
10
|
mdiHomeVariantOutline,
|
|
12
11
|
mdiLogin,
|
|
@@ -23,8 +22,7 @@ import { normalizePathname as normalizeKernelPathname } from "@jskit-ai/kernel/s
|
|
|
23
22
|
const SURFACE_SWITCH_ICON_BY_ID = Object.freeze({
|
|
24
23
|
home: mdiHomeVariantOutline,
|
|
25
24
|
app: mdiViewDashboardOutline,
|
|
26
|
-
admin: mdiShieldCrownOutline
|
|
27
|
-
console: mdiConsoleNetworkOutline
|
|
25
|
+
admin: mdiShieldCrownOutline
|
|
28
26
|
});
|
|
29
27
|
|
|
30
28
|
function resolveExplicitIconValue(explicitIcon = "") {
|
|
@@ -157,13 +155,6 @@ function resolveMenuLinkIcon({ icon = "", label = "", to = "" } = {}) {
|
|
|
157
155
|
return mdiRobotOutline;
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
if (
|
|
161
|
-
normalizedLabel.includes("console") ||
|
|
162
|
-
normalizedPathname.startsWith("/console")
|
|
163
|
-
) {
|
|
164
|
-
return mdiConsoleNetworkOutline;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
158
|
if (
|
|
168
159
|
normalizedLabel.includes("admin") ||
|
|
169
160
|
normalizedPathname.includes("/admin")
|
|
@@ -993,15 +993,15 @@ test("bootstrap placement runtime enforces surface access policies after bootstr
|
|
|
993
993
|
},
|
|
994
994
|
surfaceAccessPolicies: {
|
|
995
995
|
public: {},
|
|
996
|
-
|
|
996
|
+
ops_owner: {
|
|
997
997
|
requireAuth: true,
|
|
998
|
-
requireFlagsAll: ["
|
|
998
|
+
requireFlagsAll: ["ops_owner"]
|
|
999
999
|
}
|
|
1000
1000
|
},
|
|
1001
1001
|
surfaceConfig: {
|
|
1002
1002
|
tenancyMode: "workspaces",
|
|
1003
1003
|
defaultSurfaceId: "home",
|
|
1004
|
-
enabledSurfaceIds: ["home", "
|
|
1004
|
+
enabledSurfaceIds: ["home", "ops"],
|
|
1005
1005
|
surfacesById: {
|
|
1006
1006
|
home: {
|
|
1007
1007
|
id: "home",
|
|
@@ -1011,18 +1011,18 @@ test("bootstrap placement runtime enforces surface access policies after bootstr
|
|
|
1011
1011
|
requiresWorkspace: false,
|
|
1012
1012
|
accessPolicyId: "public"
|
|
1013
1013
|
},
|
|
1014
|
-
|
|
1015
|
-
id: "
|
|
1014
|
+
ops: {
|
|
1015
|
+
id: "ops",
|
|
1016
1016
|
enabled: true,
|
|
1017
|
-
pagesRoot: "
|
|
1018
|
-
routeBase: "/
|
|
1017
|
+
pagesRoot: "ops",
|
|
1018
|
+
routeBase: "/ops",
|
|
1019
1019
|
requiresWorkspace: false,
|
|
1020
|
-
accessPolicyId: "
|
|
1020
|
+
accessPolicyId: "ops_owner"
|
|
1021
1021
|
}
|
|
1022
1022
|
}
|
|
1023
1023
|
}
|
|
1024
1024
|
});
|
|
1025
|
-
const router = createRouterStub("/
|
|
1025
|
+
const router = createRouterStub("/ops");
|
|
1026
1026
|
const runtime = createBootstrapPlacementRuntime({
|
|
1027
1027
|
app: createAppStub({
|
|
1028
1028
|
["runtime.web-placement.client"]: placementRuntime,
|
|
@@ -1037,7 +1037,7 @@ test("bootstrap placement runtime enforces surface access policies after bootstr
|
|
|
1037
1037
|
workspaces: [],
|
|
1038
1038
|
permissions: [],
|
|
1039
1039
|
surfaceAccess: {
|
|
1040
|
-
|
|
1040
|
+
opsowner: false
|
|
1041
1041
|
}
|
|
1042
1042
|
};
|
|
1043
1043
|
}
|
package/test/menuIcons.test.js
CHANGED
|
@@ -2,7 +2,6 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import {
|
|
4
4
|
mdiAccountCogOutline,
|
|
5
|
-
mdiConsoleNetworkOutline,
|
|
6
5
|
mdiCogOutline,
|
|
7
6
|
mdiFolderOutline,
|
|
8
7
|
mdiLogin,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
|
|
18
17
|
test("resolveSurfaceSwitchIcon prefers explicit icon and maps known surfaces", () => {
|
|
19
18
|
assert.equal(resolveSurfaceSwitchIcon("admin"), mdiShieldCrownOutline);
|
|
20
|
-
assert.equal(resolveSurfaceSwitchIcon("
|
|
19
|
+
assert.equal(resolveSurfaceSwitchIcon("ops", "mdi-cog-outline"), mdiCogOutline);
|
|
21
20
|
assert.equal(resolveSurfaceSwitchIcon("admin", "custom-icon"), "custom-icon");
|
|
22
21
|
assert.equal(resolveSurfaceSwitchIcon("admin", "mdi-cog-outline"), mdiCogOutline);
|
|
23
22
|
});
|
|
@@ -11,7 +11,7 @@ function createPlacementContext({
|
|
|
11
11
|
workspace = null,
|
|
12
12
|
workspaces = [],
|
|
13
13
|
authenticated = true,
|
|
14
|
-
|
|
14
|
+
opsOwner = false
|
|
15
15
|
} = {}) {
|
|
16
16
|
return {
|
|
17
17
|
auth: {
|
|
@@ -21,7 +21,7 @@ function createPlacementContext({
|
|
|
21
21
|
workspaces,
|
|
22
22
|
permissions: [],
|
|
23
23
|
surfaceAccess: {
|
|
24
|
-
|
|
24
|
+
opsowner: opsOwner
|
|
25
25
|
},
|
|
26
26
|
surfaceAccessPolicies: {
|
|
27
27
|
public: {},
|
|
@@ -29,15 +29,15 @@ function createPlacementContext({
|
|
|
29
29
|
requireAuth: true,
|
|
30
30
|
requireWorkspaceMembership: true
|
|
31
31
|
},
|
|
32
|
-
|
|
32
|
+
ops_owner: {
|
|
33
33
|
requireAuth: true,
|
|
34
|
-
requireFlagsAll: ["
|
|
34
|
+
requireFlagsAll: ["ops_owner"]
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
surfaceConfig: {
|
|
38
38
|
tenancyMode: "workspaces",
|
|
39
39
|
defaultSurfaceId: "app",
|
|
40
|
-
enabledSurfaceIds: ["home", "app", "admin", "
|
|
40
|
+
enabledSurfaceIds: ["home", "app", "admin", "ops"],
|
|
41
41
|
surfacesById: {
|
|
42
42
|
home: {
|
|
43
43
|
id: "home",
|
|
@@ -66,14 +66,15 @@ function createPlacementContext({
|
|
|
66
66
|
requiresWorkspace: true,
|
|
67
67
|
accessPolicyId: "workspace_member"
|
|
68
68
|
},
|
|
69
|
-
|
|
70
|
-
id: "
|
|
69
|
+
ops: {
|
|
70
|
+
id: "ops",
|
|
71
71
|
enabled: true,
|
|
72
|
-
pagesRoot: "
|
|
73
|
-
routeBase: "/
|
|
72
|
+
pagesRoot: "ops",
|
|
73
|
+
routeBase: "/ops",
|
|
74
74
|
requiresAuth: true,
|
|
75
75
|
requiresWorkspace: false,
|
|
76
|
-
accessPolicyId: "
|
|
76
|
+
accessPolicyId: "ops_owner",
|
|
77
|
+
icon: "mdi-cog-outline"
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -165,7 +166,7 @@ test("resolvePrimarySurfaceSwitchLink hides workspace switch when slug is only i
|
|
|
165
166
|
assert.equal(link, null);
|
|
166
167
|
});
|
|
167
168
|
|
|
168
|
-
test("resolveProfileSurfaceMenuLinks includes
|
|
169
|
+
test("resolveProfileSurfaceMenuLinks includes gated non-workspace switches only for matching access flags", () => {
|
|
169
170
|
const nonOwnerContext = createPlacementContext({
|
|
170
171
|
workspace: {
|
|
171
172
|
id: 1,
|
|
@@ -177,7 +178,7 @@ test("resolveProfileSurfaceMenuLinks includes console switch only for console ow
|
|
|
177
178
|
slug: "acme"
|
|
178
179
|
}
|
|
179
180
|
],
|
|
180
|
-
|
|
181
|
+
opsOwner: false
|
|
181
182
|
});
|
|
182
183
|
const ownerContext = createPlacementContext({
|
|
183
184
|
workspace: {
|
|
@@ -190,7 +191,7 @@ test("resolveProfileSurfaceMenuLinks includes console switch only for console ow
|
|
|
190
191
|
slug: "acme"
|
|
191
192
|
}
|
|
192
193
|
],
|
|
193
|
-
|
|
194
|
+
opsOwner: true
|
|
194
195
|
});
|
|
195
196
|
|
|
196
197
|
const nonOwnerLinks = resolveProfileSurfaceMenuLinks({
|
|
@@ -202,6 +203,6 @@ test("resolveProfileSurfaceMenuLinks includes console switch only for console ow
|
|
|
202
203
|
surface: "app"
|
|
203
204
|
});
|
|
204
205
|
|
|
205
|
-
assert.equal(nonOwnerLinks.some((entry) => entry.id === "surface-switch.
|
|
206
|
-
assert.equal(ownerLinks.some((entry) => entry.id === "surface-switch.
|
|
206
|
+
assert.equal(nonOwnerLinks.some((entry) => entry.id === "surface-switch.ops"), false);
|
|
207
|
+
assert.equal(ownerLinks.some((entry) => entry.id === "surface-switch.ops"), true);
|
|
207
208
|
});
|
|
@@ -71,44 +71,6 @@ function expectTextMutation(id, { reason = "", category = "", skipIfContains = "
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
test("users-web console settings template exposes surface-derived settings outlets", async () => {
|
|
75
|
-
const source = await readFile(path.join(PACKAGE_DIR, "templates", "src", "pages", "console", "settings.vue"), "utf8");
|
|
76
|
-
|
|
77
|
-
assert.match(source, /target="console-settings:primary-menu"/);
|
|
78
|
-
assert.match(source, /default-link-component-token="local\.main\.ui\.surface-aware-menu-link-item"/);
|
|
79
|
-
assert.match(source, /<RouterView \/>/);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("users-web console settings index template is a simple developer-owned stub", async () => {
|
|
83
|
-
const source = await readFile(path.join(PACKAGE_DIR, "templates", "src", "pages", "console", "settings", "index.vue"), "utf8");
|
|
84
|
-
|
|
85
|
-
assert.match(source, /definePage/);
|
|
86
|
-
assert.match(source, /your_child_segment/);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test("users-web descriptor metadata advertises console settings outlets with standard positions", () => {
|
|
90
|
-
const outlets = readOutlets("console-settings:primary-menu");
|
|
91
|
-
assert.deepEqual(
|
|
92
|
-
outlets,
|
|
93
|
-
[
|
|
94
|
-
{
|
|
95
|
-
target: "console-settings:primary-menu",
|
|
96
|
-
defaultLinkComponentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
97
|
-
surfaces: ["console"],
|
|
98
|
-
source: "templates/src/pages/console/settings.vue"
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
);
|
|
102
|
-
assert.deepEqual(findFileMutation("users-web-page-console-settings"), {
|
|
103
|
-
from: "templates/src/pages/console/settings/index.vue",
|
|
104
|
-
toSurface: "console",
|
|
105
|
-
toSurfacePath: "settings/index.vue",
|
|
106
|
-
reason: "Install console settings index stub scaffold for app-owned landing or redirect behavior.",
|
|
107
|
-
category: "users-web",
|
|
108
|
-
id: "users-web-page-console-settings"
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
74
|
test("users-web home tools widget exposes home-tools outlet", async () => {
|
|
113
75
|
const source = await readFile(path.join(PACKAGE_DIR, "src", "client", "components", "UsersHomeToolsWidget.vue"), "utf8");
|
|
114
76
|
|
|
@@ -140,15 +102,6 @@ test("users-web descriptor metadata advertises home tools outlet and standard ho
|
|
|
140
102
|
]
|
|
141
103
|
);
|
|
142
104
|
|
|
143
|
-
expectContribution("users.home.menu.home", {
|
|
144
|
-
target: "shell-layout:primary-menu",
|
|
145
|
-
surfaces: ["*"],
|
|
146
|
-
order: 50,
|
|
147
|
-
componentToken: "local.main.ui.surface-aware-menu-link-item",
|
|
148
|
-
when: "auth.authenticated === true",
|
|
149
|
-
source: "mutations.text#users-web-home-shell-menu-placement"
|
|
150
|
-
});
|
|
151
|
-
|
|
152
105
|
expectContribution("users.profile.menu.settings", {
|
|
153
106
|
target: "auth-profile-menu:primary-menu",
|
|
154
107
|
surfaces: ["*"],
|
|
@@ -205,20 +158,4 @@ test("users-web descriptor metadata advertises home tools outlet and standard ho
|
|
|
205
158
|
]
|
|
206
159
|
});
|
|
207
160
|
|
|
208
|
-
expectTextMutation("users-web-home-shell-menu-placement", {
|
|
209
|
-
reason: "Append users-web home shell menu placement into app-owned placement registry.",
|
|
210
|
-
category: "users-web",
|
|
211
|
-
skipIfContains: 'id: "users.home.menu.home"',
|
|
212
|
-
snippets: [
|
|
213
|
-
'id: "users.home.menu.home"',
|
|
214
|
-
'target: "shell-layout:primary-menu"',
|
|
215
|
-
'componentToken: "local.main.ui.surface-aware-menu-link-item"',
|
|
216
|
-
'label: "Home"',
|
|
217
|
-
'surface: "home"',
|
|
218
|
-
'workspaceSuffix: "/"',
|
|
219
|
-
'nonWorkspaceSuffix: "/"',
|
|
220
|
-
'exact: true'
|
|
221
|
-
]
|
|
222
|
-
});
|
|
223
|
-
|
|
224
161
|
});
|
|
@@ -15,7 +15,7 @@ function createContext(overrides = {}) {
|
|
|
15
15
|
],
|
|
16
16
|
permissions: [],
|
|
17
17
|
surfaceAccess: {
|
|
18
|
-
|
|
18
|
+
opsowner: false
|
|
19
19
|
},
|
|
20
20
|
surfaceAccessPolicies: {
|
|
21
21
|
public: {},
|
|
@@ -23,14 +23,14 @@ function createContext(overrides = {}) {
|
|
|
23
23
|
requireAuth: true,
|
|
24
24
|
requireWorkspaceMembership: true
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
ops_owner: {
|
|
27
27
|
requireAuth: true,
|
|
28
|
-
requireFlagsAll: ["
|
|
28
|
+
requireFlagsAll: ["ops_owner"]
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
surfaceConfig: {
|
|
32
32
|
defaultSurfaceId: "home",
|
|
33
|
-
enabledSurfaceIds: ["home", "app", "
|
|
33
|
+
enabledSurfaceIds: ["home", "app", "ops"],
|
|
34
34
|
surfacesById: {
|
|
35
35
|
home: {
|
|
36
36
|
id: "home",
|
|
@@ -46,12 +46,12 @@ function createContext(overrides = {}) {
|
|
|
46
46
|
requiresWorkspace: true,
|
|
47
47
|
accessPolicyId: "workspace_member"
|
|
48
48
|
},
|
|
49
|
-
|
|
50
|
-
id: "
|
|
49
|
+
ops: {
|
|
50
|
+
id: "ops",
|
|
51
51
|
enabled: true,
|
|
52
|
-
routeBase: "/
|
|
52
|
+
routeBase: "/ops",
|
|
53
53
|
requiresWorkspace: false,
|
|
54
|
-
accessPolicyId: "
|
|
54
|
+
accessPolicyId: "ops_owner"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
},
|
|
@@ -98,17 +98,17 @@ test("evaluateSurfaceAccess allows unknown workspace membership when allowOnUnkn
|
|
|
98
98
|
test("evaluateSurfaceAccess enforces bootstrap surface access flags", () => {
|
|
99
99
|
const deniedDecision = evaluateSurfaceAccess({
|
|
100
100
|
context: createContext(),
|
|
101
|
-
surfaceId: "
|
|
101
|
+
surfaceId: "ops"
|
|
102
102
|
});
|
|
103
103
|
assert.equal(deniedDecision.allowed, false);
|
|
104
104
|
|
|
105
105
|
const allowedDecision = evaluateSurfaceAccess({
|
|
106
106
|
context: createContext({
|
|
107
107
|
surfaceAccess: {
|
|
108
|
-
|
|
108
|
+
opsowner: true
|
|
109
109
|
}
|
|
110
110
|
}),
|
|
111
|
-
surfaceId: "
|
|
111
|
+
surfaceId: "ops"
|
|
112
112
|
});
|
|
113
113
|
assert.equal(allowedDecision.allowed, true);
|
|
114
114
|
});
|
|
@@ -48,11 +48,11 @@ test("resolveWorkspaceShellLinkPath returns empty path for unknown non-default w
|
|
|
48
48
|
assert.equal(path, "");
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
test("resolveWorkspaceShellLinkPath returns empty path for unknown
|
|
51
|
+
test("resolveWorkspaceShellLinkPath returns empty path for unknown non-workspace surface ids", () => {
|
|
52
52
|
const context = createContext();
|
|
53
53
|
const path = resolveWorkspaceShellLinkPath({
|
|
54
54
|
context,
|
|
55
|
-
surface: "
|
|
55
|
+
surface: "ops",
|
|
56
56
|
mode: "workspace",
|
|
57
57
|
workspaceSlug: "acme"
|
|
58
58
|
});
|
|
@@ -10,12 +10,12 @@ test("resolveSurfaceWorkspacePathFromPlacementContext returns empty path without
|
|
|
10
10
|
const context = {
|
|
11
11
|
surfaceConfig: {
|
|
12
12
|
defaultSurfaceId: "home",
|
|
13
|
-
enabledSurfaceIds: ["home", "app", "admin", "
|
|
13
|
+
enabledSurfaceIds: ["home", "app", "admin", "ops"],
|
|
14
14
|
surfacesById: {
|
|
15
15
|
home: { id: "home", routeBase: "/home", requiresWorkspace: false },
|
|
16
16
|
app: { id: "app", routeBase: "/w/:workspaceSlug", requiresWorkspace: true },
|
|
17
17
|
admin: { id: "admin", routeBase: "/w/:workspaceSlug/admin", requiresWorkspace: true },
|
|
18
|
-
|
|
18
|
+
ops: { id: "ops", routeBase: "/ops", requiresWorkspace: false }
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-container fluid class="console-home pa-0">
|
|
3
|
-
<v-row class="ma-0" justify="center">
|
|
4
|
-
<v-col cols="12" sm="10" md="9" lg="7">
|
|
5
|
-
<v-sheet class="pa-6 pa-sm-8" rounded="lg" border>
|
|
6
|
-
<h1 class="text-h5 text-sm-h4 mb-3">Console settings</h1>
|
|
7
|
-
<p class="text-body-2 text-sm-body-1 mb-0">
|
|
8
|
-
No console settings sections are available yet. Install a module that adds a page and menu entry to
|
|
9
|
-
<code>console-settings:primary-menu</code>.
|
|
10
|
-
</p>
|
|
11
|
-
</v-sheet>
|
|
12
|
-
</v-col>
|
|
13
|
-
</v-row>
|
|
14
|
-
</v-container>
|
|
15
|
-
</template>
|
|
16
|
-
|
|
17
|
-
<style scoped>
|
|
18
|
-
.console-home {
|
|
19
|
-
min-height: min(100vh, 700px);
|
|
20
|
-
display: grid;
|
|
21
|
-
align-content: start;
|
|
22
|
-
padding-top: clamp(16px, 4vh, 48px);
|
|
23
|
-
}
|
|
24
|
-
</style>
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import ShellOutlet from "@jskit-ai/shell-web/client/components/ShellOutlet";
|
|
3
|
-
import { RouterView } from "vue-router";
|
|
4
|
-
</script>
|
|
5
|
-
|
|
6
|
-
<template>
|
|
7
|
-
<section class="settings-shell d-flex flex-column ga-4">
|
|
8
|
-
<v-card rounded="lg" elevation="1" border>
|
|
9
|
-
<v-card-item>
|
|
10
|
-
<v-card-title>Console settings</v-card-title>
|
|
11
|
-
<v-card-subtitle>Global configuration and reference data for the whole app.</v-card-subtitle>
|
|
12
|
-
</v-card-item>
|
|
13
|
-
<v-divider />
|
|
14
|
-
<v-card-text class="pt-4">
|
|
15
|
-
<v-row no-gutters>
|
|
16
|
-
<v-col cols="12" md="3" lg="2" class="pr-md-4 mb-4 mb-md-0">
|
|
17
|
-
<v-list nav density="comfortable" rounded="lg" border>
|
|
18
|
-
<ShellOutlet
|
|
19
|
-
target="console-settings:primary-menu"
|
|
20
|
-
default-link-component-token="local.main.ui.surface-aware-menu-link-item"
|
|
21
|
-
/>
|
|
22
|
-
</v-list>
|
|
23
|
-
</v-col>
|
|
24
|
-
|
|
25
|
-
<v-col cols="12" md="9" lg="10">
|
|
26
|
-
<RouterView />
|
|
27
|
-
</v-col>
|
|
28
|
-
</v-row>
|
|
29
|
-
</v-card-text>
|
|
30
|
-
</v-card>
|
|
31
|
-
</section>
|
|
32
|
-
</template>
|