@jskit-ai/agent-docs 0.1.26 → 0.1.28
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/DISTR_AGENT.md +1 -0
- package/guide/agent/app-extras/assistant.md +9 -20
- package/guide/agent/app-extras/mobile-capacitor.md +381 -0
- package/guide/agent/app-extras/realtime.md +13 -12
- package/guide/agent/app-setup/a-more-interesting-shell.md +102 -87
- package/guide/agent/app-setup/authentication.md +50 -31
- package/guide/agent/app-setup/console.md +8 -8
- package/guide/agent/app-setup/database-layer.md +15 -15
- package/guide/agent/app-setup/initial-scaffolding.md +37 -5
- package/guide/agent/app-setup/multi-homing.md +50 -47
- package/guide/agent/app-setup/quickstart.md +11 -14
- package/guide/agent/app-setup/users.md +24 -24
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +18 -10
- package/guide/agent/generators/advanced-cruds.md +111 -68
- package/guide/agent/generators/crud-generators.md +5 -5
- package/guide/agent/generators/ui-generators.md +44 -36
- package/guide/agent/index.md +3 -2
- package/package.json +1 -1
- package/patterns/INDEX.md +4 -1
- package/patterns/client-requests.md +23 -6
- package/patterns/crud-repository-mapping.md +1 -1
- package/patterns/crud-scaffolding.md +10 -1
- package/patterns/filters.md +28 -10
- package/patterns/generated-ui-contract-tracking.md +62 -0
- package/patterns/page-scaffolding.md +20 -2
- package/patterns/placements.md +67 -1
- package/patterns/surfaces.md +5 -1
- package/patterns/ui-testing.md +3 -0
- package/reference/autogen/KERNEL_MAP.md +46 -1
- package/reference/autogen/README.md +3 -0
- package/reference/autogen/packages/assistant.md +2 -1
- package/reference/autogen/packages/auth-web.md +20 -1
- package/reference/autogen/packages/crud-ui-generator.md +20 -8
- package/reference/autogen/packages/google-rewarded-core.md +222 -0
- package/reference/autogen/packages/google-rewarded-web.md +71 -0
- package/reference/autogen/packages/kernel.md +94 -10
- package/reference/autogen/packages/mobile-capacitor.md +76 -0
- package/reference/autogen/packages/realtime.md +1 -0
- package/reference/autogen/packages/shell-web.md +48 -3
- package/reference/autogen/packages/ui-generator.md +34 -2
- package/reference/autogen/packages/users-core.md +2 -0
- package/reference/autogen/packages/users-web.md +92 -4
- package/reference/autogen/packages/workspaces-web.md +3 -2
- package/reference/autogen/tooling/jskit-cli.md +114 -9
- package/templates/app/AGENTS.md +1 -0
- package/workflow/bootstrap.md +1 -0
|
@@ -249,6 +249,8 @@ packages/contacts/
|
|
|
249
249
|
|
|
250
250
|
src/pages/w/[workspaceSlug]/admin/contacts/
|
|
251
251
|
index.vue
|
|
252
|
+
listBulkActions.js
|
|
253
|
+
listFilters.js
|
|
252
254
|
new.vue
|
|
253
255
|
[contactId]/index.vue
|
|
254
256
|
[contactId]/edit.vue
|
|
@@ -439,6 +441,8 @@ src/pages/w/[workspaceSlug]/admin/contacts/
|
|
|
439
441
|
new.vue
|
|
440
442
|
[contactId]/index.vue
|
|
441
443
|
[contactId]/edit.vue
|
|
444
|
+
listBulkActions.js
|
|
445
|
+
listFilters.js
|
|
442
446
|
_components/CrudAddEditForm.vue
|
|
443
447
|
_components/CrudAddEditFormFields.js
|
|
444
448
|
```
|
|
@@ -449,13 +453,13 @@ This is the list-page container.
|
|
|
449
453
|
|
|
450
454
|
Its job is usually to:
|
|
451
455
|
|
|
452
|
-
- call `
|
|
453
|
-
-
|
|
454
|
-
- render
|
|
456
|
+
- call `useCrudListScreen()`
|
|
457
|
+
- pass page-local `listFilters` and `listBulkActions`
|
|
458
|
+
- render the shared `CrudListScreen`
|
|
455
459
|
- resolve list/view/edit/new URLs
|
|
456
460
|
- pass route query state through when navigating deeper
|
|
457
461
|
|
|
458
|
-
The actual list machinery lives
|
|
462
|
+
The actual list machinery lives in `users-web` shared screen composables and the shared resource contract.
|
|
459
463
|
|
|
460
464
|
### `[contactId]/index.vue`
|
|
461
465
|
|
|
@@ -463,8 +467,8 @@ This is the view-page container.
|
|
|
463
467
|
|
|
464
468
|
Its job is usually to:
|
|
465
469
|
|
|
466
|
-
- call `
|
|
467
|
-
- render the
|
|
470
|
+
- call `useCrudViewScreen()`
|
|
471
|
+
- render the shared `CrudViewScreen`
|
|
468
472
|
- resolve "back" and "edit" navigation
|
|
469
473
|
|
|
470
474
|
Again, the runtime behavior is mostly uphill. The page is a route-level composition layer.
|
|
@@ -475,9 +479,9 @@ These are add/edit route wrappers.
|
|
|
475
479
|
|
|
476
480
|
They usually:
|
|
477
481
|
|
|
478
|
-
- call `
|
|
482
|
+
- call `useCrudAddEditScreen()`
|
|
479
483
|
- wire lookup runtime for lookup-backed fields
|
|
480
|
-
- hand the form runtime into the shared
|
|
484
|
+
- hand the form runtime into the shared `CrudAddEditScreen`
|
|
481
485
|
|
|
482
486
|
These files are mostly containers. That is deliberate.
|
|
483
487
|
|
|
@@ -735,15 +739,14 @@ The safe mental model is:
|
|
|
735
739
|
|
|
736
740
|
### `_components/CrudAddEditForm.vue`
|
|
737
741
|
|
|
738
|
-
This is the
|
|
742
|
+
This is the generated field bridge for the shared add/edit screen.
|
|
739
743
|
|
|
740
744
|
It owns:
|
|
741
745
|
|
|
742
|
-
- the card/surface layout
|
|
743
|
-
- save/cancel buttons
|
|
744
746
|
- which set of generated form fields is rendered in `new` vs `edit`
|
|
747
|
+
- lookup field prop forwarding into those fields
|
|
745
748
|
|
|
746
|
-
It does **not** own persistence logic.
|
|
749
|
+
It does **not** own persistence logic or the shared screen chrome. `CrudAddEditScreen` from `users-web` owns the common title, load state, retry action, save/cancel action row, and form surface.
|
|
747
750
|
|
|
748
751
|
### `_components/CrudAddEditFormFields.js`
|
|
749
752
|
|
|
@@ -766,8 +769,8 @@ That is navigation wiring, not CRUD logic.
|
|
|
766
769
|
|
|
767
770
|
A generated CRUD works because several layers cooperate:
|
|
768
771
|
|
|
769
|
-
1. the route page calls `
|
|
770
|
-
2. those composables
|
|
772
|
+
1. the route page calls `useCrudListScreen()`, `useCrudViewScreen()`, or `useCrudAddEditScreen()`
|
|
773
|
+
2. those screen composables configure the lower-level list/view/add-edit runtimes from `users-web`
|
|
771
774
|
3. the request hits the HTTP route from `registerRoutes.js`
|
|
772
775
|
4. the route executes an action from `actions.js`
|
|
773
776
|
5. the action delegates to the service in `service.js`
|
|
@@ -789,8 +792,9 @@ Use this rule of thumb when deciding where to edit:
|
|
|
789
792
|
| Change default ordering, searchable fields, or ownership autofilter | `contactResource.js` | The shared resource is the single source of truth for both CRUD contract and internal JSON:API resource config |
|
|
790
793
|
| Change SQL, joins, parent filters, or advanced search | `repository.js` | This is the data-access layer |
|
|
791
794
|
| Add cross-record or domain rules on save/delete | `service.js` | This is business logic |
|
|
792
|
-
| Change
|
|
793
|
-
| Change
|
|
795
|
+
| Change shared CRUD screen chrome, load states, or retry behavior | `users-web` shared screen components | Generated pages consume the shared screen contract |
|
|
796
|
+
| Change page-specific display behavior | the route pages, generated slots, and app-owned composables | This is presentation |
|
|
797
|
+
| Change form field layout and inputs | `_components/CrudAddEditForm.vue` and `CrudAddEditFormFields.js` | This is the generated form field layer |
|
|
794
798
|
|
|
795
799
|
## How mature CRUDs grow
|
|
796
800
|
|
|
@@ -824,10 +828,10 @@ This is the default generated list-page pattern for the `contacts` resource from
|
|
|
824
828
|
|
|
825
829
|
#### Client side
|
|
826
830
|
|
|
827
|
-
|
|
831
|
+
The generated list page delegates search wiring to the shared list screen:
|
|
828
832
|
|
|
829
833
|
```js
|
|
830
|
-
const
|
|
834
|
+
const screen = useCrudListScreen({
|
|
831
835
|
resource: uiResource,
|
|
832
836
|
apiSuffix: "/contacts",
|
|
833
837
|
search: {
|
|
@@ -841,15 +845,14 @@ const records = useCrudList({
|
|
|
841
845
|
});
|
|
842
846
|
```
|
|
843
847
|
|
|
844
|
-
Then
|
|
848
|
+
Then render the shared screen:
|
|
845
849
|
|
|
846
850
|
```vue
|
|
847
|
-
<
|
|
848
|
-
v-model="records.searchQuery"
|
|
849
|
-
:loading="records.isSearchDebouncing"
|
|
850
|
-
/>
|
|
851
|
+
<CrudListScreen :screen="screen" />
|
|
851
852
|
```
|
|
852
853
|
|
|
854
|
+
The shared screen binds the search input and passes the search query into the list request.
|
|
855
|
+
|
|
853
856
|
The client runtime debounces the search input, writes the query string to `q`, and trims the list back to the first page when search changes.
|
|
854
857
|
|
|
855
858
|
#### Server side
|
|
@@ -1006,27 +1009,33 @@ Important limits:
|
|
|
1006
1009
|
|
|
1007
1010
|
For the agent-facing quick rule, see `patterns/crud-repository-mapping.md`.
|
|
1008
1011
|
|
|
1009
|
-
### Pattern 3: structured list filters
|
|
1012
|
+
### Pattern 3: client-side structured list filters
|
|
1013
|
+
|
|
1014
|
+
Generated CRUD list pages include a client-side filter seam by default. The generated page imports `./listFilters.js` and passes `listFilters` into `useCrudListScreen(...)`. The shared list screen builds the filter runtime, passes the resulting query params into the list request, and renders `CrudListFilterSurface`.
|
|
1015
|
+
|
|
1016
|
+
If `listFilters.js` is empty, the filter surface renders nothing.
|
|
1010
1017
|
|
|
1011
|
-
|
|
1018
|
+
Use this first when adding filters. The server still needs explicit support for any query params you declare; JSKIT does not infer server filter semantics from the UI.
|
|
1012
1019
|
|
|
1013
1020
|
Do not hand-build:
|
|
1014
1021
|
|
|
1015
1022
|
- one filter shape in the page
|
|
1016
|
-
-
|
|
1017
|
-
-
|
|
1023
|
+
- custom chip/reset/query-param state
|
|
1024
|
+
- a second copy of the same client filter definitions
|
|
1018
1025
|
|
|
1019
1026
|
Instead:
|
|
1020
1027
|
|
|
1021
|
-
1.
|
|
1022
|
-
2.
|
|
1023
|
-
3.
|
|
1024
|
-
4.
|
|
1028
|
+
1. edit the generated page-local `listFilters.js`
|
|
1029
|
+
2. let `useCrudListScreen(...)` wire the filter query params into the list request
|
|
1030
|
+
3. let `CrudListFilterSurface` render controls, chips, clear-one, and clear-all behavior
|
|
1031
|
+
4. add explicit server support separately for the same query params
|
|
1025
1032
|
|
|
1026
|
-
For example, a
|
|
1033
|
+
For example, a generated page-local filter-definition module can look like this:
|
|
1027
1034
|
|
|
1028
1035
|
```js
|
|
1029
|
-
|
|
1036
|
+
import { defineCrudListFilters } from "@jskit-ai/users-web/client/filters";
|
|
1037
|
+
|
|
1038
|
+
const listFilters = defineCrudListFilters({
|
|
1030
1039
|
onlyStaff: {
|
|
1031
1040
|
type: "flag",
|
|
1032
1041
|
label: "Staff"
|
|
@@ -1040,60 +1049,94 @@ export const CONTACTS_LIST_FILTER_DEFINITIONS = Object.freeze({
|
|
|
1040
1049
|
label: "Archived"
|
|
1041
1050
|
}
|
|
1042
1051
|
});
|
|
1052
|
+
|
|
1053
|
+
export { listFilters };
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
### Pattern 3B: client-side bulk list actions
|
|
1057
|
+
|
|
1058
|
+
Generated CRUD list pages also include a client-side bulk-action seam by default. The generated page imports `./listBulkActions.js` and passes `listBulkActions` into `useCrudListScreen(...)`. The shared list screen builds the bulk-action runtime and renders `CrudListBulkActionSurface`.
|
|
1059
|
+
|
|
1060
|
+
If `listBulkActions.js` is empty, selection controls and the bulk action bar stay hidden.
|
|
1061
|
+
|
|
1062
|
+
Use this first when adding selected-record actions. JSKIT does not invent server operations such as delete, archive, approve, or export; the action definition owns that behavior.
|
|
1063
|
+
|
|
1064
|
+
For example:
|
|
1065
|
+
|
|
1066
|
+
```js
|
|
1067
|
+
import { defineCrudListBulkActions } from "@jskit-ai/users-web/client/bulkActions";
|
|
1068
|
+
|
|
1069
|
+
const listBulkActions = defineCrudListBulkActions([
|
|
1070
|
+
{
|
|
1071
|
+
key: "archive",
|
|
1072
|
+
label: "Archive",
|
|
1073
|
+
async run({ selectedIds, clearSelection, reload }) {
|
|
1074
|
+
await archiveContacts(selectedIds);
|
|
1075
|
+
clearSelection();
|
|
1076
|
+
await reload();
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
]);
|
|
1080
|
+
|
|
1081
|
+
export { listBulkActions };
|
|
1043
1082
|
```
|
|
1044
1083
|
|
|
1084
|
+
The generated runtime passes action handlers:
|
|
1085
|
+
|
|
1086
|
+
- `selectedIds`
|
|
1087
|
+
- `ids` as an alias for `selectedIds`
|
|
1088
|
+
- `selectedRecords`
|
|
1089
|
+
- `clearSelection()`
|
|
1090
|
+
- `records`
|
|
1091
|
+
- `reload`
|
|
1092
|
+
|
|
1093
|
+
Keep bulk action definitions page-local unless another page needs to share them.
|
|
1094
|
+
|
|
1045
1095
|
#### Exact file checklist
|
|
1046
1096
|
|
|
1047
1097
|
For a generated CRUD, treat this as the concrete file plan:
|
|
1048
1098
|
|
|
1099
|
+
- edit `src/pages/.../contacts/listFilters.js`
|
|
1100
|
+
- make sure the matching server route/action/repository code already accepts and applies the declared query params
|
|
1101
|
+
|
|
1102
|
+
If the filter contract should be shared with server code, promote it into a CRUD package module and import it from both sides:
|
|
1103
|
+
|
|
1049
1104
|
- create `packages/contacts/src/shared/contactListFilters.js`
|
|
1050
1105
|
- update `packages/contacts/src/server/registerRoutes.js` so the list route query validator lists structured filter params explicitly with `createCrudListFilterQueryField(...)`, unless you already extracted list-query composition into `packages/contacts/src/server/listQueryValidators.js`
|
|
1051
1106
|
- update `packages/contacts/src/server/actions.js` so the list action input validator includes that same explicit contract choice
|
|
1052
1107
|
- update `packages/contacts/src/server/repository.js` so the list query path builds the `createCrudListFilters(...)` runtime and calls `applyQuery(...)`
|
|
1053
|
-
- update the app-owned list page or list-runtime composable, usually under `src/pages/.../contacts/` or `src/composables/...`, so it builds `useCrudListFilters(...)`, passes `queryParams` into `useCrudList(...)`, and renders chips / reset behavior from that runtime
|
|
1054
|
-
|
|
1055
|
-
The only file in that list that is normally **new** is the shared module:
|
|
1056
|
-
|
|
1057
|
-
- `packages/contacts/src/shared/contactListFilters.js`
|
|
1058
|
-
|
|
1059
|
-
The others are normally edits to the generated CRUD package and the app-owned page layer that already exist.
|
|
1060
1108
|
|
|
1061
1109
|
#### Client side
|
|
1062
1110
|
|
|
1063
|
-
|
|
1111
|
+
Generated CRUD list pages pass the page-local filter definitions into the shared list screen:
|
|
1064
1112
|
|
|
1065
1113
|
```js
|
|
1066
|
-
|
|
1114
|
+
import { listFilters } from "./listFilters.js";
|
|
1067
1115
|
|
|
1068
|
-
const
|
|
1116
|
+
const screen = useCrudListScreen({
|
|
1069
1117
|
resource: uiResource,
|
|
1070
1118
|
apiSuffix: "/contacts?include=pets",
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
mode: "query"
|
|
1074
|
-
},
|
|
1075
|
-
queryParams: listFilters.queryParams,
|
|
1076
|
-
syncToRoute: {
|
|
1077
|
-
enabled: true,
|
|
1078
|
-
search: true,
|
|
1079
|
-
queryParams: true,
|
|
1080
|
-
queryParamBlacklist: ["include", "cursor", "limit"]
|
|
1081
|
-
}
|
|
1119
|
+
listFilters,
|
|
1120
|
+
routeQueryBlacklist: Object.freeze(["include", "cursor", "limit"])
|
|
1082
1121
|
});
|
|
1083
1122
|
```
|
|
1084
1123
|
|
|
1085
|
-
|
|
1124
|
+
```vue
|
|
1125
|
+
<CrudListScreen :screen="screen" />
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
Inside that shared screen runtime, `useCrudListFilters(...)` gives the list:
|
|
1086
1129
|
|
|
1087
|
-
- `
|
|
1088
|
-
- `
|
|
1089
|
-
- `
|
|
1090
|
-
- `
|
|
1091
|
-
- `
|
|
1092
|
-
- `
|
|
1093
|
-
- `
|
|
1094
|
-
- `
|
|
1095
|
-
- `
|
|
1096
|
-
- `
|
|
1130
|
+
- `filterRuntime.values`
|
|
1131
|
+
- `filterRuntime.queryParams`
|
|
1132
|
+
- `filterRuntime.presets`
|
|
1133
|
+
- `filterRuntime.activeChips`
|
|
1134
|
+
- `filterRuntime.hasActiveFilters`
|
|
1135
|
+
- `filterRuntime.clearChip(...)`
|
|
1136
|
+
- `filterRuntime.clearFilters()`
|
|
1137
|
+
- `filterRuntime.toggle(...)` for flag filters
|
|
1138
|
+
- `filterRuntime.applyPreset(...)`
|
|
1139
|
+
- `filterRuntime.matchesPreset(...)`
|
|
1097
1140
|
|
|
1098
1141
|
So the same runtime owns:
|
|
1099
1142
|
|
|
@@ -1247,13 +1290,13 @@ async function list(query = {}, callOptions = {}) {
|
|
|
1247
1290
|
|
|
1248
1291
|
#### Best practices
|
|
1249
1292
|
|
|
1250
|
-
-
|
|
1293
|
+
- Keep client-only filters in the generated page-local `listFilters.js`. Move definitions into a CRUD package only when server code or another page needs to share them.
|
|
1251
1294
|
- Keep the filter keys identical all the way through: definition key, query param key, and repository meaning.
|
|
1252
1295
|
- Prefer `createCrudListFilterQueryField(...)` plus `createCrudListFilterQuerySchema(...)` at route/action boundaries so accepted structured-filter params stay visible in app code.
|
|
1253
1296
|
- Use `type: "presence"` for null/not-null filters such as assigned vs unassigned storage. Do not model those as custom enums plus `applyQuery(...)` overrides unless the SQL semantics are genuinely different from `whereNotNull(...)` / `whereNull(...)`.
|
|
1254
1297
|
- Use `createCrudListFilters(...)` unless the list semantics are truly unusual.
|
|
1255
1298
|
- Use `q` for free-text and explicit query params for structured filters.
|
|
1256
|
-
- Run `jskit doctor` after wiring filters. It flags inline
|
|
1299
|
+
- Run `jskit doctor` after wiring filters. It flags inline filter-definition objects passed into `useCrudListFilters(...)` or `createCrudListFilters(...)`.
|
|
1257
1300
|
|
|
1258
1301
|
### Pattern 4: lookup-backed structured filters
|
|
1259
1302
|
|
|
@@ -1265,7 +1308,7 @@ This is the next real-world step: filters like `supplierContactId`, `locationId`
|
|
|
1265
1308
|
|
|
1266
1309
|
The right pattern is:
|
|
1267
1310
|
|
|
1268
|
-
1. keep the lookup filter in
|
|
1311
|
+
1. keep the lookup filter in `listFilters.js` or in shared definitions when server code also imports it
|
|
1269
1312
|
2. use `useCrudListFilters(...)` for state, chips, and query params
|
|
1270
1313
|
3. use `useCrudListFilterLookups(...)` for option loading and label resolution
|
|
1271
1314
|
|
|
@@ -262,7 +262,7 @@ npx jskit generate crud-server-generator scaffold \
|
|
|
262
262
|
|
|
263
263
|
This creates an app-local package under `packages/contacts/`.
|
|
264
264
|
|
|
265
|
-
If the table should be CRUD-owned
|
|
265
|
+
If the table should already be CRUD-owned but should **not** expose public HTTP CRUD routes yet, add:
|
|
266
266
|
|
|
267
267
|
```bash
|
|
268
268
|
--internal
|
|
@@ -322,7 +322,7 @@ npm run devlinks
|
|
|
322
322
|
|
|
323
323
|
The same rule applies after later server scaffolds such as `addresses` and `comments`. The UI generator can still read the generated resource file directly, but the app runtime needs the local package install boundary to be completed before the CRUD can boot normally.
|
|
324
324
|
|
|
325
|
-
For standard CRUDs, that file is
|
|
325
|
+
For standard CRUDs, that file is intentionally compact. It uses `defineCrudResource(...)` from `@jskit-ai/resource-crud-core`, authors the canonical `schema` / `searchSchema` / `defaultSort` / `autofilter` shape once, and lets JSKIT derive the standard CRUD operation contracts from it.
|
|
326
326
|
|
|
327
327
|
### Step 3: scaffold the UI
|
|
328
328
|
|
|
@@ -498,7 +498,7 @@ It will be the block added for the `w/[workspaceSlug]/admin/contacts/[contactId]
|
|
|
498
498
|
|
|
499
499
|
Depending on what outlets already exist in the app, that block may try to place `Addresses` in the shell menu or in the contact subpages outlet. For this example, remove it either way and keep navigation manual from the contact view.
|
|
500
500
|
|
|
501
|
-
This
|
|
501
|
+
This workflow has one intentional manual cleanup:
|
|
502
502
|
|
|
503
503
|
- keep the routed pages
|
|
504
504
|
- remove the auto menu link
|
|
@@ -657,7 +657,7 @@ If the contact view page should stay visible while child comment routes render u
|
|
|
657
657
|
npx jskit generate ui-generator add-subpages \
|
|
658
658
|
w/[workspaceSlug]/admin/contacts/[contactId]/index.vue \
|
|
659
659
|
--title "Contact" \
|
|
660
|
-
--subtitle "
|
|
660
|
+
--subtitle "Contact activity and notes."
|
|
661
661
|
```
|
|
662
662
|
|
|
663
663
|
That is the point where the comments example deliberately overlaps with the `ui-generator` chapter. This pattern needs both:
|
|
@@ -772,4 +772,4 @@ They become one workflow:
|
|
|
772
772
|
2. scaffold the server/resource package
|
|
773
773
|
3. scaffold only the UI shape that the feature actually needs
|
|
774
774
|
|
|
775
|
-
The next chapter is [Advanced CRUDs](/guide/generators/advanced-cruds). Read it as the structural follow-on to this one: this chapter teaches how to generate the CRUD, and the next one teaches how to reason about the files
|
|
775
|
+
The next chapter is [Advanced CRUDs](/guide/generators/advanced-cruds). Read it as the structural follow-on to this one: this chapter teaches how to generate the CRUD, and the next one teaches how to reason about the generated files the app owns.
|
|
@@ -80,7 +80,7 @@ The important default is this:
|
|
|
80
80
|
- if JSKIT sees no nearer routed host, the new page gets a normal shell/menu placement
|
|
81
81
|
- if JSKIT does see a nearer routed host, the new page gets linked into that host instead
|
|
82
82
|
|
|
83
|
-
Open the app
|
|
83
|
+
Open the app to see a real `/reports` page plus a real shell link for it.
|
|
84
84
|
|
|
85
85
|
### Customizing the generated menu link
|
|
86
86
|
|
|
@@ -93,7 +93,8 @@ That is where things such as:
|
|
|
93
93
|
- `label`
|
|
94
94
|
- `order`
|
|
95
95
|
- `icon`
|
|
96
|
-
-
|
|
96
|
+
- `owner`
|
|
97
|
+
- `surfaces`
|
|
97
98
|
|
|
98
99
|
normally get adjusted.
|
|
99
100
|
|
|
@@ -145,21 +146,12 @@ Use this when the generated page link should go somewhere other than the generat
|
|
|
145
146
|
Typical reasons:
|
|
146
147
|
|
|
147
148
|
- you want the page in a different shell menu
|
|
148
|
-
- you want the page link inside a specific existing
|
|
149
|
+
- you want the page link inside a specific existing semantic placement
|
|
149
150
|
- you do not want the link to land in the normal top-level menu
|
|
150
151
|
|
|
151
152
|
For example, if a page should appear in a settings menu rather than the shell drawer, `--link-placement` is the override that says so.
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Use this when the page link should render with a different link component than the default inferred one.
|
|
156
|
-
|
|
157
|
-
In practice, this often means:
|
|
158
|
-
|
|
159
|
-
- using a tab-style link instead of a normal menu link
|
|
160
|
-
- using a local custom link token for a special shell section
|
|
161
|
-
|
|
162
|
-
This matters most once you start targeting non-default outlets. A settings or tab host may want a different link renderer than the main shell drawer.
|
|
154
|
+
The value should normally be semantic, such as `shell.primary-nav`, `page.section-nav`, or another `area.slot` placement from `jskit list-placements`. Concrete `host:position` outlets remain an escape hatch, not the default authoring path.
|
|
163
155
|
|
|
164
156
|
#### `--link-to`
|
|
165
157
|
|
|
@@ -225,7 +217,7 @@ After the command, the page gains three important pieces:
|
|
|
225
217
|
- a `ShellOutlet` for the child-page tabs
|
|
226
218
|
- `RouterView`
|
|
227
219
|
|
|
228
|
-
That
|
|
220
|
+
That lets the page keep rendering shared content while child routes render underneath it.
|
|
229
221
|
|
|
230
222
|
This is the first big distinction in this chapter:
|
|
231
223
|
|
|
@@ -255,7 +247,7 @@ The route page is still a normal page file. What changes is the inferred placeme
|
|
|
255
247
|
- no parent host found -> shell/menu entry
|
|
256
248
|
- nearest parent host found -> child link inside that host
|
|
257
249
|
|
|
258
|
-
So JSKIT is not switching to a different generator.
|
|
250
|
+
So JSKIT is not switching to a different generator. The route tree has a routed host above the new page, so the inferred placement behavior follows that host.
|
|
259
251
|
|
|
260
252
|
### Making a child page the default landing route
|
|
261
253
|
|
|
@@ -330,12 +322,13 @@ But the placement it wrote was **not** another top-level shell link.
|
|
|
330
322
|
Instead, it targeted the host outlet:
|
|
331
323
|
|
|
332
324
|
```text
|
|
333
|
-
|
|
325
|
+
page.section-nav
|
|
334
326
|
```
|
|
335
327
|
|
|
336
|
-
|
|
328
|
+
with the host owner and relative route:
|
|
337
329
|
|
|
338
330
|
```js
|
|
331
|
+
owner: "reports",
|
|
339
332
|
to: "./exports"
|
|
340
333
|
```
|
|
341
334
|
|
|
@@ -345,7 +338,7 @@ That is exactly the behavior you want:
|
|
|
345
338
|
- `Exports` becomes a child tab under it
|
|
346
339
|
- the child route renders under the parent instead of becoming another top-level menu entry
|
|
347
340
|
|
|
348
|
-
This is also why `--link-placement
|
|
341
|
+
This is also why `--link-placement` and `--link-to` are often unnecessary in the default nested case. Once the host exists, JSKIT already knows the likely semantic placement, owner, and relative `to` value. The link renderer comes from `src/placementTopology.js`.
|
|
349
342
|
|
|
350
343
|
## Nested pages under a file-route host
|
|
351
344
|
|
|
@@ -365,7 +358,7 @@ Then upgrade that page into a host:
|
|
|
365
358
|
npx jskit generate ui-generator add-subpages \
|
|
366
359
|
home/contacts/[contactId].vue \
|
|
367
360
|
--title "Contact" \
|
|
368
|
-
--subtitle "
|
|
361
|
+
--subtitle "Contact activity and notes."
|
|
369
362
|
```
|
|
370
363
|
|
|
371
364
|
This time the parent is a file route, not an `index.vue` route.
|
|
@@ -443,13 +436,13 @@ This is different from `page` in a very important way:
|
|
|
443
436
|
|
|
444
437
|
So if the thing you are adding should live *inside* an existing shell region, not at its own route, `placed-element` is the right command.
|
|
445
438
|
|
|
446
|
-
By default, the element
|
|
439
|
+
By default, the element targets the semantic status placement:
|
|
447
440
|
|
|
448
441
|
```text
|
|
449
|
-
shell
|
|
442
|
+
shell.status
|
|
450
443
|
```
|
|
451
444
|
|
|
452
|
-
That is why this is such a good command for widgets, status panels, and compact shell extensions.
|
|
445
|
+
That is why this is such a good command for widgets, status panels, and compact shell extensions. The default shell topology maps `shell.status` to the concrete shell status outlet for each layout class.
|
|
453
446
|
|
|
454
447
|
### When `--surface` matters
|
|
455
448
|
|
|
@@ -476,19 +469,19 @@ A practical example is:
|
|
|
476
469
|
npx jskit generate ui-generator placed-element \
|
|
477
470
|
--name "Ops Panel" \
|
|
478
471
|
--surface admin \
|
|
479
|
-
--placement shell
|
|
472
|
+
--placement shell.status
|
|
480
473
|
```
|
|
481
474
|
|
|
482
|
-
`shell
|
|
475
|
+
`shell.status` can be global across several surfaces. If your app has several enabled surfaces, `--surface admin` tells JSKIT which one this element is actually meant for.
|
|
483
476
|
|
|
484
477
|
So the rule of thumb is:
|
|
485
478
|
|
|
486
|
-
- page-owned
|
|
487
|
-
- shared shell
|
|
479
|
+
- page-owned semantic placement target -> surface is often inferable
|
|
480
|
+
- shared shell semantic placement in a multi-surface app -> pass `--surface`
|
|
488
481
|
|
|
489
482
|
### `--placement`
|
|
490
483
|
|
|
491
|
-
Use `--placement` when the default target `shell
|
|
484
|
+
Use `--placement` when the default target `shell.status` is not what you want.
|
|
492
485
|
|
|
493
486
|
This is the option that answers:
|
|
494
487
|
|
|
@@ -496,6 +489,8 @@ This is the option that answers:
|
|
|
496
489
|
|
|
497
490
|
In practice, it is the first override you will use for `placed-element`.
|
|
498
491
|
|
|
492
|
+
`--placement` expects a semantic placement id such as `shell.status`, `shell.global-actions`, or `settings.sections`. Concrete `host:position` outlets are exposed through topology, not used as normal placed-element authoring targets.
|
|
493
|
+
|
|
499
494
|
### `--path`
|
|
500
495
|
|
|
501
496
|
Use `--path` when the component file should live somewhere other than `src/components`.
|
|
@@ -532,13 +527,15 @@ In the verified throwaway app, after generating `Alerts Widget`, I ran:
|
|
|
532
527
|
```bash
|
|
533
528
|
npx jskit generate ui-generator outlet \
|
|
534
529
|
src/components/AlertsWidgetElement.vue \
|
|
535
|
-
--target alerts-widget:actions
|
|
530
|
+
--target alerts-widget:actions \
|
|
531
|
+
--placement page.actions
|
|
536
532
|
```
|
|
537
533
|
|
|
538
|
-
That command touched
|
|
534
|
+
That command touched the Vue file and the topology file:
|
|
539
535
|
|
|
540
536
|
```text
|
|
541
537
|
src/components/AlertsWidgetElement.vue
|
|
538
|
+
src/placementTopology.js
|
|
542
539
|
```
|
|
543
540
|
|
|
544
541
|
and injected:
|
|
@@ -561,13 +558,16 @@ Use `outlet` when you want:
|
|
|
561
558
|
- later content to be targetable there
|
|
562
559
|
- no routed child-page behavior
|
|
563
560
|
|
|
564
|
-
After adding the outlet, `npx jskit list-placements` showed the new
|
|
561
|
+
After adding the outlet, `npx jskit list-placements` showed the new semantic placement immediately:
|
|
565
562
|
|
|
566
563
|
```text
|
|
567
|
-
-
|
|
564
|
+
- page.actions: ...
|
|
565
|
+
- compact -> alerts-widget:actions
|
|
566
|
+
- medium -> alerts-widget:actions
|
|
567
|
+
- expanded -> alerts-widget:actions
|
|
568
568
|
```
|
|
569
569
|
|
|
570
|
-
So `outlet` is the smallest possible way to
|
|
570
|
+
So `outlet` is the smallest possible way to add a concrete recipient and expose it through the public placement topology in the same change.
|
|
571
571
|
|
|
572
572
|
### When `outlet` is the smaller correct tool
|
|
573
573
|
|
|
@@ -588,7 +588,7 @@ That is why `outlet` is often the better choice for:
|
|
|
588
588
|
|
|
589
589
|
If you do **not** need `RouterView` and you do **not** need child routes, `outlet` is usually the cleaner tool.
|
|
590
590
|
|
|
591
|
-
### Choosing a good custom `--target`
|
|
591
|
+
### Choosing a good custom `--target` and `--placement`
|
|
592
592
|
|
|
593
593
|
`--target` should be meaningful to humans, not just syntactically valid.
|
|
594
594
|
|
|
@@ -611,12 +611,20 @@ custom-area:slot1
|
|
|
611
611
|
|
|
612
612
|
because the meaningful target name will later show up in:
|
|
613
613
|
|
|
614
|
-
- `jskit list-placements`
|
|
615
|
-
-
|
|
614
|
+
- `jskit list-placements --concrete`
|
|
615
|
+
- topology mappings
|
|
616
616
|
- future generator commands
|
|
617
617
|
|
|
618
618
|
So the target should describe the UI seam you are creating, not just satisfy the `host:position` format.
|
|
619
619
|
|
|
620
|
+
`--placement` is the public authoring target that other entries should use. It should be semantic, such as:
|
|
621
|
+
|
|
622
|
+
```text
|
|
623
|
+
page.actions
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Adding an outlet without adding a semantic mapping would leave a low-level recipient that normal generators and humans will not discover by default.
|
|
627
|
+
|
|
620
628
|
## `add-subpages` versus `outlet`
|
|
621
629
|
|
|
622
630
|
This is the distinction that most often causes hesitation.
|
|
@@ -676,4 +684,4 @@ That is why the commands fit together cleanly:
|
|
|
676
684
|
- `page` can then create nested child routes under those hosts
|
|
677
685
|
- `placed-element` and `outlet` handle the non-routed side of the same UI system
|
|
678
686
|
|
|
679
|
-
Once the UI you want
|
|
687
|
+
Once the UI you want needs real database-backed list/view/new/edit behavior instead of only page structure, move to the CRUD generators chapter.
|
package/guide/agent/index.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
This guide is the main hands-on path through JSKIT.
|
|
6
6
|
|
|
7
|
-
It
|
|
7
|
+
It starts with a fast reproducible Quickstart, then steps back to the smaller scaffold-first chapters that explain how the app is assembled piece by piece. After that, it introduces the database-backed users layer, expands into console and workspace-aware app structure, and adds a small `App extras` section for optional runtime packages such as the Android Capacitor shell, realtime, and assistant. Finally, the guide breaks out generator-specific workflows into their own section.
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
|
@@ -22,6 +22,7 @@ It now starts with a fast reproducible Quickstart, then steps back to the smalle
|
|
|
22
22
|
|
|
23
23
|
### App Extras
|
|
24
24
|
|
|
25
|
+
- [Mobile Capacitor](/guide/app-extras/mobile-capacitor)
|
|
25
26
|
- [Realtime](/guide/app-extras/realtime)
|
|
26
27
|
- [Assistant](/guide/app-extras/assistant)
|
|
27
28
|
|
|
@@ -36,6 +37,6 @@ It now starts with a fast reproducible Quickstart, then steps back to the smalle
|
|
|
36
37
|
|
|
37
38
|
- Start with `Quickstart` if you want the fastest route to a real workspace-enabled app and the first page-extension patterns.
|
|
38
39
|
- Start with the rest of `App Setup` if you want to understand the base scaffold layer by layer.
|
|
39
|
-
- Use `App Extras` once the base app structure is in place and you want optional runtime packages.
|
|
40
|
+
- Use `App Extras` once the base app structure is in place and you want optional runtime packages such as the Android shell, realtime, or assistant.
|
|
40
41
|
- Jump into `Generators` if you already understand the runtime packages and want app-owned scaffolding workflows.
|
|
41
42
|
- Inside `Generators`, read `CRUD Generators` before `Advanced CRUDs`: the first chapter teaches the workflow, and the second explains the generated anatomy and customization points.
|
package/package.json
CHANGED
package/patterns/INDEX.md
CHANGED
|
@@ -26,10 +26,12 @@ How to use it:
|
|
|
26
26
|
- `page-redirects.md`
|
|
27
27
|
- live actions, checkbox, toggle, patch button, inline action, `useCommand()`
|
|
28
28
|
- `live-actions.md`
|
|
29
|
-
- ajax, fetch, API call, request, endpoint, HTTP client, `useList()`, `useView()`, `useAddEdit()`, `useEndpointResource()`, `usersWebHttpClient`
|
|
29
|
+
- ajax, fetch, API call, request, endpoint, HTTP client, `useCrudListScreen()`, `useCrudViewScreen()`, `useCrudAddEditScreen()`, `useList()`, `useView()`, `useAddEdit()`, `useEndpointResource()`, `usersWebHttpClient`
|
|
30
30
|
- `client-requests.md`
|
|
31
31
|
- playwright, browser test, e2e, ui verification, authenticated ui test, test auth, dev login as, dev auth bypass
|
|
32
32
|
- `ui-testing.md`
|
|
33
|
+
- generated UI contract, design contract, navigation roles, density, placeholder copy, card shells, shared CRUD screens
|
|
34
|
+
- `generated-ui-contract-tracking.md`
|
|
33
35
|
- filter, filters, search facets, chips, date range, enum filter, lookup filter, `useCrudListFilters`, `createCrudListFilters`
|
|
34
36
|
- `filters.md`
|
|
35
37
|
- `searchSchema`, `search: true`, `applyFilter`, server search, query validators, backend filters, internal JSON REST filters
|
|
@@ -49,6 +51,7 @@ How to use it:
|
|
|
49
51
|
- [live-actions.md](./live-actions.md)
|
|
50
52
|
- [client-requests.md](./client-requests.md)
|
|
51
53
|
- [ui-testing.md](./ui-testing.md)
|
|
54
|
+
- [generated-ui-contract-tracking.md](./generated-ui-contract-tracking.md)
|
|
52
55
|
- [filters.md](./filters.md)
|
|
53
56
|
- [server-search.md](./server-search.md)
|
|
54
57
|
- [crud-repository-mapping.md](./crud-repository-mapping.md)
|