@jskit-ai/users-web 0.1.178-oldline.3 → 0.1.178
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.json +197 -45
- package/patterns/account-settings/PATTERN.md +61 -0
- package/src/client/bootstrap/user-bootstrap-handler.js +2 -12
- package/src/client/composables/account-settings/accountSettingsAvatarUploadRuntime.js +2 -2
- package/src/client/composables/useAccountSettingsRuntime.js +3 -3
- package/src/client/index.js +0 -16
- package/src/client/providers/UsersWebClientProvider.js +13 -14
- package/test/bootstrap.test.js +6 -41
- package/test/exportsContract.test.js +3 -29
- package/test/packageMetadataOwnership.test.js +19 -0
- package/test/settingsPlacementContract.test.js +93 -405
- package/fixtures/crud-list-date-filters/App.vue +0 -107
- package/fixtures/crud-list-date-filters/index.html +0 -12
- package/fixtures/crud-list-date-filters/main.js +0 -24
- package/fixtures/crud-list-date-filters/vite.config.mjs +0 -18
- package/package.descriptor.mjs +0 -468
- package/src/client/bulkActions.js +0 -47
- package/src/client/components/CrudAddEditScreen.vue +0 -186
- package/src/client/components/CrudListBulkActionSurface.vue +0 -126
- package/src/client/components/CrudListDateFilterControl.vue +0 -188
- package/src/client/components/CrudListFilterSurface.vue +0 -388
- package/src/client/components/CrudListRecordActionMenu.vue +0 -120
- package/src/client/components/CrudListScreen.vue +0 -501
- package/src/client/components/CrudViewScreen.vue +0 -197
- package/src/client/composables/crud/crudBindingSupport.js +0 -75
- package/src/client/composables/crud/crudHttpClientSupport.js +0 -57
- package/src/client/composables/crud/crudJsonApiTransportSupport.js +0 -145
- package/src/client/composables/crud/crudLookupFieldLabelSupport.js +0 -151
- package/src/client/composables/crud/crudLookupFieldRuntime.js +0 -251
- package/src/client/composables/crud/crudSchemaFormHelpers.js +0 -464
- package/src/client/composables/internal/crudListFilterLookupSupport.js +0 -161
- package/src/client/composables/internal/crudListParentTitleSupport.js +0 -171
- package/src/client/composables/internal/useOperationScope.js +0 -144
- package/src/client/composables/records/useAddEdit.js +0 -224
- package/src/client/composables/records/useCrudAddEdit.js +0 -227
- package/src/client/composables/records/useCrudList.js +0 -101
- package/src/client/composables/records/useCrudView.js +0 -47
- package/src/client/composables/records/useList.js +0 -500
- package/src/client/composables/records/useView.js +0 -164
- package/src/client/composables/runtime/addEditUiRuntime.js +0 -130
- package/src/client/composables/runtime/listUiRuntime.js +0 -123
- package/src/client/composables/runtime/modelStateHelpers.js +0 -90
- package/src/client/composables/runtime/operationAdapters.js +0 -34
- package/src/client/composables/runtime/operationUiHelpers.js +0 -125
- package/src/client/composables/runtime/operationValidationHelpers.js +0 -51
- package/src/client/composables/runtime/useAddEditCore.js +0 -112
- package/src/client/composables/runtime/useCommandCore.js +0 -123
- package/src/client/composables/runtime/useEndpointResource.js +0 -199
- package/src/client/composables/runtime/useFieldErrorBag.js +0 -61
- package/src/client/composables/runtime/useListCore.js +0 -112
- package/src/client/composables/runtime/useUiFeedback.js +0 -98
- package/src/client/composables/runtime/useViewCore.js +0 -93
- package/src/client/composables/runtime/viewUiRuntime.js +0 -96
- package/src/client/composables/support/errorMessageHelpers.js +0 -68
- package/src/client/composables/support/listQueryParamSupport.js +0 -473
- package/src/client/composables/support/listSearchSupport.js +0 -70
- package/src/client/composables/support/refValueHelpers.js +0 -19
- package/src/client/composables/support/requestQueryRuntimeSupport.js +0 -141
- package/src/client/composables/support/resourceLoadStateHelpers.js +0 -229
- package/src/client/composables/support/routeTemplateHelpers.js +0 -285
- package/src/client/composables/support/scopeHelpers.js +0 -145
- package/src/client/composables/useAccess.js +0 -109
- package/src/client/composables/useCommand.js +0 -118
- package/src/client/composables/useCrudAddEditScreen.js +0 -88
- package/src/client/composables/useCrudDeleteAction.js +0 -160
- package/src/client/composables/useCrudListBulkActions.js +0 -147
- package/src/client/composables/useCrudListFilterLookups.js +0 -146
- package/src/client/composables/useCrudListFilters.js +0 -339
- package/src/client/composables/useCrudListParentTitle.js +0 -151
- package/src/client/composables/useCrudListRowActions.js +0 -144
- package/src/client/composables/useCrudListScreen.js +0 -237
- package/src/client/composables/useCrudViewScreen.js +0 -77
- package/src/client/composables/usePagedCollection.js +0 -181
- package/src/client/composables/usePaths.js +0 -120
- package/src/client/composables/useRealtimeQueryInvalidation.js +0 -156
- package/src/client/composables/useScopeRuntime.js +0 -135
- package/src/client/composables/useSurfaceRouteContext.js +0 -25
- package/src/client/filters.js +0 -15
- package/src/client/lib/httpClient.js +0 -47
- package/src/client/lib/permissions.js +0 -34
- package/src/client/rowActions.js +0 -47
- package/src/client/support/contractGuards.js +0 -34
- package/src/client/support/crudListDateFilterSupport.js +0 -91
- package/test/addEditUiRuntime.test.js +0 -110
- package/test/crudBindingSupport.test.js +0 -110
- package/test/crudHttpClientSupport.test.js +0 -77
- package/test/crudJsonApiTransportSupport.test.js +0 -179
- package/test/crudListBulkActionSurface.test.js +0 -27
- package/test/crudListDateFilterSupport.test.js +0 -92
- package/test/crudListDateFilterSurface.browser.test.js +0 -273
- package/test/crudListFilterSurface.test.js +0 -90
- package/test/crudLookupFieldRuntime.test.js +0 -264
- package/test/crudScreenComponents.test.js +0 -108
- package/test/errorIntentContract.test.js +0 -31
- package/test/errorMessageHelpers.test.js +0 -39
- package/test/listQueryParamSupport.test.js +0 -223
- package/test/listUiRuntime.test.js +0 -102
- package/test/operationValidationHelpers.test.js +0 -64
- package/test/packageDescriptorOwnership.test.js +0 -18
- package/test/permissions.test.js +0 -35
- package/test/refValueHelpers.test.js +0 -14
- package/test/requestTransportOptions.test.js +0 -457
- package/test/resourceLoadStateHelpers.test.js +0 -189
- package/test/routeTemplateHelpers.test.js +0 -85
- package/test/scopeHelpers.test.js +0 -57
- package/test/useAddEditCore.test.js +0 -124
- package/test/useAddEditRequestQueryParams.test.js +0 -190
- package/test/useCrudAddEdit.test.js +0 -435
- package/test/useCrudDeleteAction.test.js +0 -139
- package/test/useCrudListBulkActions.test.js +0 -65
- package/test/useCrudListFilterLookups.test.js +0 -114
- package/test/useCrudListFilters.test.js +0 -293
- package/test/useCrudListParentTitle.test.js +0 -262
- package/test/useCrudListRowActions.test.js +0 -77
- package/test/useListRouteInitialization.test.js +0 -337
- package/test/useListSearchSupport.test.js +0 -61
- package/test/usePagedCollection.test.js +0 -53
- package/test/useViewRequestQueryParams.test.js +0 -20
- package/test/viewCoreLoading.test.js +0 -44
- package/test/viewUiRuntime.test.js +0 -95
- /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsNotificationsSection.vue +0 -0
- /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsPreferencesSection.vue +0 -0
- /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsProfileSection.vue +0 -0
- /package/{templates → patterns/account-settings/example}/src/pages/account/index.vue +0 -0
package/package.json
CHANGED
|
@@ -1,64 +1,216 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/users-web",
|
|
3
|
-
"version": "0.1.178
|
|
3
|
+
"version": "0.1.178",
|
|
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/UsersWebClientProvider": "./src/client/providers/UsersWebClientProvider.js",
|
|
10
11
|
"./client/components/AccountSettingsClientElement": "./src/client/components/AccountSettingsClientElement.vue",
|
|
11
|
-
"./client/
|
|
12
|
-
"./client/components/CrudListBulkActionSurface": "./src/client/components/CrudListBulkActionSurface.vue",
|
|
13
|
-
"./client/components/CrudListFilterSurface": "./src/client/components/CrudListFilterSurface.vue",
|
|
14
|
-
"./client/components/CrudListScreen": "./src/client/components/CrudListScreen.vue",
|
|
15
|
-
"./client/components/CrudViewScreen": "./src/client/components/CrudViewScreen.vue",
|
|
16
|
-
"./client/account-settings/sections": "./src/client/account-settings/sections.js",
|
|
17
|
-
"./client/bulkActions": "./src/client/bulkActions.js",
|
|
18
|
-
"./client/filters": "./src/client/filters.js",
|
|
19
|
-
"./client/rowActions": "./src/client/rowActions.js",
|
|
20
|
-
"./client/composables/useAddEdit": "./src/client/composables/records/useAddEdit.js",
|
|
21
|
-
"./client/composables/useAccess": "./src/client/composables/useAccess.js",
|
|
22
|
-
"./client/composables/useCommand": "./src/client/composables/useCommand.js",
|
|
23
|
-
"./client/composables/useCrudAddEdit": "./src/client/composables/records/useCrudAddEdit.js",
|
|
24
|
-
"./client/composables/useCrudAddEditScreen": "./src/client/composables/useCrudAddEditScreen.js",
|
|
25
|
-
"./client/composables/useCrudDeleteAction": "./src/client/composables/useCrudDeleteAction.js",
|
|
26
|
-
"./client/composables/useCrudListBulkActions": "./src/client/composables/useCrudListBulkActions.js",
|
|
27
|
-
"./client/composables/useCrudListRowActions": "./src/client/composables/useCrudListRowActions.js",
|
|
28
|
-
"./client/composables/crudLookupFieldRuntime": "./src/client/composables/crud/crudLookupFieldRuntime.js",
|
|
29
|
-
"./client/composables/useCrudListFilterLookups": "./src/client/composables/useCrudListFilterLookups.js",
|
|
30
|
-
"./client/composables/useCrudListFilters": "./src/client/composables/useCrudListFilters.js",
|
|
31
|
-
"./client/composables/useEndpointResource": "./src/client/composables/runtime/useEndpointResource.js",
|
|
32
|
-
"./client/composables/useList": "./src/client/composables/records/useList.js",
|
|
33
|
-
"./client/composables/useCrudList": "./src/client/composables/records/useCrudList.js",
|
|
34
|
-
"./client/composables/useCrudListScreen": "./src/client/composables/useCrudListScreen.js",
|
|
35
|
-
"./client/crudHttpClient": "./src/client/composables/crud/crudHttpClientSupport.js",
|
|
36
|
-
"./client/composables/useCrudListParentTitle": "./src/client/composables/useCrudListParentTitle.js",
|
|
37
|
-
"./client/composables/useRealtimeQueryInvalidation": "./src/client/composables/useRealtimeQueryInvalidation.js",
|
|
38
|
-
"./client/composables/useSurfaceRouteContext": "./src/client/composables/useSurfaceRouteContext.js",
|
|
39
|
-
"./client/composables/useView": "./src/client/composables/records/useView.js",
|
|
40
|
-
"./client/composables/useCrudView": "./src/client/composables/records/useCrudView.js",
|
|
41
|
-
"./client/composables/useCrudViewScreen": "./src/client/composables/useCrudViewScreen.js",
|
|
42
|
-
"./client/composables/usePagedCollection": "./src/client/composables/usePagedCollection.js",
|
|
43
|
-
"./client/composables/usePaths": "./src/client/composables/usePaths.js",
|
|
44
|
-
"./client/composables/runtime/useUiFeedback": "./src/client/composables/runtime/useUiFeedback.js",
|
|
45
|
-
"./client/lib/httpClient": "./src/client/lib/httpClient.js",
|
|
46
|
-
"./client/lib/permissions": "./src/client/lib/permissions.js",
|
|
47
|
-
"./client/support/contractGuards": "./src/client/support/contractGuards.js"
|
|
12
|
+
"./client/account-settings/sections": "./src/client/account-settings/sections.js"
|
|
48
13
|
},
|
|
49
14
|
"dependencies": {
|
|
50
|
-
"@
|
|
51
|
-
"@jskit-ai/http-
|
|
52
|
-
"@jskit-ai/
|
|
53
|
-
"@jskit-ai/
|
|
54
|
-
"@jskit-ai/shell-web": "0.1.
|
|
55
|
-
"@jskit-ai/uploads-image-web": "0.1.
|
|
56
|
-
"@jskit-ai/users-core": "0.1.
|
|
15
|
+
"@jskit-ai/auth-web": "0.1.160",
|
|
16
|
+
"@jskit-ai/http-web": "0.1.5",
|
|
17
|
+
"@jskit-ai/http-runtime": "0.1.158",
|
|
18
|
+
"@jskit-ai/kernel": "0.1.160",
|
|
19
|
+
"@jskit-ai/shell-web": "0.1.164",
|
|
20
|
+
"@jskit-ai/uploads-image-web": "0.1.135",
|
|
21
|
+
"@jskit-ai/users-core": "0.1.173"
|
|
57
22
|
},
|
|
58
23
|
"peerDependencies": {
|
|
59
24
|
"@tanstack/vue-query": "^5.90.5",
|
|
60
25
|
"vue": "^3.5.13",
|
|
61
26
|
"vue-router": "^5.0.4",
|
|
62
27
|
"vuetify": "^4.0.0"
|
|
28
|
+
},
|
|
29
|
+
"description": "Users web module with account, profile, and user-specific shell UI.",
|
|
30
|
+
"jskit": {
|
|
31
|
+
"kind": "runtime",
|
|
32
|
+
"capabilities": {
|
|
33
|
+
"provides": [
|
|
34
|
+
"users.web"
|
|
35
|
+
],
|
|
36
|
+
"requires": []
|
|
37
|
+
},
|
|
38
|
+
"runtime": {
|
|
39
|
+
"server": {
|
|
40
|
+
"providers": []
|
|
41
|
+
},
|
|
42
|
+
"client": {
|
|
43
|
+
"providers": [
|
|
44
|
+
{
|
|
45
|
+
"entrypoint": "src/client/providers/UsersWebClientProvider.js",
|
|
46
|
+
"export": "UsersWebClientProvider"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"metadata": {
|
|
52
|
+
"apiSummary": {
|
|
53
|
+
"surfaces": [
|
|
54
|
+
{
|
|
55
|
+
"subpath": "./client",
|
|
56
|
+
"summary": "Exports users-web client provider registration surface."
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"subpath": "./client/providers/UsersWebClientProvider",
|
|
60
|
+
"summary": "Exports users-web client provider class."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"subpath": "./client/components/AccountSettingsClientElement",
|
|
64
|
+
"summary": "Exports the package-owned account settings host that renders placement-backed account sections."
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"subpath": "./client/account-settings/sections",
|
|
68
|
+
"summary": "Exports placement-backed account settings section helpers."
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
"ui": {
|
|
73
|
+
"placements": {
|
|
74
|
+
"outlets": [
|
|
75
|
+
{
|
|
76
|
+
"target": "home-cog:primary-menu",
|
|
77
|
+
"surfaces": [
|
|
78
|
+
"home"
|
|
79
|
+
],
|
|
80
|
+
"source": "src/client/components/UsersHomeToolsWidget.vue"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"target": "account-settings:sections",
|
|
84
|
+
"surfaces": [
|
|
85
|
+
"account"
|
|
86
|
+
],
|
|
87
|
+
"source": "src/client/components/AccountSettingsClientElement.vue"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"topology": {
|
|
91
|
+
"placements": [
|
|
92
|
+
{
|
|
93
|
+
"id": "home.tools-menu",
|
|
94
|
+
"description": "Home surface tools menu actions.",
|
|
95
|
+
"surfaces": [
|
|
96
|
+
"home"
|
|
97
|
+
],
|
|
98
|
+
"variants": {
|
|
99
|
+
"compact": {
|
|
100
|
+
"outlet": "home-cog:primary-menu",
|
|
101
|
+
"renderers": {
|
|
102
|
+
"link": "local.main.ui.surface-aware-menu-link-item"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"medium": {
|
|
106
|
+
"outlet": "home-cog:primary-menu",
|
|
107
|
+
"renderers": {
|
|
108
|
+
"link": "local.main.ui.surface-aware-menu-link-item"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"expanded": {
|
|
112
|
+
"outlet": "home-cog:primary-menu",
|
|
113
|
+
"renderers": {
|
|
114
|
+
"link": "local.main.ui.surface-aware-menu-link-item"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "settings.sections",
|
|
121
|
+
"owner": "account-settings",
|
|
122
|
+
"description": "Account settings content sections.",
|
|
123
|
+
"surfaces": [
|
|
124
|
+
"account"
|
|
125
|
+
],
|
|
126
|
+
"variants": {
|
|
127
|
+
"compact": {
|
|
128
|
+
"outlet": "account-settings:sections"
|
|
129
|
+
},
|
|
130
|
+
"medium": {
|
|
131
|
+
"outlet": "account-settings:sections"
|
|
132
|
+
},
|
|
133
|
+
"expanded": {
|
|
134
|
+
"outlet": "account-settings:sections"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
"contributions": [
|
|
141
|
+
{
|
|
142
|
+
"id": "users.profile.menu.settings",
|
|
143
|
+
"target": "auth.profile-menu",
|
|
144
|
+
"kind": "link",
|
|
145
|
+
"surfaces": [
|
|
146
|
+
"*"
|
|
147
|
+
],
|
|
148
|
+
"order": 500,
|
|
149
|
+
"when": "auth.authenticated === true",
|
|
150
|
+
"source": "patterns/account-settings/PATTERN.md"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "users.home.tools.widget",
|
|
154
|
+
"target": "shell.status",
|
|
155
|
+
"kind": "component",
|
|
156
|
+
"surfaces": [
|
|
157
|
+
"home"
|
|
158
|
+
],
|
|
159
|
+
"order": 900,
|
|
160
|
+
"componentToken": "users.web.home.tools.widget",
|
|
161
|
+
"when": "auth.authenticated === true",
|
|
162
|
+
"source": "src/client/components/UsersHomeToolsWidget.vue"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": "users.home.menu.settings",
|
|
166
|
+
"target": "home.tools-menu",
|
|
167
|
+
"kind": "link",
|
|
168
|
+
"surfaces": [
|
|
169
|
+
"home"
|
|
170
|
+
],
|
|
171
|
+
"order": 100,
|
|
172
|
+
"when": "auth.authenticated === true",
|
|
173
|
+
"source": "patterns/account-settings/PATTERN.md"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"id": "users.account.settings.profile",
|
|
177
|
+
"target": "settings.sections",
|
|
178
|
+
"owner": "account-settings",
|
|
179
|
+
"kind": "component",
|
|
180
|
+
"surfaces": [
|
|
181
|
+
"account"
|
|
182
|
+
],
|
|
183
|
+
"order": 100,
|
|
184
|
+
"componentToken": "local.main.account-settings.section.profile",
|
|
185
|
+
"source": "patterns/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"id": "users.account.settings.preferences",
|
|
189
|
+
"target": "settings.sections",
|
|
190
|
+
"owner": "account-settings",
|
|
191
|
+
"kind": "component",
|
|
192
|
+
"surfaces": [
|
|
193
|
+
"account"
|
|
194
|
+
],
|
|
195
|
+
"order": 200,
|
|
196
|
+
"componentToken": "local.main.account-settings.section.preferences",
|
|
197
|
+
"source": "patterns/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"id": "users.account.settings.notifications",
|
|
201
|
+
"target": "settings.sections",
|
|
202
|
+
"owner": "account-settings",
|
|
203
|
+
"kind": "component",
|
|
204
|
+
"surfaces": [
|
|
205
|
+
"account"
|
|
206
|
+
],
|
|
207
|
+
"order": 300,
|
|
208
|
+
"componentToken": "local.main.account-settings.section.notifications",
|
|
209
|
+
"source": "patterns/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue"
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
63
215
|
}
|
|
64
216
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: users/account-settings
|
|
3
|
+
title: Account settings surface
|
|
4
|
+
summary: Compose an account settings route and profile, preference, and notification sections from JSKIT user web components.
|
|
5
|
+
keywords: account, notifications, preferences, profile, settings, user, vue
|
|
6
|
+
requires: @jskit-ai/users-core, @jskit-ai/users-web, @jskit-ai/shell-web
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Account settings surface
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when authenticated users need to manage their own profile and
|
|
14
|
+
account preferences.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
Do not use this pattern for administrator-managed users, authentication
|
|
19
|
+
credential storage, or anonymous profile editing.
|
|
20
|
+
|
|
21
|
+
## Product decisions
|
|
22
|
+
|
|
23
|
+
Choose editable profile fields, preference vocabulary, notification options,
|
|
24
|
+
section order, and which account operations require reauthentication.
|
|
25
|
+
|
|
26
|
+
## Framework APIs
|
|
27
|
+
|
|
28
|
+
Use account settings elements and composables from `@jskit-ai/users-web`,
|
|
29
|
+
ordinary `useCommand()` mutation behavior, and JSKIT shell placements.
|
|
30
|
+
|
|
31
|
+
## Invariants
|
|
32
|
+
|
|
33
|
+
- Sections use JSKIT account settings APIs rather than direct HTTP helpers.
|
|
34
|
+
- Cached resource data hydrates local writable fields immediately.
|
|
35
|
+
- Mutation errors use the standard toast and do not push the form down.
|
|
36
|
+
- Loading uses layout-stable skeletons, never an indeterminate spinner.
|
|
37
|
+
- Pending controls keep stable labels and prevent duplicate submission.
|
|
38
|
+
- The route and placement owner agree.
|
|
39
|
+
|
|
40
|
+
## Example files
|
|
41
|
+
|
|
42
|
+
`example/` contains an account route and three concrete settings sections.
|
|
43
|
+
Adapt their fields and copy while retaining the shared account runtime.
|
|
44
|
+
|
|
45
|
+
## Variation points
|
|
46
|
+
|
|
47
|
+
Change sections, fields, copy, order, permissions, preference choices, and
|
|
48
|
+
notification vocabulary while keeping server-owned validation authoritative.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
Navigate away and back with warm cache, exercise browser back/forward, save and
|
|
53
|
+
clear fields, verify toast errors, inspect skeleton geometry, and test keyboard
|
|
54
|
+
operation at compact and expanded widths.
|
|
55
|
+
|
|
56
|
+
## Avoid
|
|
57
|
+
|
|
58
|
+
- page-local request clients
|
|
59
|
+
- inline mutation alerts that shift content
|
|
60
|
+
- lazy non-immediate watchers for initial hydration
|
|
61
|
+
- copied user repositories or generator source markers
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
registerBootstrapPayloadHandler,
|
|
3
|
-
resolveBootstrapErrorStatusCode
|
|
4
|
-
} from "@jskit-ai/shell-web/client/bootstrap";
|
|
1
|
+
import { resolveBootstrapErrorStatusCode } from "@jskit-ai/shell-web/client/bootstrap";
|
|
5
2
|
import { resolvePlacementUserFromBootstrapPayload } from "../lib/bootstrap.js";
|
|
6
3
|
|
|
7
4
|
function createUsersBootstrapUserHandler() {
|
|
@@ -43,11 +40,4 @@ function createUsersBootstrapUserHandler() {
|
|
|
43
40
|
});
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
registerBootstrapPayloadHandler(app, "users.web.bootstrap.user-handler", () => createUsersBootstrapUserHandler());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export {
|
|
51
|
-
createUsersBootstrapUserHandler,
|
|
52
|
-
registerUsersBootstrapPayloadHandlers
|
|
53
|
-
};
|
|
43
|
+
export { createUsersBootstrapUserHandler };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "@jskit-ai/uploads-image-web/client/styles";
|
|
2
2
|
import { createManagedImageAssetRuntime } from "@jskit-ai/uploads-image-web/client/composables/createManagedImageAssetRuntime";
|
|
3
3
|
import { resolveFieldErrors } from "@jskit-ai/http-runtime/client";
|
|
4
|
-
import {
|
|
4
|
+
import { httpWebClient } from "@jskit-ai/http-web/client/lib/httpClient";
|
|
5
5
|
|
|
6
6
|
function createAccountSettingsAvatarUploadRuntime({
|
|
7
7
|
queryClient,
|
|
@@ -15,7 +15,7 @@ function createAccountSettingsAvatarUploadRuntime({
|
|
|
15
15
|
const sessionPayload = await queryClient.fetchQuery({
|
|
16
16
|
queryKey: sessionQueryKey,
|
|
17
17
|
queryFn: () =>
|
|
18
|
-
|
|
18
|
+
httpWebClient.request("/api/session", {
|
|
19
19
|
method: "GET"
|
|
20
20
|
}),
|
|
21
21
|
staleTime: 60_000
|
|
@@ -10,14 +10,14 @@ import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
|
|
|
10
10
|
import { ROUTE_VISIBILITY_PUBLIC } from "@jskit-ai/kernel/shared/support/visibility";
|
|
11
11
|
import { userProfileResource } from "@jskit-ai/users-core/shared/resources/userProfileResource";
|
|
12
12
|
import { userSettingsResource } from "@jskit-ai/users-core/shared/resources/userSettingsResource";
|
|
13
|
+
import { useAddEdit } from "@jskit-ai/http-web/client/composables/useAddEdit";
|
|
14
|
+
import { useCommand } from "@jskit-ai/http-web/client/composables/useCommand";
|
|
15
|
+
import { useView } from "@jskit-ai/http-web/client/composables/useView";
|
|
13
16
|
import {
|
|
14
17
|
persistThemePreference,
|
|
15
18
|
resolveThemeNameForPreference,
|
|
16
19
|
setVuetifyThemeName
|
|
17
20
|
} from "../lib/theme.js";
|
|
18
|
-
import { useAddEdit } from "./records/useAddEdit.js";
|
|
19
|
-
import { useCommand } from "./useCommand.js";
|
|
20
|
-
import { useView } from "./records/useView.js";
|
|
21
21
|
import { resolveSurfacePathFromPlacementContext } from "@jskit-ai/shell-web/client/placement";
|
|
22
22
|
import {
|
|
23
23
|
ACCOUNT_SETTINGS_DEFAULTS,
|
package/src/client/index.js
CHANGED
|
@@ -1,18 +1,2 @@
|
|
|
1
|
-
import { UsersWebClientProvider } from "./providers/UsersWebClientProvider.js";
|
|
2
|
-
|
|
3
1
|
export { UsersWebClientProvider } from "./providers/UsersWebClientProvider.js";
|
|
4
2
|
export { default as AccountSettingsClientElement } from "./components/AccountSettingsClientElement.vue";
|
|
5
|
-
export { default as CrudAddEditScreen } from "./components/CrudAddEditScreen.vue";
|
|
6
|
-
export { default as CrudListBulkActionSurface } from "./components/CrudListBulkActionSurface.vue";
|
|
7
|
-
export { default as CrudListFilterSurface } from "./components/CrudListFilterSurface.vue";
|
|
8
|
-
export { default as CrudListScreen } from "./components/CrudListScreen.vue";
|
|
9
|
-
export { default as CrudViewScreen } from "./components/CrudViewScreen.vue";
|
|
10
|
-
export {
|
|
11
|
-
normalizeCrudApiAccess,
|
|
12
|
-
resolveCrudHttpClient
|
|
13
|
-
} from "./composables/crud/crudHttpClientSupport.js";
|
|
14
|
-
export { useCrudDeleteAction } from "./composables/useCrudDeleteAction.js";
|
|
15
|
-
|
|
16
|
-
const clientProviders = Object.freeze([UsersWebClientProvider]);
|
|
17
|
-
|
|
18
|
-
export { clientProviders };
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
import { defineProvider } from "@jskit-ai/kernel/shared/capabilities";
|
|
1
2
|
import UsersHomeToolsWidget from "../components/UsersHomeToolsWidget.vue";
|
|
2
3
|
import ProfileClientElement from "../components/ProfileClientElement.vue";
|
|
3
|
-
import {
|
|
4
|
+
import { createUsersBootstrapUserHandler } from "../bootstrap/user-bootstrap-handler.js";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
app.singleton("users.web.profile.element", () => ProfileClientElement);
|
|
16
|
-
registerUsersBootstrapPayloadHandlers(app);
|
|
6
|
+
const UsersWebClientProvider = defineProvider({
|
|
7
|
+
id: "users.web.client",
|
|
8
|
+
requires: {
|
|
9
|
+
components: "client.components",
|
|
10
|
+
shell: "client.shell"
|
|
11
|
+
},
|
|
12
|
+
setup({ components, shell }) {
|
|
13
|
+
components.register("users.web.home.tools.widget", UsersHomeToolsWidget);
|
|
14
|
+
components.register("users.web.profile.element", ProfileClientElement);
|
|
15
|
+
shell.bootstrapHandlers.register(createUsersBootstrapUserHandler());
|
|
17
16
|
}
|
|
18
|
-
}
|
|
17
|
+
});
|
|
19
18
|
|
|
20
19
|
export { UsersWebClientProvider };
|
package/test/bootstrap.test.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
|
-
import {
|
|
3
|
+
import { createBootstrapPayloadHandlerRegistry } from "@jskit-ai/shell-web/client/bootstrap";
|
|
4
4
|
import { resolvePlacementUserFromBootstrapPayload } from "../src/client/lib/bootstrap.js";
|
|
5
|
-
import {
|
|
6
|
-
createUsersBootstrapUserHandler,
|
|
7
|
-
registerUsersBootstrapPayloadHandlers
|
|
8
|
-
} from "../src/client/bootstrap/user-bootstrap-handler.js";
|
|
5
|
+
import { createUsersBootstrapUserHandler } from "../src/client/bootstrap/user-bootstrap-handler.js";
|
|
9
6
|
|
|
10
7
|
test("resolvePlacementUserFromBootstrapPayload returns null for anonymous sessions", () => {
|
|
11
8
|
assert.equal(
|
|
@@ -62,38 +59,6 @@ function createPlacementRuntimeDouble() {
|
|
|
62
59
|
};
|
|
63
60
|
}
|
|
64
61
|
|
|
65
|
-
function createBootstrapRegistryAppDouble() {
|
|
66
|
-
const singletons = new Map();
|
|
67
|
-
const instances = new Map();
|
|
68
|
-
const tags = new Map();
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
singleton(token, factory) {
|
|
72
|
-
singletons.set(token, factory);
|
|
73
|
-
},
|
|
74
|
-
tag(token, tagName) {
|
|
75
|
-
const current = tags.get(tagName) || [];
|
|
76
|
-
current.push(token);
|
|
77
|
-
tags.set(tagName, current);
|
|
78
|
-
},
|
|
79
|
-
resolveTag(tagName) {
|
|
80
|
-
return (tags.get(tagName) || []).map((token) => this.make(token));
|
|
81
|
-
},
|
|
82
|
-
make(token) {
|
|
83
|
-
if (instances.has(token)) {
|
|
84
|
-
return instances.get(token);
|
|
85
|
-
}
|
|
86
|
-
const factory = singletons.get(token);
|
|
87
|
-
if (typeof factory !== "function") {
|
|
88
|
-
throw new Error(`Unknown token ${String(token)}`);
|
|
89
|
-
}
|
|
90
|
-
const instance = factory(this);
|
|
91
|
-
instances.set(token, instance);
|
|
92
|
-
return instance;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
62
|
test("users web bootstrap user handler writes placement user", async () => {
|
|
98
63
|
const handler = createUsersBootstrapUserHandler();
|
|
99
64
|
const placementRuntime = createPlacementRuntimeDouble();
|
|
@@ -156,11 +121,11 @@ test("users web bootstrap user handler clears placement user on bootstrap 401 on
|
|
|
156
121
|
assert.equal(placementRuntime.getContext().user, null);
|
|
157
122
|
});
|
|
158
123
|
|
|
159
|
-
test("
|
|
160
|
-
const
|
|
161
|
-
|
|
124
|
+
test("users bootstrap user handler registers with the explicit shell registry", () => {
|
|
125
|
+
const registry = createBootstrapPayloadHandlerRegistry();
|
|
126
|
+
registry.register(createUsersBootstrapUserHandler());
|
|
162
127
|
|
|
163
|
-
const handlers =
|
|
128
|
+
const handlers = registry.list();
|
|
164
129
|
assert.equal(handlers.length, 1);
|
|
165
130
|
assert.equal(handlers[0]?.handlerId, "users.web.bootstrap.user");
|
|
166
131
|
assert.equal(typeof handlers[0]?.applyBootstrapPayload, "function");
|
|
@@ -8,42 +8,16 @@ const TEST_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
|
|
|
8
8
|
const REPO_ROOT = path.resolve(TEST_DIRECTORY, "..", "..", "..");
|
|
9
9
|
const PACKAGE_DIR = path.join(REPO_ROOT, "packages", "users-web");
|
|
10
10
|
|
|
11
|
-
test("users-web exports
|
|
11
|
+
test("users-web exports only user-owned client surfaces", () => {
|
|
12
12
|
const result = evaluatePackageExportsContract({
|
|
13
13
|
repoRoot: REPO_ROOT,
|
|
14
14
|
packageDir: PACKAGE_DIR,
|
|
15
15
|
packageId: "@jskit-ai/users-web",
|
|
16
16
|
requiredExports: [
|
|
17
17
|
"./client",
|
|
18
|
+
"./client/providers/UsersWebClientProvider",
|
|
18
19
|
"./client/components/AccountSettingsClientElement",
|
|
19
|
-
"./client/
|
|
20
|
-
"./client/components/CrudListBulkActionSurface",
|
|
21
|
-
"./client/components/CrudListFilterSurface",
|
|
22
|
-
"./client/components/CrudListScreen",
|
|
23
|
-
"./client/components/CrudViewScreen",
|
|
24
|
-
"./client/account-settings/sections",
|
|
25
|
-
"./client/bulkActions",
|
|
26
|
-
"./client/filters",
|
|
27
|
-
"./client/rowActions",
|
|
28
|
-
"./client/composables/useAddEdit",
|
|
29
|
-
"./client/composables/useCommand",
|
|
30
|
-
"./client/composables/useEndpointResource",
|
|
31
|
-
"./client/composables/useList",
|
|
32
|
-
"./client/composables/usePaths",
|
|
33
|
-
"./client/composables/useView",
|
|
34
|
-
"./client/composables/useCrudAddEdit",
|
|
35
|
-
"./client/composables/useCrudAddEditScreen",
|
|
36
|
-
"./client/composables/useCrudDeleteAction",
|
|
37
|
-
"./client/composables/useCrudListBulkActions",
|
|
38
|
-
"./client/composables/useCrudListRowActions",
|
|
39
|
-
"./client/composables/useCrudListFilterLookups",
|
|
40
|
-
"./client/composables/useCrudListFilters",
|
|
41
|
-
"./client/composables/useCrudList",
|
|
42
|
-
"./client/composables/useCrudListScreen",
|
|
43
|
-
"./client/crudHttpClient",
|
|
44
|
-
"./client/composables/useCrudView",
|
|
45
|
-
"./client/composables/useCrudViewScreen",
|
|
46
|
-
"./client/lib/httpClient"
|
|
20
|
+
"./client/account-settings/sections"
|
|
47
21
|
]
|
|
48
22
|
});
|
|
49
23
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
7
|
+
|
|
8
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
|
|
10
|
+
test("users-web publishes account examples as agent-readable patterns", async () => {
|
|
11
|
+
assert.equal(packageJson.jskit?.mutations, undefined);
|
|
12
|
+
|
|
13
|
+
const pattern = await readFile(path.join(packageRoot, "patterns", "account-settings", "PATTERN.md"), "utf8");
|
|
14
|
+
assert.match(pattern, /## Product decisions/);
|
|
15
|
+
assert.match(pattern, /## Invariants/);
|
|
16
|
+
assert.match(pattern, /Mutation errors use the standard toast/);
|
|
17
|
+
assert.match(pattern, /Loading uses layout-stable skeletons/);
|
|
18
|
+
assert.match(pattern, /## Example files/);
|
|
19
|
+
});
|