@jskit-ai/users-web 0.1.72 → 0.1.73
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 +107 -19
- package/package.json +8 -8
- package/src/client/account-settings/sections.js +14 -10
- package/{templates/src/components/account/settings → src/client/components}/AccountSettingsClientElement.vue +14 -41
- package/src/client/composables/crud/crudJsonApiTransportSupport.js +137 -0
- package/src/client/composables/crud/crudLookupFieldLabelSupport.js +13 -1
- package/src/client/composables/crud/crudLookupFieldRuntime.js +6 -0
- package/src/client/composables/crud/crudSchemaFormHelpers.js +30 -0
- package/src/client/composables/records/useCrudAddEdit.js +11 -1
- package/src/client/composables/records/useCrudList.js +4 -0
- package/src/client/composables/records/useCrudView.js +7 -0
- package/src/client/composables/runtime/useListCore.js +8 -0
- package/src/client/composables/useCrudListFilterLookups.js +5 -0
- package/src/client/index.js +1 -0
- package/templates/src/components/account/settings/vibe-coding-todo.todo +20 -0
- package/templates/src/pages/account/index.vue +1 -1
- package/test/accountSettingsSections.test.js +16 -5
- package/test/crudJsonApiTransportSupport.test.js +166 -0
- package/test/crudLookupFieldRuntime.test.js +25 -0
- package/test/exportsContract.test.js +1 -0
- package/test/requestTransportOptions.test.js +35 -0
- package/test/settingsPlacementContract.test.js +153 -1
- package/test/useCrudAddEdit.test.js +50 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { computed, unref } from "vue";
|
|
2
2
|
import { useRoute } from "vue-router";
|
|
3
|
+
import { resolveCrudJsonApiTransport } from "../crud/crudJsonApiTransportSupport.js";
|
|
3
4
|
import { resolveLookupFieldDisplayValue } from "../crud/crudLookupFieldLabelSupport.js";
|
|
4
5
|
import { resolveCrudBoundValues } from "../crud/crudBindingSupport.js";
|
|
5
6
|
import { resolveCrudListParentDescriptor } from "../internal/crudListParentTitleSupport.js";
|
|
@@ -65,6 +66,9 @@ function useCrudList({
|
|
|
65
66
|
});
|
|
66
67
|
const records = useList({
|
|
67
68
|
...listOptions,
|
|
69
|
+
transport: resolveCrudJsonApiTransport(listOptions.transport, resource, {
|
|
70
|
+
mode: "list"
|
|
71
|
+
}),
|
|
68
72
|
recordIdParam,
|
|
69
73
|
requestQueryParams(context = {}) {
|
|
70
74
|
const baseRequestQueryParams = resolveRequestQueryParamsInput(requestQueryParams, context);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { computed } from "vue";
|
|
2
2
|
import { useRoute } from "vue-router";
|
|
3
|
+
import {
|
|
4
|
+
resolveCrudJsonApiTransport
|
|
5
|
+
} from "../crud/crudJsonApiTransportSupport.js";
|
|
3
6
|
import {
|
|
4
7
|
resolveLookupFieldDisplayValue,
|
|
5
8
|
resolveRecordTitle
|
|
@@ -9,6 +12,7 @@ import { asPlainObject } from "../support/scopeHelpers.js";
|
|
|
9
12
|
import { useView } from "./useView.js";
|
|
10
13
|
|
|
11
14
|
function useCrudView({
|
|
15
|
+
resource = null,
|
|
12
16
|
paramBinding = null,
|
|
13
17
|
route = null,
|
|
14
18
|
...viewOptions
|
|
@@ -25,6 +29,9 @@ function useCrudView({
|
|
|
25
29
|
});
|
|
26
30
|
const view = useView({
|
|
27
31
|
...viewOptions,
|
|
32
|
+
transport: resolveCrudJsonApiTransport(viewOptions.transport, resource, {
|
|
33
|
+
mode: "view"
|
|
34
|
+
}),
|
|
28
35
|
routeParams: boundRouteParams
|
|
29
36
|
});
|
|
30
37
|
view.resolveFieldDisplay = resolveLookupFieldDisplayValue;
|
|
@@ -4,6 +4,8 @@ import { asPlainObject } from "../support/scopeHelpers.js";
|
|
|
4
4
|
import { resolveEnabledRef, resolveTextRef } from "../support/refValueHelpers.js";
|
|
5
5
|
import { usePagedCollection } from "../usePagedCollection.js";
|
|
6
6
|
|
|
7
|
+
const DEFAULT_LIST_LIMIT = 20;
|
|
8
|
+
|
|
7
9
|
function buildListRequestOptions({
|
|
8
10
|
requestOptions = null,
|
|
9
11
|
transport = null,
|
|
@@ -18,6 +20,12 @@ function buildListRequestOptions({
|
|
|
18
20
|
resolvedOptions.query && typeof resolvedOptions.query === "object" && !Array.isArray(resolvedOptions.query)
|
|
19
21
|
? { ...resolvedOptions.query }
|
|
20
22
|
: {};
|
|
23
|
+
if (
|
|
24
|
+
!Object.hasOwn(sourceQuery, "limit") &&
|
|
25
|
+
!Object.hasOwn(sourceQuery, "page[limit]")
|
|
26
|
+
) {
|
|
27
|
+
sourceQuery.limit = DEFAULT_LIST_LIMIT;
|
|
28
|
+
}
|
|
21
29
|
if (pageParam !== null && pageParam !== undefined && pageParam !== "") {
|
|
22
30
|
sourceQuery.cursor = String(pageParam);
|
|
23
31
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
mergeSelectedLookupOptions,
|
|
16
16
|
resolveLookupOptionLabel
|
|
17
17
|
} from "./internal/crudListFilterLookupSupport.js";
|
|
18
|
+
import { inferCrudLookupJsonApiTransport } from "./crud/crudJsonApiTransportSupport.js";
|
|
18
19
|
|
|
19
20
|
function useCrudListFilterLookups(
|
|
20
21
|
definitions = {},
|
|
@@ -46,10 +47,14 @@ function useCrudListFilterLookups(
|
|
|
46
47
|
if (!filter.lookup?.apiSuffix) {
|
|
47
48
|
continue;
|
|
48
49
|
}
|
|
50
|
+
const transport = inferCrudLookupJsonApiTransport({
|
|
51
|
+
apiPath: filter.lookup.apiSuffix
|
|
52
|
+
});
|
|
49
53
|
|
|
50
54
|
const runtime = useList({
|
|
51
55
|
adapter: adapter || undefined,
|
|
52
56
|
apiSuffix: filter.lookup.apiSuffix,
|
|
57
|
+
...(transport ? { transport } : {}),
|
|
53
58
|
queryKeyFactory: (surfaceId = "", scopeParamValue = "") => [
|
|
54
59
|
...normalizedQueryKeyPrefix,
|
|
55
60
|
filter.key,
|
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 { default as AccountSettingsClientElement } from "./components/AccountSettingsClientElement.vue";
|
|
4
5
|
|
|
5
6
|
const clientProviders = Object.freeze([UsersWebClientProvider]);
|
|
6
7
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
This note was split.
|
|
2
|
+
|
|
3
|
+
Use these repo-level docs instead:
|
|
4
|
+
|
|
5
|
+
- `docs/jskit-product-lanes-rulebook.md`
|
|
6
|
+
- `docs/jskit-product-lanes-workboard.md`
|
|
7
|
+
|
|
8
|
+
Why:
|
|
9
|
+
|
|
10
|
+
- the previous file had become a giant mixed artifact
|
|
11
|
+
- the durable product direction now lives in the rulebook
|
|
12
|
+
- the prioritized execution plan now lives in the workboard
|
|
13
|
+
- this template-path file is intentionally reduced to a pointer so the catch-all handoff does not keep living inside a shipped template location
|
|
14
|
+
|
|
15
|
+
If a future agent needs to continue the work:
|
|
16
|
+
|
|
17
|
+
1. read `AGENTS.md`
|
|
18
|
+
2. read the JSKIT pattern/workflow files named in the rulebook
|
|
19
|
+
3. use the rulebook for architecture and product direction
|
|
20
|
+
4. use the workboard for prioritization and execution planning
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
</template>
|
|
14
14
|
|
|
15
15
|
<script setup>
|
|
16
|
-
import AccountSettingsClientElement from "
|
|
16
|
+
import AccountSettingsClientElement from "@jskit-ai/users-web/client/components/AccountSettingsClientElement";
|
|
17
17
|
</script>
|
|
@@ -16,12 +16,12 @@ test("resolveAccountSettingsSections normalizes, deduplicates, and sorts placeme
|
|
|
16
16
|
|
|
17
17
|
const resolved = resolveAccountSettingsSections([
|
|
18
18
|
{
|
|
19
|
-
id: "users.
|
|
19
|
+
id: "users.profile.duplicate",
|
|
20
20
|
order: 999,
|
|
21
21
|
component: SectionA,
|
|
22
22
|
props: {
|
|
23
|
-
value: "
|
|
24
|
-
title: "
|
|
23
|
+
value: "profile",
|
|
24
|
+
title: "Profile duplicate"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
{
|
|
@@ -37,10 +37,20 @@ test("resolveAccountSettingsSections normalizes, deduplicates, and sorts placeme
|
|
|
37
37
|
id: "invalid.missing-component",
|
|
38
38
|
order: 250,
|
|
39
39
|
props: {
|
|
40
|
-
value: "
|
|
40
|
+
value: "broken",
|
|
41
41
|
title: "Broken missing component"
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
+
{
|
|
45
|
+
id: "users.profile",
|
|
46
|
+
order: 100,
|
|
47
|
+
component: SectionB,
|
|
48
|
+
props: {
|
|
49
|
+
value: "profile",
|
|
50
|
+
title: "Profile",
|
|
51
|
+
usesSharedRuntime: true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
44
54
|
{
|
|
45
55
|
id: "security.section",
|
|
46
56
|
order: 350,
|
|
@@ -70,8 +80,9 @@ test("resolveAccountSettingsSections normalizes, deduplicates, and sorts placeme
|
|
|
70
80
|
usesSharedRuntime: entry.usesSharedRuntime
|
|
71
81
|
})),
|
|
72
82
|
[
|
|
83
|
+
{ value: "invites", title: "Second duplicate", order: 100, usesSharedRuntime: false },
|
|
84
|
+
{ value: "profile", title: "Profile", order: 100, usesSharedRuntime: true },
|
|
73
85
|
{ value: "security", title: "Security", order: 350, usesSharedRuntime: true },
|
|
74
|
-
{ value: "invites", title: "Invites", order: 400, usesSharedRuntime: false }
|
|
75
86
|
]
|
|
76
87
|
);
|
|
77
88
|
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createSchema } from "json-rest-schema";
|
|
4
|
+
import {
|
|
5
|
+
inferCrudJsonApiTransport,
|
|
6
|
+
inferCrudLookupJsonApiTransport,
|
|
7
|
+
resolveCrudJsonApiTransport,
|
|
8
|
+
resolveLookupFieldMap
|
|
9
|
+
} from "../src/client/composables/crud/crudJsonApiTransportSupport.js";
|
|
10
|
+
|
|
11
|
+
const resource = {
|
|
12
|
+
namespace: "pets",
|
|
13
|
+
contract: {
|
|
14
|
+
lookup: {
|
|
15
|
+
containerKey: "lookups"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
operations: {
|
|
19
|
+
view: {
|
|
20
|
+
output: {
|
|
21
|
+
schema: createSchema({
|
|
22
|
+
id: {
|
|
23
|
+
type: "string",
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
contactId: {
|
|
27
|
+
type: "string",
|
|
28
|
+
required: true,
|
|
29
|
+
belongsTo: "contacts",
|
|
30
|
+
as: "contact"
|
|
31
|
+
},
|
|
32
|
+
breedId: {
|
|
33
|
+
type: "string",
|
|
34
|
+
nullable: true,
|
|
35
|
+
belongsTo: "breeds",
|
|
36
|
+
as: "breed"
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
test("inferCrudJsonApiTransport infers collection transport for CRUD lists", () => {
|
|
45
|
+
assert.deepEqual(
|
|
46
|
+
inferCrudJsonApiTransport(resource, {
|
|
47
|
+
mode: "list"
|
|
48
|
+
}),
|
|
49
|
+
{
|
|
50
|
+
kind: "jsonapi-resource",
|
|
51
|
+
responseType: "pets",
|
|
52
|
+
responseKind: "collection"
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("inferCrudJsonApiTransport infers record request/response transport for CRUD add/edit", () => {
|
|
58
|
+
assert.deepEqual(
|
|
59
|
+
inferCrudJsonApiTransport(resource, {
|
|
60
|
+
mode: "add-edit",
|
|
61
|
+
operationName: "patch"
|
|
62
|
+
}),
|
|
63
|
+
{
|
|
64
|
+
kind: "jsonapi-resource",
|
|
65
|
+
requestType: "pets",
|
|
66
|
+
responseType: "pets",
|
|
67
|
+
responseKind: "record"
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("inferCrudLookupJsonApiTransport infers collection transport from lookup namespace", () => {
|
|
73
|
+
assert.deepEqual(
|
|
74
|
+
inferCrudLookupJsonApiTransport({
|
|
75
|
+
namespace: "services"
|
|
76
|
+
}),
|
|
77
|
+
{
|
|
78
|
+
kind: "jsonapi-resource",
|
|
79
|
+
responseType: "services",
|
|
80
|
+
responseKind: "collection"
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("inferCrudLookupJsonApiTransport infers collection transport from lookup apiPath", () => {
|
|
86
|
+
assert.deepEqual(
|
|
87
|
+
inferCrudLookupJsonApiTransport({
|
|
88
|
+
apiPath: "/contact-roles"
|
|
89
|
+
}),
|
|
90
|
+
{
|
|
91
|
+
kind: "jsonapi-resource",
|
|
92
|
+
responseType: "contact-roles",
|
|
93
|
+
responseKind: "collection"
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("inferCrudLookupJsonApiTransport returns null without a lookup namespace", () => {
|
|
99
|
+
assert.equal(
|
|
100
|
+
inferCrudLookupJsonApiTransport({}),
|
|
101
|
+
null
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("resolveLookupFieldMap derives lookup aliases from the shared CRUD resource", () => {
|
|
106
|
+
assert.deepEqual(resolveLookupFieldMap(resource), {
|
|
107
|
+
breed: "breedId",
|
|
108
|
+
contact: "contactId"
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("resolveCrudJsonApiTransport infers and enriches JSON:API transport from the resource", () => {
|
|
113
|
+
assert.deepEqual(
|
|
114
|
+
resolveCrudJsonApiTransport(undefined, resource, {
|
|
115
|
+
mode: "list"
|
|
116
|
+
}),
|
|
117
|
+
{
|
|
118
|
+
kind: "jsonapi-resource",
|
|
119
|
+
responseType: "pets",
|
|
120
|
+
responseKind: "collection",
|
|
121
|
+
lookupContainerKey: "lookups",
|
|
122
|
+
lookupFieldMap: {
|
|
123
|
+
breed: "breedId",
|
|
124
|
+
contact: "contactId"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("resolveCrudJsonApiTransport infers record request/response transport for CRUD add/edit", () => {
|
|
131
|
+
assert.deepEqual(
|
|
132
|
+
resolveCrudJsonApiTransport(undefined, resource, {
|
|
133
|
+
mode: "add-edit",
|
|
134
|
+
operationName: "patch"
|
|
135
|
+
}),
|
|
136
|
+
{
|
|
137
|
+
kind: "jsonapi-resource",
|
|
138
|
+
requestType: "pets",
|
|
139
|
+
responseType: "pets",
|
|
140
|
+
responseKind: "record",
|
|
141
|
+
lookupContainerKey: "lookups",
|
|
142
|
+
lookupFieldMap: {
|
|
143
|
+
breed: "breedId",
|
|
144
|
+
contact: "contactId"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("resolveCrudJsonApiTransport rejects explicit CRUD transport overrides", () => {
|
|
151
|
+
assert.throws(
|
|
152
|
+
() =>
|
|
153
|
+
resolveCrudJsonApiTransport(
|
|
154
|
+
{
|
|
155
|
+
kind: "jsonapi-resource",
|
|
156
|
+
responseType: "pets",
|
|
157
|
+
responseKind: "record"
|
|
158
|
+
},
|
|
159
|
+
resource,
|
|
160
|
+
{
|
|
161
|
+
mode: "view"
|
|
162
|
+
}
|
|
163
|
+
),
|
|
164
|
+
/no longer accept explicit transport/
|
|
165
|
+
);
|
|
166
|
+
});
|
|
@@ -203,6 +203,31 @@ test("resolveLookupFieldDisplayValue supports custom lookup container key", () =
|
|
|
203
203
|
);
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
+
test("resolveLookupFieldDisplayValue falls back to alias-keyed lookups for relationship-backed fields", () => {
|
|
207
|
+
assert.equal(
|
|
208
|
+
resolveLookupFieldDisplayValue(
|
|
209
|
+
{
|
|
210
|
+
vetId: "17",
|
|
211
|
+
lookups: {
|
|
212
|
+
vet: {
|
|
213
|
+
id: "17",
|
|
214
|
+
name: "Harbor Vet"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
key: "vetId",
|
|
220
|
+
relation: {
|
|
221
|
+
kind: "lookup",
|
|
222
|
+
valueKey: "id",
|
|
223
|
+
labelKey: "name"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
),
|
|
227
|
+
"Harbor Vet"
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
206
231
|
test("resolveLookupFieldDisplayValue returns raw value for non-lookup fields", () => {
|
|
207
232
|
assert.equal(
|
|
208
233
|
resolveLookupFieldDisplayValue(
|
|
@@ -15,6 +15,7 @@ test("users-web exports are explicit and aligned with production/template usage"
|
|
|
15
15
|
packageId: "@jskit-ai/users-web",
|
|
16
16
|
requiredExports: [
|
|
17
17
|
"./client",
|
|
18
|
+
"./client/components/AccountSettingsClientElement",
|
|
18
19
|
"./client/account-settings/sections",
|
|
19
20
|
"./client/composables/useAddEdit",
|
|
20
21
|
"./client/composables/useCommand",
|
|
@@ -95,6 +95,7 @@ test("list request options stay GET and carry transport when provided", () => {
|
|
|
95
95
|
"x-demo": "1"
|
|
96
96
|
},
|
|
97
97
|
query: {
|
|
98
|
+
limit: 20,
|
|
98
99
|
cursor: "cursor_2"
|
|
99
100
|
},
|
|
100
101
|
transport: {
|
|
@@ -105,3 +106,37 @@ test("list request options stay GET and carry transport when provided", () => {
|
|
|
105
106
|
}
|
|
106
107
|
);
|
|
107
108
|
});
|
|
109
|
+
|
|
110
|
+
test("list request options preserve explicit limit values", () => {
|
|
111
|
+
assert.deepEqual(
|
|
112
|
+
buildListRequestOptions({
|
|
113
|
+
requestOptions: {
|
|
114
|
+
query: {
|
|
115
|
+
limit: 50
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}),
|
|
119
|
+
{
|
|
120
|
+
method: "GET",
|
|
121
|
+
query: {
|
|
122
|
+
limit: 50
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
assert.deepEqual(
|
|
128
|
+
buildListRequestOptions({
|
|
129
|
+
requestOptions: {
|
|
130
|
+
query: {
|
|
131
|
+
"page[limit]": "75"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}),
|
|
135
|
+
{
|
|
136
|
+
method: "GET",
|
|
137
|
+
query: {
|
|
138
|
+
"page[limit]": "75"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
});
|
|
@@ -80,6 +80,28 @@ test("users-web home tools widget exposes home-cog outlet", async () => {
|
|
|
80
80
|
assert.match(source, /:default-link-component-token="HOME_COG_OUTLET\.defaultLinkComponentToken"/);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
test("users-web account page template uses the package-owned account settings host", async () => {
|
|
84
|
+
const source = await readFile(path.join(PACKAGE_DIR, "templates", "src", "pages", "account", "index.vue"), "utf8");
|
|
85
|
+
|
|
86
|
+
assert.match(
|
|
87
|
+
source,
|
|
88
|
+
/import AccountSettingsClientElement from "@jskit-ai\/users-web\/client\/components\/AccountSettingsClientElement";/
|
|
89
|
+
);
|
|
90
|
+
assert.doesNotMatch(source, /components\/account\/settings\/AccountSettingsClientElement\.vue/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("users-web package-owned account settings host is fully placement-backed", async () => {
|
|
94
|
+
const source = await readFile(
|
|
95
|
+
path.join(PACKAGE_DIR, "src", "client", "components", "AccountSettingsClientElement.vue"),
|
|
96
|
+
"utf8"
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
assert.match(source, /useAccountSettingsSections/);
|
|
100
|
+
assert.doesNotMatch(source, /AccountSettingsProfileSection/);
|
|
101
|
+
assert.doesNotMatch(source, /AccountSettingsPreferencesSection/);
|
|
102
|
+
assert.doesNotMatch(source, /AccountSettingsNotificationsSection/);
|
|
103
|
+
});
|
|
104
|
+
|
|
83
105
|
test("users-web descriptor metadata advertises home cog outlet and standard home settings placements", () => {
|
|
84
106
|
assert.deepEqual(
|
|
85
107
|
readOutlets("home-cog:primary-menu"),
|
|
@@ -98,7 +120,7 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
|
|
|
98
120
|
{
|
|
99
121
|
target: "account-settings:sections",
|
|
100
122
|
surfaces: ["account"],
|
|
101
|
-
source: "
|
|
123
|
+
source: "src/client/components/AccountSettingsClientElement.vue"
|
|
102
124
|
}
|
|
103
125
|
]
|
|
104
126
|
);
|
|
@@ -130,6 +152,27 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
|
|
|
130
152
|
source: "mutations.text#users-web-home-tools-placement"
|
|
131
153
|
});
|
|
132
154
|
assert.equal(findContribution("users.home.settings.general"), null);
|
|
155
|
+
expectContribution("users.account.settings.profile", {
|
|
156
|
+
target: "account-settings:sections",
|
|
157
|
+
surfaces: ["account"],
|
|
158
|
+
order: 100,
|
|
159
|
+
componentToken: "local.main.account-settings.section.profile",
|
|
160
|
+
source: "mutations.text#users-web-account-settings-sections-placement"
|
|
161
|
+
});
|
|
162
|
+
expectContribution("users.account.settings.preferences", {
|
|
163
|
+
target: "account-settings:sections",
|
|
164
|
+
surfaces: ["account"],
|
|
165
|
+
order: 200,
|
|
166
|
+
componentToken: "local.main.account-settings.section.preferences",
|
|
167
|
+
source: "mutations.text#users-web-account-settings-sections-placement"
|
|
168
|
+
});
|
|
169
|
+
expectContribution("users.account.settings.notifications", {
|
|
170
|
+
target: "account-settings:sections",
|
|
171
|
+
surfaces: ["account"],
|
|
172
|
+
order: 300,
|
|
173
|
+
componentToken: "local.main.account-settings.section.notifications",
|
|
174
|
+
source: "mutations.text#users-web-account-settings-sections-placement"
|
|
175
|
+
});
|
|
133
176
|
|
|
134
177
|
expectTextMutation("users-web-home-tools-placement", {
|
|
135
178
|
reason: "Append users-web home tools widget and settings menu placements into app-owned placement registry.",
|
|
@@ -145,6 +188,22 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
|
|
|
145
188
|
'unscopedSuffix: "/settings"'
|
|
146
189
|
]
|
|
147
190
|
});
|
|
191
|
+
expectTextMutation("users-web-account-settings-sections-placement", {
|
|
192
|
+
reason: "Append users-web account settings section placements into the app-owned placement registry.",
|
|
193
|
+
category: "users-web",
|
|
194
|
+
skipIfContains: 'id: "users.account.settings.profile"',
|
|
195
|
+
snippets: [
|
|
196
|
+
'id: "users.account.settings.profile"',
|
|
197
|
+
'componentToken: "local.main.account-settings.section.profile"',
|
|
198
|
+
'value: "profile"',
|
|
199
|
+
'id: "users.account.settings.preferences"',
|
|
200
|
+
'componentToken: "local.main.account-settings.section.preferences"',
|
|
201
|
+
'value: "preferences"',
|
|
202
|
+
'id: "users.account.settings.notifications"',
|
|
203
|
+
'componentToken: "local.main.account-settings.section.notifications"',
|
|
204
|
+
'value: "notifications"'
|
|
205
|
+
]
|
|
206
|
+
});
|
|
148
207
|
|
|
149
208
|
expectTextMutation("users-web-profile-settings-placement", {
|
|
150
209
|
reason: "Append users-web profile settings menu placement into app-owned placement registry.",
|
|
@@ -159,6 +218,99 @@ test("users-web descriptor metadata advertises home cog outlet and standard home
|
|
|
159
218
|
]
|
|
160
219
|
});
|
|
161
220
|
|
|
221
|
+
assert.equal(findFileMutation("users-web-component-account-settings-root"), null);
|
|
162
222
|
assert.equal(findFileMutation("users-web-component-account-settings-invites"), null);
|
|
223
|
+
assert.deepEqual(findFileMutation("users-web-component-account-settings-profile"), {
|
|
224
|
+
from: "templates/src/components/account/settings/AccountSettingsProfileSection.vue",
|
|
225
|
+
to: "src/components/account/settings/AccountSettingsProfileSection.vue",
|
|
226
|
+
reason: "Install app-owned account settings profile section scaffold.",
|
|
227
|
+
category: "users-web",
|
|
228
|
+
id: "users-web-component-account-settings-profile"
|
|
229
|
+
});
|
|
230
|
+
assert.deepEqual(findFileMutation("users-web-component-account-settings-preferences"), {
|
|
231
|
+
from: "templates/src/components/account/settings/AccountSettingsPreferencesSection.vue",
|
|
232
|
+
to: "src/components/account/settings/AccountSettingsPreferencesSection.vue",
|
|
233
|
+
reason: "Install app-owned account settings preferences section scaffold.",
|
|
234
|
+
category: "users-web",
|
|
235
|
+
id: "users-web-component-account-settings-preferences"
|
|
236
|
+
});
|
|
237
|
+
assert.deepEqual(findFileMutation("users-web-component-account-settings-notifications"), {
|
|
238
|
+
from: "templates/src/components/account/settings/AccountSettingsNotificationsSection.vue",
|
|
239
|
+
to: "src/components/account/settings/AccountSettingsNotificationsSection.vue",
|
|
240
|
+
reason: "Install app-owned account settings notifications section scaffold.",
|
|
241
|
+
category: "users-web",
|
|
242
|
+
id: "users-web-component-account-settings-notifications"
|
|
243
|
+
});
|
|
244
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-profile-import"), {
|
|
245
|
+
op: "append-text",
|
|
246
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
247
|
+
position: "top",
|
|
248
|
+
skipIfContains:
|
|
249
|
+
"import AccountSettingsProfileSection from \"/src/components/account/settings/AccountSettingsProfileSection.vue\";",
|
|
250
|
+
value: "import AccountSettingsProfileSection from \"/src/components/account/settings/AccountSettingsProfileSection.vue\";\n",
|
|
251
|
+
reason: "Bind the app-owned account profile settings section into local main client provider imports.",
|
|
252
|
+
category: "users-web",
|
|
253
|
+
id: "users-web-main-client-provider-account-settings-profile-import"
|
|
254
|
+
});
|
|
255
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-preferences-import"), {
|
|
256
|
+
op: "append-text",
|
|
257
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
258
|
+
position: "top",
|
|
259
|
+
skipIfContains:
|
|
260
|
+
"import AccountSettingsPreferencesSection from \"/src/components/account/settings/AccountSettingsPreferencesSection.vue\";",
|
|
261
|
+
value:
|
|
262
|
+
"import AccountSettingsPreferencesSection from \"/src/components/account/settings/AccountSettingsPreferencesSection.vue\";\n",
|
|
263
|
+
reason: "Bind the app-owned account preferences settings section into local main client provider imports.",
|
|
264
|
+
category: "users-web",
|
|
265
|
+
id: "users-web-main-client-provider-account-settings-preferences-import"
|
|
266
|
+
});
|
|
267
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-notifications-import"), {
|
|
268
|
+
op: "append-text",
|
|
269
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
270
|
+
position: "top",
|
|
271
|
+
skipIfContains:
|
|
272
|
+
"import AccountSettingsNotificationsSection from \"/src/components/account/settings/AccountSettingsNotificationsSection.vue\";",
|
|
273
|
+
value:
|
|
274
|
+
"import AccountSettingsNotificationsSection from \"/src/components/account/settings/AccountSettingsNotificationsSection.vue\";\n",
|
|
275
|
+
reason: "Bind the app-owned account notifications settings section into local main client provider imports.",
|
|
276
|
+
category: "users-web",
|
|
277
|
+
id: "users-web-main-client-provider-account-settings-notifications-import"
|
|
278
|
+
});
|
|
279
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-profile-register"), {
|
|
280
|
+
op: "append-text",
|
|
281
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
282
|
+
position: "bottom",
|
|
283
|
+
skipIfContains:
|
|
284
|
+
"registerMainClientComponent(\"local.main.account-settings.section.profile\", () => AccountSettingsProfileSection);",
|
|
285
|
+
value:
|
|
286
|
+
"\nregisterMainClientComponent(\"local.main.account-settings.section.profile\", () => AccountSettingsProfileSection);\n",
|
|
287
|
+
reason: "Bind the app-owned account profile settings section token into local main client provider registry.",
|
|
288
|
+
category: "users-web",
|
|
289
|
+
id: "users-web-main-client-provider-account-settings-profile-register"
|
|
290
|
+
});
|
|
291
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-preferences-register"), {
|
|
292
|
+
op: "append-text",
|
|
293
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
294
|
+
position: "bottom",
|
|
295
|
+
skipIfContains:
|
|
296
|
+
"registerMainClientComponent(\"local.main.account-settings.section.preferences\", () => AccountSettingsPreferencesSection);",
|
|
297
|
+
value:
|
|
298
|
+
"\nregisterMainClientComponent(\"local.main.account-settings.section.preferences\", () => AccountSettingsPreferencesSection);\n",
|
|
299
|
+
reason: "Bind the app-owned account preferences settings section token into local main client provider registry.",
|
|
300
|
+
category: "users-web",
|
|
301
|
+
id: "users-web-main-client-provider-account-settings-preferences-register"
|
|
302
|
+
});
|
|
303
|
+
assert.deepEqual(findTextMutation("users-web-main-client-provider-account-settings-notifications-register"), {
|
|
304
|
+
op: "append-text",
|
|
305
|
+
file: "packages/main/src/client/providers/MainClientProvider.js",
|
|
306
|
+
position: "bottom",
|
|
307
|
+
skipIfContains:
|
|
308
|
+
"registerMainClientComponent(\"local.main.account-settings.section.notifications\", () => AccountSettingsNotificationsSection);",
|
|
309
|
+
value:
|
|
310
|
+
"\nregisterMainClientComponent(\"local.main.account-settings.section.notifications\", () => AccountSettingsNotificationsSection);\n",
|
|
311
|
+
reason: "Bind the app-owned account notifications settings section token into local main client provider registry.",
|
|
312
|
+
category: "users-web",
|
|
313
|
+
id: "users-web-main-client-provider-account-settings-notifications-register"
|
|
314
|
+
});
|
|
163
315
|
|
|
164
316
|
});
|