@jskit-ai/agent-docs 0.1.279 → 0.1.281
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/guide/agent/app-extras/assistant-conversation.md +5 -1
- package/guide/agent/app-extras/assistant.md +123 -0
- package/guide/agent/app-extras/realtime.md +20 -10
- package/guide/agent/app-setup/authentication.md +54 -4
- package/guide/agent/app-setup/database-layer.md +108 -35
- package/guide/agent/app-setup/existing-application-migration.md +7 -1
- package/guide/agent/app-setup/material-3-migration.md +38 -9
- package/guide/agent/app-setup/multi-homing.md +14 -4
- package/guide/agent/app-setup/upgrading-jskit.md +105 -0
- package/guide/agent/app-setup/users.md +9 -1
- package/guide/agent/framework/client-features.md +35 -1
- package/guide/agent/framework/material-3.md +111 -71
- package/guide/agent/framework/sanity-checks.md +181 -0
- package/guide/agent/framework/translation.md +4 -0
- package/guide/agent/framework/typed-features.md +222 -120
- package/guide/agent/framework/ui-operations.md +3 -1
- package/guide/agent/index.md +3 -0
- package/package.json +2 -2
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/PATTERN.md +6 -2
- package/patterns/minimal-foundation/example/AGENTS.md +22 -5
- package/patterns/minimal-foundation/example/package.json +6 -6
- package/patterns/minimal-foundation/example/playwright.config.mjs +3 -30
- package/patterns/minimal-foundation/example/server.js +7 -1
- package/patterns/minimal-foundation/example/src/main.js +3 -2
- package/patterns/minimal-foundation/example/tests/e2e/startup.spec.ts +13 -0
- package/patterns/minimal-foundation/example/vite.config.mjs +3 -1
- package/patterns/shell-foundation/PATTERN.md +4 -1
- package/patterns/shell-foundation/example/AGENTS.md +22 -5
- package/patterns/shell-foundation/example/package.json +7 -7
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +3 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +3 -30
- package/patterns/shell-foundation/example/server.js +7 -1
- package/patterns/shell-foundation/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/patterns/shell-foundation/example/src/main.js +3 -2
- package/patterns/shell-foundation/example/src/pages/home.vue +1 -1
- package/patterns/shell-foundation/example/src/views/NotFound.vue +1 -1
- package/patterns/shell-foundation/example/tests/e2e/startup.spec.ts +13 -0
- package/patterns/shell-foundation/example/vite.config.mjs +3 -1
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/packages/agent-docs.md +4 -0
- package/reference/autogen/packages/architecture-inspector.md +1 -0
- package/reference/autogen/packages/assistant-runtime.md +28 -3
- package/reference/autogen/packages/auth-provider-local-core.md +2 -1
- package/reference/autogen/packages/auth-web.md +10 -0
- package/reference/autogen/packages/connectors-catalog.md +8 -0
- package/reference/autogen/packages/crud-core.md +3 -0
- package/reference/autogen/packages/database-runtime.md +33 -0
- package/reference/autogen/packages/http-web.md +0 -4
- package/reference/autogen/packages/json-rest-api-core.md +17 -4
- package/reference/autogen/packages/kernel.md +37 -2
- package/reference/autogen/packages/material-web.md +2 -1
- package/reference/autogen/packages/oidc-issuer-core.md +0 -1
- package/reference/autogen/packages/realtime.md +8 -5
- package/reference/autogen/packages/shell-web.md +88 -3
- package/reference/autogen/packages/users-web.md +5 -2
- package/reference/autogen/packages/workspaces-core.md +3 -1
- package/reference/autogen/tooling/jskit-catalog.md +122 -5
- package/reference/autogen/tooling/testUtils.md +15 -1
- package/skills/jskit/SKILL.md +17 -5
- package/skills/jskit/references/client-features.md +35 -1
- package/skills/jskit/references/existing-application-migration.md +7 -1
- package/skills/jskit/references/heuristics/INDEX.md +3 -1
- package/skills/jskit/references/heuristics/row-policies.md +3 -3
- package/skills/jskit/references/heuristics/typed-features.md +7 -7
- package/skills/jskit/references/heuristics/ui-testing.md +27 -21
- package/skills/jskit/references/material-3.md +111 -71
- package/skills/jskit/references/multi-homing.md +14 -4
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +6 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +22 -5
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +6 -6
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +3 -30
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +7 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/main.js +3 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/e2e/startup.spec.ts +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/vite.config.mjs +3 -1
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +4 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +22 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +7 -7
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +3 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +3 -30
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +7 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/main.js +3 -2
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home.vue +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/views/NotFound.vue +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/startup.spec.ts +13 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/vite.config.mjs +3 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +18 -5
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/components/AppBrand.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/login.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/reset-password.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/signout.vue +2 -2
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/LoginView.vue +6 -1
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/ResetPasswordView.vue +6 -1
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/SignOutView.vue +6 -1
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/formats/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console.vue +1 -1
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +34 -24
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +3 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/tests/e2e/databases.js +25 -0
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +12 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +3 -2
- package/skills/jskit/references/patterns/database/postgres-application/example/tests/e2e/databases.js +25 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +11 -6
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/SectionTabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home.vue +1 -1
- package/skills/jskit/references/patterns/shell/application-shell/example/src/views/NotFound.vue +1 -1
- package/skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md +6 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue +9 -4
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +5 -3
- package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +24 -3
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue +1 -1
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +2 -1
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +3 -2
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/[section].vue +23 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account.vue +4 -3
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue +3 -3
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/root.vue +1 -1
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/root.vue +1 -1
- package/skills/jskit/references/sanity-checks.md +181 -0
- package/skills/jskit/references/translation.md +4 -0
- package/skills/jskit/references/typed-features.md +222 -120
- package/skills/jskit/references/ui-operations.md +3 -1
- package/skills/jskit/references/patterns/database/mysql-application/example/tests/browser/database.js +0 -68
|
@@ -55,12 +55,17 @@ placement registry, topology, and adaptive smoke helper exported by
|
|
|
55
55
|
border widths to `0` and gives navigation a tonal surface, for example
|
|
56
56
|
`rgb(var(--v-theme-surface-container-low))` when the theme defines it.
|
|
57
57
|
- `createShellRouter()` from `@jskit-ai/kernel/client` installs
|
|
58
|
-
`shellScrollBehavior`: a new screen opens at the top (or its hash target
|
|
59
|
-
Back/Forward restore the saved
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
`shellScrollBehavior`: a new screen opens at the top (or its hash target,
|
|
59
|
+
below the target's `scroll-margin-top`), Back/Forward restore the saved
|
|
60
|
+
position, and query, hash, tab or sub-view changes within the same page keep
|
|
61
|
+
it. A tab or sub-view is the same page when both locations share a parent
|
|
62
|
+
page record below the surface root that draws a component, a layout hosting
|
|
63
|
+
the tabs; a folder's component-less record, as file routing creates for
|
|
64
|
+
`bookings/`, makes its pages different pages. Pass `scrollBehavior` to replace it
|
|
65
|
+
(calling `shellScrollBehavior` for what it leaves to the shell), or
|
|
66
|
+
`scrollBehavior: false` to disable it. A `createRouter` that replaces the
|
|
67
|
+
behaviour it is given throws, so never set one there; do not wrap the router
|
|
68
|
+
or reset scroll in page components.
|
|
64
69
|
- The adaptive browser check closes navigation through its public close control.
|
|
65
70
|
|
|
66
71
|
## Example files
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ShellSectionTabLinkItem from "@jskit-ai/shell-web/client/components/ShellSectionTabLinkItem";
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
label: {
|
|
6
|
+
type: String,
|
|
7
|
+
default: ""
|
|
8
|
+
},
|
|
9
|
+
to: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: ""
|
|
12
|
+
},
|
|
13
|
+
icon: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: ""
|
|
16
|
+
},
|
|
17
|
+
surface: {
|
|
18
|
+
type: String,
|
|
19
|
+
default: ""
|
|
20
|
+
},
|
|
21
|
+
scopedSuffix: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: "/"
|
|
24
|
+
},
|
|
25
|
+
unscopedSuffix: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: "/"
|
|
28
|
+
},
|
|
29
|
+
disabled: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false
|
|
32
|
+
},
|
|
33
|
+
exact: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<ShellSectionTabLinkItem v-bind="props" />
|
|
42
|
+
</template>
|
package/skills/jskit/references/patterns/shell/application-shell/example/src/views/NotFound.vue
CHANGED
|
@@ -6,7 +6,7 @@ const message = "The page you requested does not exist.";
|
|
|
6
6
|
|
|
7
7
|
<template>
|
|
8
8
|
<!-- The shell's top app bar carries the title, and its navigation leads back into the app. -->
|
|
9
|
-
<ShellLayout title="Not Found"
|
|
9
|
+
<ShellLayout title="Not Found">
|
|
10
10
|
<section class="d-flex flex-column align-center text-center on-surface-variant py-16">
|
|
11
11
|
<v-icon icon="$searchOff" size="48" />
|
|
12
12
|
<p class="text-body-large mt-4 mb-0">{{ message }}</p>
|
|
@@ -35,6 +35,12 @@ a filename alone.
|
|
|
35
35
|
- Child links share an explicit section owner.
|
|
36
36
|
- Topology maps each semantic placement to concrete responsive outlets.
|
|
37
37
|
- Placed components are registered by token through a client provider.
|
|
38
|
+
- Section navigation is Material 3 primary tabs: the section's `page.section-nav`
|
|
39
|
+
topology names a section-tab renderer (`ShellSectionTabLinkItem`, registered as
|
|
40
|
+
`local.main.ui.section-tab-link-item`), and the page draws the tab row (one
|
|
41
|
+
row over a 1dp `outline-variant` divider that scrolls sideways). A navigation
|
|
42
|
+
bar destination (`ShellTabLinkItem`) belongs to the shell's navigation bar
|
|
43
|
+
only; placed in a page it draws a section tab.
|
|
38
44
|
- Compact navigation controls remain accessible and at least 48 CSS pixels.
|
|
39
45
|
- Application source has no generated-file marker, receipt, or overwrite state.
|
|
40
46
|
|
package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue
CHANGED
|
@@ -8,10 +8,9 @@ definePage({ meta: { jskit: { title: "Reports" } } });
|
|
|
8
8
|
|
|
9
9
|
<template>
|
|
10
10
|
<section class="reports-section d-flex flex-column ga-4">
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</v-tabs>
|
|
11
|
+
<!-- Material 3 primary tabs: one row over a divider, scrolling sideways when the tabs don't fit. -->
|
|
12
|
+
<nav class="reports-section__tabs" aria-label="Report sections">
|
|
13
|
+
<ShellOutlet target="reports:section-nav" />
|
|
15
14
|
</nav>
|
|
16
15
|
|
|
17
16
|
<div class="reports-section__content">
|
|
@@ -25,4 +24,10 @@ definePage({ meta: { jskit: { title: "Reports" } } });
|
|
|
25
24
|
.reports-section__content {
|
|
26
25
|
min-width: 0;
|
|
27
26
|
}
|
|
27
|
+
|
|
28
|
+
.reports-section__tabs {
|
|
29
|
+
border-bottom: 1px solid rgb(var(--v-theme-outline-variant));
|
|
30
|
+
display: flex;
|
|
31
|
+
overflow-x: auto;
|
|
32
|
+
}
|
|
28
33
|
</style>
|
package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js
CHANGED
|
@@ -4,6 +4,8 @@ function addPlacementTopology(value = {}) {
|
|
|
4
4
|
placements.push(value);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
// The section's tabs: Material 3 primary tabs at every width (the shell's section-tab renderer), never navigation bar
|
|
8
|
+
// destinations, which belong to the shell's navigation bar alone.
|
|
7
9
|
addPlacementTopology({
|
|
8
10
|
id: "page.section-nav",
|
|
9
11
|
owner: "reports",
|
|
@@ -12,15 +14,15 @@ addPlacementTopology({
|
|
|
12
14
|
variants: {
|
|
13
15
|
compact: {
|
|
14
16
|
outlet: "reports:section-nav",
|
|
15
|
-
renderers: { link: "local.main.ui.tab-link-item" }
|
|
17
|
+
renderers: { link: "local.main.ui.section-tab-link-item" }
|
|
16
18
|
},
|
|
17
19
|
medium: {
|
|
18
20
|
outlet: "reports:section-nav",
|
|
19
|
-
renderers: { link: "local.main.ui.tab-link-item" }
|
|
21
|
+
renderers: { link: "local.main.ui.section-tab-link-item" }
|
|
20
22
|
},
|
|
21
23
|
expanded: {
|
|
22
24
|
outlet: "reports:section-nav",
|
|
23
|
-
renderers: { link: "local.main.ui.tab-link-item" }
|
|
25
|
+
renderers: { link: "local.main.ui.section-tab-link-item" }
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
});
|
|
@@ -38,6 +38,18 @@ app's language; the app does, for example
|
|
|
38
38
|
`watch(useAccountLocale(), (code) => { if (code) i18n.global.locale.value = code; }, { immediate: true })`.
|
|
39
39
|
Section titles may be plain text, a message key or `{ key, fallback }`.
|
|
40
40
|
|
|
41
|
+
Sections are pages of the account surface, in Material 3's list-detail layout
|
|
42
|
+
(shell-web's `ShellListDetail`): `/account` is the section list
|
|
43
|
+
(`src/pages/account/index.vue`) and `/account/<section>` one section
|
|
44
|
+
(`src/pages/account/[section].vue`, its `value`, such as
|
|
45
|
+
`/account/preferences`), both rendering `AccountSettingsClientElement`, which
|
|
46
|
+
reads the section from the route's `section` param. The section page's parent
|
|
47
|
+
is the list, the surface's `"/"`. A phone or medium window shows the list or one
|
|
48
|
+
section, and Up returns from the section to the list; an expanded or large
|
|
49
|
+
window shows the list beside the open section, or beside the first section on
|
|
50
|
+
the list's own page. A link to a section is its path, `/account/invites`, with
|
|
51
|
+
`returnTo` in the query for Done.
|
|
52
|
+
|
|
41
53
|
`runtime.signInMethods.methods` lists the auth provider's OAuth sign-in
|
|
42
54
|
methods as `{ provider, label, linked, canLink, canUnlink }`, read from the
|
|
43
55
|
settings security status. `link(provider)` leaves for the provider through
|
|
@@ -59,12 +71,19 @@ provider offers provider linking (`providerLinking` in its capabilities).
|
|
|
59
71
|
- The route and placement owner agree.
|
|
60
72
|
- The account surface renders in its own layout, `src/pages/account.vue`
|
|
61
73
|
(`ShellLayout` around `<RouterView />`, `meta.jskit.surface: "account"`), so
|
|
62
|
-
the settings page's title
|
|
74
|
+
the settings page's title and Up arrow are in the top app bar. Up is the
|
|
75
|
+
page's only way out; `AccountSettingsClientElement` adds a Done action only
|
|
76
|
+
where Up can't go back (no parent, a section beside the list on a wide
|
|
77
|
+
window, or a returnTo on another origin).
|
|
63
78
|
With no navigation items, the surface shows no navigation bar, rail or drawer.
|
|
79
|
+
- Each section has its own address, `/account/<section>`, served by
|
|
80
|
+
`src/pages/account/[section].vue` with parent `"/"`; nothing selects a
|
|
81
|
+
section through the query.
|
|
64
82
|
|
|
65
83
|
## Example files
|
|
66
84
|
|
|
67
|
-
`example/` contains the account surface's layout,
|
|
85
|
+
`example/` contains the account surface's layout, the section list's route
|
|
86
|
+
(`account/index.vue`), a section's route (`account/[section].vue`) and four
|
|
68
87
|
concrete settings sections.
|
|
69
88
|
Adapt their fields and copy while retaining the shared account runtime.
|
|
70
89
|
|
|
@@ -77,7 +96,9 @@ notification vocabulary while keeping server-owned validation authoritative.
|
|
|
77
96
|
|
|
78
97
|
Navigate away and back with warm cache, exercise browser back/forward, save and
|
|
79
98
|
clear fields, verify toast errors, inspect skeleton geometry, and test keyboard
|
|
80
|
-
operation at compact and expanded widths.
|
|
99
|
+
operation at compact and expanded widths. At 390 px check that the list and a
|
|
100
|
+
section show one at a time and Up returns from the section to the list; at
|
|
101
|
+
1280 px that the list shows beside the open section, with no Up.
|
|
81
102
|
|
|
82
103
|
## Avoid
|
|
83
104
|
|
|
@@ -35,11 +35,11 @@ const notifications = props.runtime.notifications;
|
|
|
35
35
|
color="primary"
|
|
36
36
|
hide-details
|
|
37
37
|
disabled
|
|
38
|
-
class="mb-4"
|
|
39
38
|
/>
|
|
40
39
|
<v-btn
|
|
41
40
|
type="submit"
|
|
42
41
|
color="primary"
|
|
42
|
+
class="mt-4"
|
|
43
43
|
:loading="notifications.isSaving.value"
|
|
44
44
|
:disabled="notifications.isRefreshing.value"
|
|
45
45
|
>
|
|
@@ -94,7 +94,7 @@ const preferences = props.runtime.preferences;
|
|
|
94
94
|
/>
|
|
95
95
|
</v-col>
|
|
96
96
|
|
|
97
|
-
<v-col cols="12" md="
|
|
97
|
+
<v-col cols="12" md="4">
|
|
98
98
|
<v-select
|
|
99
99
|
v-model.number="preferences.form.avatarSize"
|
|
100
100
|
label="Avatar size"
|
|
@@ -110,6 +110,7 @@ const preferences = props.runtime.preferences;
|
|
|
110
110
|
<v-btn
|
|
111
111
|
type="submit"
|
|
112
112
|
color="primary"
|
|
113
|
+
class="mt-4"
|
|
113
114
|
:loading="preferences.isSaving.value"
|
|
114
115
|
:disabled="preferences.isRefreshing.value"
|
|
115
116
|
>
|
|
@@ -51,7 +51,7 @@ const profile = props.runtime.profile;
|
|
|
51
51
|
</v-row>
|
|
52
52
|
|
|
53
53
|
<v-row>
|
|
54
|
-
<v-col cols="12"
|
|
54
|
+
<v-col cols="12">
|
|
55
55
|
<v-text-field
|
|
56
56
|
v-model="profile.form.displayName"
|
|
57
57
|
label="Display name"
|
|
@@ -63,7 +63,7 @@ const profile = props.runtime.profile;
|
|
|
63
63
|
/>
|
|
64
64
|
</v-col>
|
|
65
65
|
|
|
66
|
-
<v-col cols="12"
|
|
66
|
+
<v-col cols="12">
|
|
67
67
|
<v-text-field
|
|
68
68
|
v-model="profile.form.email"
|
|
69
69
|
label="Email"
|
|
@@ -79,6 +79,7 @@ const profile = props.runtime.profile;
|
|
|
79
79
|
<v-btn
|
|
80
80
|
type="submit"
|
|
81
81
|
color="primary"
|
|
82
|
+
class="mt-4"
|
|
82
83
|
:loading="profile.isSaving.value"
|
|
83
84
|
:disabled="profile.isDeletingAvatar.value || profile.isRefreshing.value"
|
|
84
85
|
>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<route lang="json">
|
|
2
|
+
{
|
|
3
|
+
"meta": {
|
|
4
|
+
"guard": {
|
|
5
|
+
"policy": "authenticated"
|
|
6
|
+
},
|
|
7
|
+
"jskit": {
|
|
8
|
+
"title": "Account settings",
|
|
9
|
+
"parent": "/"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
</route>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<AccountSettingsClientElement />
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
// One section of account settings (/account/preferences). Its parent is the section list, the surface's "/", so on a
|
|
21
|
+
// phone Up returns to the list; a wide window shows the list beside the section.
|
|
22
|
+
import AccountSettingsClientElement from "@jskit-ai/users-web/client/components/AccountSettingsClientElement";
|
|
23
|
+
</script>
|
package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account.vue
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
</route>
|
|
10
10
|
|
|
11
11
|
<script setup>
|
|
12
|
-
// The account surface's layout: the shell's top app bar carries the settings page's title
|
|
13
|
-
//
|
|
12
|
+
// The account surface's layout: the shell's top app bar carries the settings page's title and its Up arrow back to
|
|
13
|
+
// home, the page's only way out (a Done action shows only where Up can't go back, such as a returnTo on another of
|
|
14
|
+
// the app's origins). The surface has no navigation items, so the shell draws no navigation bar, rail or drawer.
|
|
14
15
|
import ShellLayout from "@/components/ShellLayout.vue";
|
|
15
16
|
import { RouterView } from "vue-router";
|
|
16
17
|
</script>
|
|
17
18
|
|
|
18
19
|
<template>
|
|
19
|
-
<ShellLayout
|
|
20
|
+
<ShellLayout>
|
|
20
21
|
<RouterView />
|
|
21
22
|
</ShellLayout>
|
|
22
23
|
</template>
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"./shared": "./src/shared/index.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@jskit-ai/crud-core": "0.2.
|
|
14
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
13
|
+
"@jskit-ai/crud-core": "0.2.13",
|
|
14
|
+
"@jskit-ai/resource-crud-core": "0.1.203"
|
|
15
15
|
},
|
|
16
16
|
"jskit": {
|
|
17
17
|
"kind": "runtime",
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
"./shared": "./src/shared/index.js"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@jskit-ai/crud-core": "0.2.
|
|
14
|
-
"@jskit-ai/resource-crud-core": "0.1.
|
|
15
|
-
"@jskit-ai/workspaces-core": "0.2.
|
|
13
|
+
"@jskit-ai/crud-core": "0.2.13",
|
|
14
|
+
"@jskit-ai/resource-crud-core": "0.1.203",
|
|
15
|
+
"@jskit-ai/workspaces-core": "0.2.14"
|
|
16
16
|
},
|
|
17
17
|
"jskit": {
|
|
18
18
|
"kind": "runtime",
|
|
@@ -57,16 +57,16 @@ const isVisible = computed(() => {
|
|
|
57
57
|
|
|
58
58
|
const resolvedTo = computed(() => {
|
|
59
59
|
const hasAccountSurface = Boolean(resolveSurfaceDefinitionFromPlacementContext(placementContext.value, "account"));
|
|
60
|
+
// The invitations section of account settings, /account/invites.
|
|
60
61
|
const accountSettingsPath = hasAccountSurface
|
|
61
|
-
? resolveSurfacePathFromPlacementContext(placementContext.value, "account", "/")
|
|
62
|
-
: "/account";
|
|
62
|
+
? resolveSurfacePathFromPlacementContext(placementContext.value, "account", "/invites")
|
|
63
|
+
: "/account/invites";
|
|
63
64
|
const accountSettingsNavigation = resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
64
65
|
path: accountSettingsPath,
|
|
65
66
|
surfaceId: "account"
|
|
66
67
|
});
|
|
67
68
|
|
|
68
69
|
const query = new URLSearchParams({
|
|
69
|
-
section: "invites",
|
|
70
70
|
returnTo: accountSettingsNavigation.sameOrigin ? resolveReturnTo() : resolveReturnToHref()
|
|
71
71
|
});
|
|
72
72
|
return appendQueryString(accountSettingsPath, query.toString());
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!-- Generated from `packages/agent-docs/site/guide/framework/sanity-checks.md`. -->
|
|
2
|
+
|
|
3
|
+
# Sanity checks
|
|
4
|
+
|
|
5
|
+
Before calling a list, a save, a test, a refactor, a screen or a deployment
|
|
6
|
+
done, measure what it actually costs and does, judge whether that is sane, and
|
|
7
|
+
fix the cause when it is not. This page is the JSKIT part of that: the
|
|
8
|
+
pitfalls JSKIT's own packages cause, then which JSKIT call, helper or setting
|
|
9
|
+
applies each check, with one line on what the check catches and why.
|
|
10
|
+
|
|
11
|
+
## JSKIT's own pitfalls
|
|
12
|
+
|
|
13
|
+
### Theme and component defaults
|
|
14
|
+
|
|
15
|
+
**Check:** after changing a theme, a Vuetify default, a material-web default
|
|
16
|
+
or a shared component, use what it affects in a production build: open a
|
|
17
|
+
select and type, press a segmented button at desktop width, tap neighbouring
|
|
18
|
+
icon buttons, and leave a field to see whether the layout shifts under the
|
|
19
|
+
next tap. A default reaches every component that renders the one it names, so
|
|
20
|
+
a change made for one screen can break others that never import it
|
|
21
|
+
([Material 3](material-3.md)).
|
|
22
|
+
|
|
23
|
+
**Examples:**
|
|
24
|
+
|
|
25
|
+
- A `VMenu: { VSheet: {} }` default broke a select's typeahead.
|
|
26
|
+
- A common button padding squeezed segmented buttons into slivers.
|
|
27
|
+
- A field that grew 32 px on blur moved the button under a person's tap.
|
|
28
|
+
|
|
29
|
+
### Navigation metadata
|
|
30
|
+
|
|
31
|
+
**Check:** open each inner page directly and by link, and see its Up arrow
|
|
32
|
+
and title. Some navigation declarations look right but switch Up off, and
|
|
33
|
+
some shapes leave pages the navigation rules cannot judge
|
|
34
|
+
([Material 3](material-3.md)):
|
|
35
|
+
|
|
36
|
+
- a parent declared beside `jskit.surface` is never read; the surface goes on
|
|
37
|
+
the layout page and the parent on the page it renders (`nav/surface-parent`
|
|
38
|
+
reports the two on one record);
|
|
39
|
+
- an inner page repeating its surface becomes a root of its own, with no Up;
|
|
40
|
+
- until a main-navigation placement is literal data, no page is judged for a
|
|
41
|
+
missing parent (`nav/placement-data`);
|
|
42
|
+
- a layout that also renders its pages without `ShellLayout` leaves those
|
|
43
|
+
pages unjudged by `nav/missing-parent`, so a missing parent passes;
|
|
44
|
+
- a package route is judged only when its client entry lists
|
|
45
|
+
`routeComponents` literally; a built map passes unjudged.
|
|
46
|
+
|
|
47
|
+
**Example:** a design-system update moved a page title into a top app bar
|
|
48
|
+
that one page did not have, so its title vanished; only the browser suite
|
|
49
|
+
caught it.
|
|
50
|
+
|
|
51
|
+
### Generated action and tool contracts
|
|
52
|
+
|
|
53
|
+
**Check:** call each assistant tool the way the model will, with sparse
|
|
54
|
+
`fields` and an `include`, and compare the result with the output contract it
|
|
55
|
+
advertises. An action is a tool only when it has an input contract and a
|
|
56
|
+
truthful model-facing output; the assistant validates the result against
|
|
57
|
+
`extensions.assistant.output` and rejects unexpected fields, so a contract
|
|
58
|
+
that promises what execution cannot return fails at run time, not at review
|
|
59
|
+
([Assistant](/guide/app-extras/assistant#database-surface-action-tools)).
|
|
60
|
+
|
|
61
|
+
**Example:** sparse primary fields stay sparse, and an included record is read
|
|
62
|
+
from its lookup container (`items[0].lookups.pet.name`); a contract that
|
|
63
|
+
expects the relationship id or an unselected field never gets it.
|
|
64
|
+
|
|
65
|
+
## Applying each check
|
|
66
|
+
|
|
67
|
+
### Every row
|
|
68
|
+
|
|
69
|
+
- An unpaged JSON:API query returns the first 20 rows, and a page above the
|
|
70
|
+
resource's `queryMaxLimit` (100 unless it sets one) is cut to that size,
|
|
71
|
+
both without an error; CRUD `queryDocuments()` refuses such a `limit`. A
|
|
72
|
+
read its callers treat as complete uses `queryAllJsonRestCollectionRows()`
|
|
73
|
+
or the repository's `queryEveryDocument()`, because the missing rows
|
|
74
|
+
otherwise vanish from every picker and delivery built on it
|
|
75
|
+
([Every row](typed-features.md#every-row)).
|
|
76
|
+
- A lookup by a unique key matches at most one row, so it may read `rows[0]`
|
|
77
|
+
of a plain query.
|
|
78
|
+
|
|
79
|
+
### Query counts and batches
|
|
80
|
+
|
|
81
|
+
- Count a path's queries with `countQueries()` from
|
|
82
|
+
`@jskit-ai/database-runtime/server/testDatabases` at a few rows and at a
|
|
83
|
+
realistic number; the count should follow tables and pages, not rows
|
|
84
|
+
([Query counts at realistic
|
|
85
|
+
sizes](typed-features.md#query-counts-at-realistic-sizes)).
|
|
86
|
+
- A JSON:API read adds a few lookup and visibility queries per page and per
|
|
87
|
+
relationship field. That follows pages, so it is expected.
|
|
88
|
+
- `getDocumentById()`, `queryDocuments()` or a service `get` inside a loop is
|
|
89
|
+
the usual per-row read; batch it with an id-list `searchSchema` filter or
|
|
90
|
+
`include`, grouped with `Map.groupBy()` ([Lists read related rows in
|
|
91
|
+
batches](typed-features.md#lists-read-related-rows-in-batches)).
|
|
92
|
+
- A `rowPolicy` adds one correlated predicate to the query it is given, so
|
|
93
|
+
its cost follows the rows read, not the subject's history. It runs on every
|
|
94
|
+
single-record read, including a write's default `returning: "full"` read
|
|
95
|
+
back, so a write that discards its result passes `returning: "minimal"` and
|
|
96
|
+
a batch of creates uses `createDocuments()`, in the owner's transaction
|
|
97
|
+
([Bounded access
|
|
98
|
+
checks](typed-features.md#bounded-access-checks)).
|
|
99
|
+
|
|
100
|
+
### Tests
|
|
101
|
+
|
|
102
|
+
- `jskit test` runs test files in parallel within the machine's test budget
|
|
103
|
+
(`V64_TEST_CONCURRENCY`, else half the CPUs), and Playwright's `workers` and
|
|
104
|
+
Vitest's `maxWorkers` come from `testConcurrency()`. `jskit check` reports a
|
|
105
|
+
script or config that runs files one at a time; a file that must run alone
|
|
106
|
+
says why on its first line, `// jskit-test: alone - <reason>` ([Test files
|
|
107
|
+
run in parallel](typed-features.md#test-files-run-in-parallel)).
|
|
108
|
+
- Tests use `TEST_DB_NAME` and `BROWSER_TEST_DB_NAME`, both different from
|
|
109
|
+
`DB_NAME`, because tests write and delete rows and would destroy the
|
|
110
|
+
developer's data. A skip for want of a test database is a failure.
|
|
111
|
+
- Test databases restore a stored snapshot checked by a digest of the
|
|
112
|
+
migration and seed sources, and the harness reports each preparation phase's
|
|
113
|
+
duration, so slow preparation shows ([Test databases are prepared
|
|
114
|
+
once](typed-features.md#test-databases-are-prepared-once),
|
|
115
|
+
[integration test
|
|
116
|
+
databases](/guide/app-setup/database-layer#integration-test-databases)).
|
|
117
|
+
|
|
118
|
+
### Inputs and access
|
|
119
|
+
|
|
120
|
+
- An action input declared `mode: "patch"` makes every field optional. Use it
|
|
121
|
+
only for an action that updates part of a record, and send that action
|
|
122
|
+
nothing to see what it does, because a missing field is then never refused.
|
|
123
|
+
- A route that repetition can abuse declares `rateLimit`, which the kernel
|
|
124
|
+
refuses with 429 and `kernel.http.rateLimited`; auth's limits come from
|
|
125
|
+
`config.auth.rateLimits` ([Sign-in
|
|
126
|
+
protection](/guide/app-setup/authentication#sign-in-protection)). Each
|
|
127
|
+
limit needs a test expecting the 429, or a dropped one goes unseen.
|
|
128
|
+
- Who acts comes from `resolveActor(context)` and the workspace from the
|
|
129
|
+
context's resolvers ([One reader per
|
|
130
|
+
fact](typed-features.md#one-reader-per-fact)); send another
|
|
131
|
+
workspace's id in the body and see the context win.
|
|
132
|
+
|
|
133
|
+
### Refactors
|
|
134
|
+
|
|
135
|
+
Before changing a JSKIT feature, list where its behaviour lives, with the test
|
|
136
|
+
that covers each item, and walk the list again after: routes, actions and
|
|
137
|
+
their input schemas, row policies, CRUD fields, lookups and hooks, placements
|
|
138
|
+
and navigation meta, messages and their codes, events, jobs and migrations.
|
|
139
|
+
These are the places a consolidation drops behaviour without a failing build.
|
|
140
|
+
|
|
141
|
+
### Changes others depend on
|
|
142
|
+
|
|
143
|
+
- After updating JSKIT packages, read [Upgrade
|
|
144
|
+
JSKIT](/guide/app-setup/upgrading-jskit) and each package changelog's
|
|
145
|
+
"Upgrading" notes, then boot, sign in and run the browser tests before
|
|
146
|
+
anything else, because a changed default shows only at run time.
|
|
147
|
+
|
|
148
|
+
### Screens
|
|
149
|
+
|
|
150
|
+
- A long list renders what is visible, with pages or `v-virtual-scroll`,
|
|
151
|
+
because every row rendered costs DOM nodes and main-thread time.
|
|
152
|
+
- Command feedback goes through the shell's snackbar path: `ShellErrorHost`
|
|
153
|
+
keeps it clear of the FAB and the actions it reports on, and a full-screen
|
|
154
|
+
dialog puts its confirm action in the top bar, where a snackbar never covers
|
|
155
|
+
it ([Material 3](material-3.md)).
|
|
156
|
+
- Up is the shell's, from `meta.jskit.parent`; the navigation rules forbid
|
|
157
|
+
`router.back()` and hand-made back controls, so Up lands inside the app
|
|
158
|
+
even on a page opened from a link.
|
|
159
|
+
|
|
160
|
+
### Production settings
|
|
161
|
+
|
|
162
|
+
- `NODE_ENV=production` is JSKIT's only production switch. Without it a
|
|
163
|
+
deployed server runs as development: no first-account setup code, and
|
|
164
|
+
development-only settings accepted.
|
|
165
|
+
- On an empty production database, local auth asks for the first account's
|
|
166
|
+
setup code, so whoever reaches a new deployment first cannot own it ([The
|
|
167
|
+
first account in
|
|
168
|
+
production](/guide/app-setup/authentication#the-first-account-in-production-local-auth)).
|
|
169
|
+
Give any registration of your own the same protection.
|
|
170
|
+
- `config.securityHeaders` sends the security headers, with the content
|
|
171
|
+
security policy reported, not enforced, by default; read them on a
|
|
172
|
+
production build ([Security
|
|
173
|
+
headers](/guide/app-setup/initial-scaffolding#security-headers)).
|
|
174
|
+
- Email confirmation needs `auth.local.confirmation-sender` in production, or
|
|
175
|
+
the server refuses to start while anyone may register ([Email
|
|
176
|
+
confirmation](/guide/app-setup/authentication#email-confirmation-local-auth)).
|
|
177
|
+
- Changing the assistant's instructions needs `assistant.settings.update` or
|
|
178
|
+
the surface's own permission ([Who may change the
|
|
179
|
+
instructions](/guide/app-extras/assistant#who-may-change-the-instructions)).
|
|
180
|
+
Its tools run as the typing user, through the `automation` channel, so an
|
|
181
|
+
action kept off that channel is never a tool.
|
|
@@ -193,6 +193,10 @@ and params to `details.fieldErrorCodes`, so an untranslated app shows exactly
|
|
|
193
193
|
the English it showed before. The failed check's own params (for example
|
|
194
194
|
`limit`) are sent too, and the coded entry's `params` win over them. JSKIT's
|
|
195
195
|
own schemas use this form, which is why their field messages translate.
|
|
196
|
+
With json-rest-schema 1.0.18 or later, which checks them, an array field's
|
|
197
|
+
`minItems` and `maxItems` failures send `kernel.validation.field.minItems` and
|
|
198
|
+
`kernel.validation.field.maxItems` with `{ min | max, actual }`, and its
|
|
199
|
+
`messages.minItems` and `messages.maxItems` override them.
|
|
196
200
|
|
|
197
201
|
## Placement labels
|
|
198
202
|
|