@cosmicdrift/kumiko-renderer 0.386.0 → 0.387.0
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/LICENSE +21 -57
- package/dist/app/action-form-body.d.ts +2 -2
- package/dist/app/action-form-body.js +2 -2
- package/dist/app/action-form-shim.d.ts +8 -8
- package/dist/app/action-form-shim.js +20 -22
- package/dist/app/app-features-context.js +4 -4
- package/dist/app/column-renderers.d.ts +7 -9
- package/dist/app/column-renderers.js +15 -18
- package/dist/app/config-edit-body.js +1 -1
- package/dist/app/config-edit-shim.d.ts +7 -8
- package/dist/app/config-edit-shim.js +18 -20
- package/dist/app/custom-screens.d.ts +3 -3
- package/dist/app/custom-screens.js +8 -8
- package/dist/app/dashboard-body.d.ts +2 -2
- package/dist/app/dashboard-body.js +2 -2
- package/dist/app/entity-edit-prefill.js +9 -9
- package/dist/app/entity-edit-screen.js +4 -4
- package/dist/app/entity-list-screen.js +3 -3
- package/dist/app/extension-form-submit.d.ts +1 -1
- package/dist/app/extension-form-submit.js +14 -15
- package/dist/app/extension-sections.d.ts +24 -25
- package/dist/app/extension-sections.js +10 -10
- package/dist/app/feature-schema.js +11 -11
- package/dist/app/form-schema.js +1 -1
- package/dist/app/header-actions-bar.js +1 -1
- package/dist/app/kumiko-screen.js +8 -10
- package/dist/app/layout-fields.js +1 -1
- package/dist/app/list-facets.js +3 -3
- package/dist/app/nav.d.ts +10 -10
- package/dist/app/nav.js +13 -13
- package/dist/app/projection-detail-body.js +4 -4
- package/dist/app/projection-detail-shim.d.ts +6 -5
- package/dist/app/projection-detail-shim.js +23 -22
- package/dist/app/projection-list-body.js +10 -10
- package/dist/app/projection-list-shim.d.ts +5 -5
- package/dist/app/projection-list-shim.js +17 -18
- package/dist/app/qn.js +10 -12
- package/dist/app/qualify-screen-id.js +1 -1
- package/dist/app/screen-access.js +2 -2
- package/dist/app/screen-shared.js +1 -1
- package/dist/app/secret-mint-body.js +4 -4
- package/dist/app/write-failed-error.js +8 -7
- package/dist/components/embedded-list-field.js +4 -4
- package/dist/components/grid-cell-for-field.d.ts +1 -1
- package/dist/components/reference-create-dialog.js +3 -3
- package/dist/components/related-list-section.d.ts +1 -1
- package/dist/components/related-list-section.js +1 -1
- package/dist/components/render-edit-logic.js +1 -1
- package/dist/components/render-edit-types.d.ts +6 -6
- package/dist/components/render-edit.js +63 -65
- package/dist/components/render-field.d.ts +7 -7
- package/dist/components/render-field.js +57 -59
- package/dist/components/render-list.d.ts +42 -43
- package/dist/components/render-list.js +63 -67
- package/dist/components/use-wizard-form-draft.js +10 -10
- package/dist/context/dispatcher-context.js +5 -5
- package/dist/context/user-roles-context.js +2 -2
- package/dist/headless/apex/index.d.ts +1 -2
- package/dist/headless/apex/index.js +5 -6
- package/dist/headless/form/form-controller.js +6 -6
- package/dist/headless/form/zod-bridge.js +2 -2
- package/dist/headless/format/money.js +1 -1
- package/dist/headless/index.js +2 -2
- package/dist/headless/view-model/edit.js +2 -2
- package/dist/headless/view-model/list.js +3 -4
- package/dist/headless/view-model/types.d.ts +3 -3
- package/dist/hooks/reference-limits.js +11 -12
- package/dist/hooks/use-list-url-state.d.ts +13 -13
- package/dist/hooks/use-list-url-state.js +21 -22
- package/dist/hooks/use-query.js +3 -3
- package/dist/hooks/use-reference-lookup.js +16 -17
- package/dist/hooks/use-store.js +18 -22
- package/dist/hooks/use-stream-handler.js +4 -2
- package/dist/i18n-defaults.js +2 -8
- package/dist/i18n.d.ts +10 -10
- package/dist/i18n.js +25 -25
- package/dist/index.js +5 -4
- package/dist/live/dispatcher-live.js +2 -2
- package/dist/primitives.d.ts +225 -221
- package/dist/primitives.js +1 -1
- package/dist/sse/live-events.d.ts +5 -5
- package/dist/sse/live-events.js +17 -17
- package/dist/tokens.d.ts +8 -8
- package/dist/tokens.js +16 -17
- package/dist/web/app/browser-locale.d.ts +9 -9
- package/dist/web/app/browser-locale.js +19 -19
- package/dist/web/app/client-plugin.d.ts +44 -52
- package/dist/web/app/client-plugin.js +4 -5
- package/dist/web/app/create-app.d.ts +28 -31
- package/dist/web/app/create-app.js +21 -22
- package/dist/web/app/document-lang-sync.js +1 -1
- package/dist/web/app/draft-storage.js +1 -1
- package/dist/web/app/nav-providers-context.d.ts +3 -3
- package/dist/web/app/nav-providers-context.js +3 -3
- package/dist/web/app/nav.d.ts +18 -17
- package/dist/web/app/nav.js +66 -64
- package/dist/web/app/rich-content-editor.js +1 -1
- package/dist/web/components/config-cascade.js +17 -18
- package/dist/web/components/config-source-badge.js +4 -4
- package/dist/web/layout/app-layout.d.ts +9 -9
- package/dist/web/layout/app-layout.js +2 -2
- package/dist/web/layout/avatar.d.ts +4 -3
- package/dist/web/layout/avatar.js +15 -17
- package/dist/web/layout/default-app-shell.d.ts +22 -23
- package/dist/web/layout/editor-panel.js +3 -3
- package/dist/web/layout/nav-tree.js +86 -84
- package/dist/web/layout/profile-menu.d.ts +1 -1
- package/dist/web/layout/sidebar-brand.d.ts +7 -7
- package/dist/web/layout/sidebar-user.d.ts +1 -1
- package/dist/web/layout/sidebar-user.js +4 -4
- package/dist/web/layout/sidebar.d.ts +8 -8
- package/dist/web/layout/sidebar.js +7 -7
- package/dist/web/layout/target-resolver-stub.d.ts +5 -5
- package/dist/web/layout/target-resolver-stub.js +20 -20
- package/dist/web/layout/target-url.d.ts +7 -7
- package/dist/web/layout/target-url.js +22 -22
- package/dist/web/layout/theme-toggle.js +4 -5
- package/dist/web/layout/workspace-shell.d.ts +21 -21
- package/dist/web/layout/workspace-shell.js +29 -30
- package/dist/web/lib/cn.d.ts +4 -4
- package/dist/web/lib/cn.js +4 -4
- package/dist/web/primitives/action-menu.d.ts +8 -8
- package/dist/web/primitives/action-menu.js +14 -13
- package/dist/web/primitives/calendar-popover.d.ts +1 -1
- package/dist/web/primitives/calendar-popover.js +10 -10
- package/dist/web/primitives/card-styles.js +1 -1
- package/dist/web/primitives/card.js +2 -2
- package/dist/web/primitives/combobox.d.ts +12 -12
- package/dist/web/primitives/combobox.js +34 -35
- package/dist/web/primitives/data-table-cell.js +2 -2
- package/dist/web/primitives/data-table.js +2 -3
- package/dist/web/primitives/date-field.js +2 -2
- package/dist/web/primitives/date-input.js +4 -4
- package/dist/web/primitives/default-form.js +2 -2
- package/dist/web/primitives/dropdown-menu.js +14 -15
- package/dist/web/primitives/embedded-list-input.js +3 -3
- package/dist/web/primitives/facet-filter.js +1 -1
- package/dist/web/primitives/field.js +9 -8
- package/dist/web/primitives/form.d.ts +1 -1
- package/dist/web/primitives/form.js +6 -6
- package/dist/web/primitives/input.js +2 -2
- package/dist/web/primitives/layout-elements.js +1 -1
- package/dist/web/primitives/layout.js +2 -2
- package/dist/web/primitives/located-timestamp-input.js +4 -4
- package/dist/web/primitives/money-input.js +13 -17
- package/dist/web/primitives/pager.js +1 -1
- package/dist/web/primitives/row-actions.js +3 -4
- package/dist/web/primitives/secret-reveal.js +1 -1
- package/dist/web/primitives/timestamp-input.d.ts +9 -9
- package/dist/web/primitives/timestamp-input.js +21 -21
- package/dist/web/primitives/toast.js +12 -13
- package/dist/web/sse/live-events.d.ts +6 -6
- package/dist/web/sse/live-events.js +3 -3
- package/dist/web/tokens.d.ts +11 -12
- package/dist/web/tokens.js +35 -37
- package/dist/web/version/update-checker.js +14 -13
- package/dist/web/widgets/ai-text-field.js +1 -1
- package/dist/web/widgets/charts.d.ts +10 -10
- package/dist/web/widgets/charts.js +8 -8
- package/dist/web/widgets/collapsible-section.d.ts +3 -3
- package/dist/web/widgets/collapsible-section.js +6 -6
- package/dist/web/widgets/detail-list.d.ts +1 -3
- package/dist/web/widgets/detail-list.js +1 -3
- package/dist/web/widgets/feed-list.d.ts +2 -2
- package/dist/web/widgets/feed-list.js +2 -2
- package/dist/web/widgets/form-fields.d.ts +14 -14
- package/dist/web/widgets/form-fields.js +14 -13
- package/dist/web/widgets/index.js +4 -4
- package/dist/web/widgets/infinity-list.js +3 -3
- package/dist/web/widgets/mode-switch.d.ts +2 -2
- package/dist/web/widgets/mode-switch.js +2 -2
- package/dist/web/widgets/progress-list.d.ts +1 -2
- package/dist/web/widgets/progress-list.js +1 -2
- package/dist/web/widgets/query-table.d.ts +6 -6
- package/dist/web/widgets/result-panel.d.ts +16 -16
- package/dist/web/widgets/result-panel.js +10 -10
- package/dist/web/widgets/section-card.d.ts +3 -3
- package/dist/web/widgets/section-card.js +3 -3
- package/dist/web/widgets/stat.d.ts +4 -4
- package/dist/web/widgets/stat.js +6 -6
- package/dist/web/widgets/states.d.ts +4 -4
- package/dist/web/widgets/states.js +4 -4
- package/dist/web/widgets/use-draft.d.ts +7 -7
- package/dist/web/widgets/use-draft.js +7 -7
- package/package.json +6 -6
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
// Shim
|
|
1
|
+
// Shim for the ProjectionList renderer (analogous to action-form-shim.ts / config-edit-shim.ts).
|
|
2
2
|
//
|
|
3
|
-
// RenderList + computeListViewModel
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// hierüber aufgelöst (der Body nimmt `screen.query` direkt).
|
|
3
|
+
// RenderList + computeListViewModel require an `entity: EntityDefinition` +
|
|
4
|
+
// `screen: EntityListScreenDefinition` pair, but only use `entity.fields`
|
|
5
|
+
// (column type/label) and the screen's list fields (columns/rowActions/…). A
|
|
6
|
+
// projectionList screen is query-driven and has NO entity, so these two helpers
|
|
7
|
+
// reshape the input ad hoc to reuse the existing list machinery. The query is
|
|
8
|
+
// NOT resolved here (the body reads `screen.query` directly).
|
|
10
9
|
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// derivedFields)
|
|
14
|
-
//
|
|
15
|
-
// query-native ListView
|
|
10
|
+
// This preserves the same debt reservation as the other shims: if the list
|
|
11
|
+
// machinery later accesses additional EntityDefinition fields (transitions,
|
|
12
|
+
// idType, derivedFields), or a boot validator cross-references the
|
|
13
|
+
// schema.entities map, these type lies will fail silently. At that point, a
|
|
14
|
+
// query-native ListView component is needed.
|
|
16
15
|
import { normalizeListColumn } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
17
16
|
const PROJECTION_PSEUDO_ENTITY = "__projection__";
|
|
18
17
|
// Satisfies the text-field PII stance of the entity field type; these synthesized
|
|
@@ -20,7 +19,7 @@ const PROJECTION_PSEUDO_ENTITY = "__projection__";
|
|
|
20
19
|
export const SYNTHESIZED_FIELD_PII_REASON = "synthesized display field, not stored entity data";
|
|
21
20
|
/** Minimal EntityDefinition from the column list: every field is a text
|
|
22
21
|
* field. `sortable` applies to all columns — buildAppSchema derives it from
|
|
23
|
-
* the query's Zod schema (`screen.sortable
|
|
22
|
+
* the query's Zod schema (`screen.sortable`); the query itself has
|
|
24
23
|
* no per-field server-sort guarantee, so a column opts out with
|
|
25
24
|
* `sortable: false` when the handler cannot order by it.
|
|
26
25
|
* computeListViewModel only reads `fields[<col>].type` — text is enough,
|
|
@@ -37,10 +36,10 @@ export function synthesizeProjectionEntity(columns, sortable) {
|
|
|
37
36
|
}
|
|
38
37
|
return { fields };
|
|
39
38
|
}
|
|
40
|
-
/**
|
|
41
|
-
* RenderList
|
|
42
|
-
*
|
|
43
|
-
*
|
|
39
|
+
/** Converts a ProjectionListScreenDefinition to the EntityListScreen shape
|
|
40
|
+
* expected by RenderList. `type` = "entityList" plus a pseudo-entity satisfy
|
|
41
|
+
* the type constraint; RenderList does not branch on `type` and reads `entity`
|
|
42
|
+
* only for error messages. The list fields are passed through unchanged. */
|
|
44
43
|
export function synthesizeProjectionScreen(screen) {
|
|
45
44
|
return {
|
|
46
45
|
id: screen.id,
|
package/dist/app/qn.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
// Qualified-
|
|
2
|
-
// Feature-Prefix auf jede Screen/Nav/Workspace-id ein:
|
|
1
|
+
// Qualified-name helper. At boot, Kumiko's Registry adds the feature prefix to every Screen/Nav/Workspace ID:
|
|
3
2
|
//
|
|
4
3
|
// r.screen({ id: "task-list", ... })
|
|
5
4
|
// → registry-stored.id === "tasks:screen:task-list"
|
|
6
|
-
// → schema.screens (
|
|
5
|
+
// → schema.screens (sent to the browser) has id === "tasks:screen:task-list"
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// ("/tasks:screen:task-list" +
|
|
7
|
+
// The renderer uses short-form IDs: formatPath writes them to the URL unchanged,
|
|
8
|
+
// and parsePath reads them back unchanged. When converting from the schema (QN form)
|
|
9
|
+
// to nav.navigate (short form), the prefix must be removed; otherwise the URL becomes
|
|
10
|
+
// doubly qualified
|
|
11
|
+
// ("/tasks:screen:task-list" + re-lookup → "tasks:screen:tasks:screen:
|
|
13
12
|
// task-list" → 404).
|
|
14
13
|
//
|
|
15
|
-
// `lastSegment`
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// ids in eigenen Stellen weiter passt).
|
|
14
|
+
// `lastSegment` is the inverse of qualifyScreenId/Nav/Workspace: it takes the final
|
|
15
|
+
// ":"-separated part. Strings without ":" are returned unchanged so app-author code
|
|
16
|
+
// using short-form IDs continues to work.
|
|
19
17
|
export function lastSegment(qn) {
|
|
20
18
|
const idx = qn.lastIndexOf(":");
|
|
21
19
|
return idx < 0 ? qn : qn.slice(idx + 1);
|
|
@@ -7,7 +7,7 @@ export function qualifyScreenId(featureName, screenId) {
|
|
|
7
7
|
// Inverse of qualifyScreenId. A short id ("task-list") has no feature
|
|
8
8
|
// segment and returns undefined — callers need that to tell "this redirect
|
|
9
9
|
// names a feature" apart from "this redirect is feature-less, resolve by
|
|
10
|
-
// short id alone"
|
|
10
|
+
// short id alone".
|
|
11
11
|
export function featureNameFromQualifiedScreenId(id) {
|
|
12
12
|
const parts = id.split(":");
|
|
13
13
|
return parts.length === 3 && parts[1] === "screen" ? parts[0] : undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isUiAccessGranted } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
2
|
import { findDetailForScreen } from "./nav.js";
|
|
3
3
|
import { lastSegment } from "./qn.js";
|
|
4
|
-
// Shared UI-visibility predicate for the screen-render path
|
|
4
|
+
// Shared UI-visibility predicate for the screen-render path — nav
|
|
5
5
|
// filtering via filterByAccess in workspace-shell.tsx hid role-gated
|
|
6
6
|
// screens from the menu, but a direct URL/screenQn hit reached
|
|
7
7
|
// KumikoScreen unchecked). Public name kept as an alias of the shared
|
|
@@ -9,7 +9,7 @@ import { lastSegment } from "./qn.js";
|
|
|
9
9
|
export { isUiAccessGranted as screenAccessAllows };
|
|
10
10
|
// A navigate target (metric click) declares no access rule of its own — the
|
|
11
11
|
// destination screen already does, so the jump is offered exactly when the
|
|
12
|
-
// user may open where it lands
|
|
12
|
+
// user may open where it lands. No second copy of the rule to
|
|
13
13
|
// drift from the screen's own.
|
|
14
14
|
export function navigateTargetAllows(navigate, appFeatures, userRoles) {
|
|
15
15
|
const { screen, entity } = navigate;
|
|
@@ -166,7 +166,7 @@ export function entityQueryCommand(featureName, entity, verb) {
|
|
|
166
166
|
// search/sort/sortDirection/limit + offset/totalCount for pager mode OR
|
|
167
167
|
// cursor for infinite scroll. Shared by EntityListBody and
|
|
168
168
|
// ProjectionListBody so the two branches can't drift on this shape
|
|
169
|
-
//
|
|
169
|
+
// — entity-only additions (screen.filter, faceted filters) are
|
|
170
170
|
// layered on top by the caller instead of living in here.
|
|
171
171
|
export function buildListQueryPayload(state) {
|
|
172
172
|
const payload = { limit: state.limit };
|
|
@@ -40,10 +40,10 @@ function isBlank(value) {
|
|
|
40
40
|
// Mint form → one-time reveal → optional confirm → done. The revealed values
|
|
41
41
|
// live ONLY in this component's `revealed` state — never in the URL, a query
|
|
42
42
|
// cache, or nav — the write-handler's success payload is the only place the
|
|
43
|
-
// secret ever exists
|
|
43
|
+
// secret ever exists. onSubmit copies exclusively the fields
|
|
44
44
|
// declared in `screen.reveal.fields` out of that payload (a whitelist, never
|
|
45
45
|
// the payload as a whole) so an unrelated field (e.g. an internal "id") can
|
|
46
|
-
// never leak into the reveal. `screen.confirm` (
|
|
46
|
+
// never leak into the reveal. `screen.confirm` (e.g. TOTP enroll:
|
|
47
47
|
// scan the code, then enter one) works the same way for its own carried
|
|
48
48
|
// mint-payload fields — those live only in `carriedRef`, never in React state
|
|
49
49
|
// that gets rendered, never in the confirm form's own values.
|
|
@@ -63,7 +63,7 @@ export function SecretMintBody({ schema, screen, translate }) {
|
|
|
63
63
|
urlPrefillFields: screen.urlPrefillFields,
|
|
64
64
|
renderableFields: layoutFieldNames(synthScreen),
|
|
65
65
|
// A mint form has no entity either, so its money fields name their own
|
|
66
|
-
// currency source
|
|
66
|
+
// currency source.
|
|
67
67
|
...(mintCurrencyOverrides !== undefined && {
|
|
68
68
|
moneyCurrencyOverrides: mintCurrencyOverrides,
|
|
69
69
|
}),
|
|
@@ -188,7 +188,7 @@ export function SecretMintBody({ schema, screen, translate }) {
|
|
|
188
188
|
// submit state) across phases.
|
|
189
189
|
if (confirm !== undefined && confirmEntity !== undefined && confirmScreen !== undefined) {
|
|
190
190
|
// Hold until a tenant-declared currency lands, else the form would seed (and
|
|
191
|
-
// on a fast click submit) the fallback currency
|
|
191
|
+
// on a fast click submit) the fallback currency.
|
|
192
192
|
if (confirmCurrencyLoading) {
|
|
193
193
|
return _jsx(QueryLoadingBanner, {});
|
|
194
194
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// dispatcher.write
|
|
2
|
-
// { isSuccess: false, error }. Action
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// UI
|
|
1
|
+
// dispatcher.write does NOT throw on server errors; it returns
|
|
2
|
+
// { isSuccess: false, error }. Action wiring that discards the result
|
|
3
|
+
// makes failures invisible ("click does nothing" in production).
|
|
4
|
+
// This class carries the structured DispatcherError to a layer that can
|
|
5
|
+
// display it in the UI, such as a toast with docsUrl.
|
|
6
6
|
export class WriteFailedError extends Error {
|
|
7
7
|
dispatcherError;
|
|
8
8
|
constructor(error, message) {
|
|
@@ -11,8 +11,9 @@ export class WriteFailedError extends Error {
|
|
|
11
11
|
this.dispatcherError = error;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
// i18nKey
|
|
15
|
-
//
|
|
14
|
+
// i18nKey takes precedence when the bundle knows it (translate returns
|
|
15
|
+
// the key unchanged when it does not, per the renderer convention),
|
|
16
|
+
// followed by message and then code.
|
|
16
17
|
export function dispatcherErrorText(error, translate) {
|
|
17
18
|
const translated = translate(error.i18nKey, error.i18nParams);
|
|
18
19
|
if (translated !== error.i18nKey)
|
|
@@ -71,11 +71,11 @@ function coerceCellValue(column, text, currency) {
|
|
|
71
71
|
// (renderCellControl's MoneyInput, which scales by the same
|
|
72
72
|
// currencyDecimals) — a hardcoded ×100 here diverged for zero-/three-
|
|
73
73
|
// decimal currencies (JPY, BHD, ...), landing a pasted value 100x off
|
|
74
|
-
// from the same value typed by hand
|
|
74
|
+
// from the same value typed by hand.
|
|
75
75
|
// parseLocaleAwareDecimal handles both "1.234,56" (de) and
|
|
76
76
|
// "1,234.56" (en-US) thousands/decimal conventions — a naive
|
|
77
|
-
// `replace(",", ".")` mangled
|
|
78
|
-
// separators into NaN
|
|
77
|
+
// `replace(",", ".")` mangled German-locale pastes with thousands
|
|
78
|
+
// separators into NaN.
|
|
79
79
|
if (text.trim() === "")
|
|
80
80
|
return undefined;
|
|
81
81
|
const n = parseLocaleAwareDecimal(text);
|
|
@@ -259,7 +259,7 @@ function EmbeddedListFieldInner({ field, id, onChange, allIssues, featureName, }
|
|
|
259
259
|
const coerced = coerceCellValue(column, text, field.embeddedListCurrency ?? "EUR");
|
|
260
260
|
// Also covers an unparseable money paste (e.g. mangled thousands
|
|
261
261
|
// separators) — the cell must stay unchanged instead of silently
|
|
262
|
-
// clearing to undefined
|
|
262
|
+
// clearing to undefined.
|
|
263
263
|
const isUnmatchedOrUnparseable = (column.type === "select" || column.type === "reference" || column.type === "money") &&
|
|
264
264
|
coerced === undefined &&
|
|
265
265
|
text.trim() !== "";
|
|
@@ -7,7 +7,7 @@ export type GridCellForFieldProps = {
|
|
|
7
7
|
readonly issues: readonly FieldIssue[] | undefined;
|
|
8
8
|
readonly onChange: (value: unknown) => void;
|
|
9
9
|
readonly GridCell: ReturnType<typeof usePrimitives>["GridCell"];
|
|
10
|
-
/**
|
|
10
|
+
/** Passed through so Reference fields can build the correct
|
|
11
11
|
* lookup query QN (`<feature>:query:<refEntity>:list`). */
|
|
12
12
|
readonly featureName: string;
|
|
13
13
|
readonly labelAppendix?: ReactNode;
|
|
@@ -8,7 +8,7 @@ import { usePrimitives } from "../primitives.js";
|
|
|
8
8
|
import { RenderEdit } from "./render-edit.js";
|
|
9
9
|
// Hosts a target entity's create-form inside a bare Modal so a reference
|
|
10
10
|
// field can create a missing record without leaving the current form
|
|
11
|
-
//
|
|
11
|
+
// — same create wiring as EntityEditCreateBody
|
|
12
12
|
// (kumiko-screen.tsx), but reports the new id back via a callback instead
|
|
13
13
|
// of navigating to the entity's list screen.
|
|
14
14
|
function entityWriteCommand(featureName, entity) {
|
|
@@ -17,7 +17,7 @@ function entityWriteCommand(featureName, entity) {
|
|
|
17
17
|
// The create handler's success payload is `{ kind: "save", id, ... }`
|
|
18
18
|
// (see event-store-executor-write.ts) but RenderEdit's onSubmit only
|
|
19
19
|
// types it as `unknown` — narrow defensively instead of casting through it.
|
|
20
|
-
// `field` is author-declared (ActionFormRedirect.idFrom
|
|
20
|
+
// `field` is author-declared (ActionFormRedirect.idFrom), never
|
|
21
21
|
// user input; the own-property check keeps a prototype key like
|
|
22
22
|
// "constructor" from resolving to anything.
|
|
23
23
|
export function extractIdField(data, field) {
|
|
@@ -36,7 +36,7 @@ export function ReferenceCreateDialog({ open, onClose, onCreated, featureName, s
|
|
|
36
36
|
const t = useTranslation();
|
|
37
37
|
const entityDefaultCurrency = entity.defaultCurrency ?? "EUR";
|
|
38
38
|
const tenantCurrencyFieldNames = useMemo(() => (open ? tenantCurrencyMoneyFieldNames(entity.fields) : []), [open, entity.fields]);
|
|
39
|
-
// Same tenant-currency resolution as the entityEdit create screen
|
|
39
|
+
// Same tenant-currency resolution as the entityEdit create screen,
|
|
40
40
|
// so a `currency: { kind: "tenant" }` field seeds identically via this dialog.
|
|
41
41
|
const { overrides: moneyCurrencyOverrides, loading: currencyLoading } = useMoneyCurrencyOverrides(entity.fields, tenantCurrencyFieldNames, entityDefaultCurrency);
|
|
42
42
|
const initial = useMemo(() => buildInitialValues(entity.fields, entityDefaultCurrency, moneyCurrencyOverrides), [entity.fields, entityDefaultCurrency, moneyCurrencyOverrides]);
|
|
@@ -13,7 +13,7 @@ export declare function RelatedListSection({ section, parentId, record, featureN
|
|
|
13
13
|
readonly hideTitle?: boolean;
|
|
14
14
|
/** Under a fixed-height screen the tab panel chain stretches so the count footer sits at the bottom. */
|
|
15
15
|
readonly grow?: boolean;
|
|
16
|
-
/** Opens a drawer-kind rowAction
|
|
16
|
+
/** Opens a drawer-kind rowAction. Supplied by the parent
|
|
17
17
|
* (ProjectionDetailBody), which owns schema + the actual Drawer render —
|
|
18
18
|
* this component only ever invokes the callback. */
|
|
19
19
|
readonly onOpenDrawer?: (action: RowActionDrawer, initialValues: Readonly<Record<string, unknown>> | undefined) => void;
|
|
@@ -338,7 +338,7 @@ export function RelatedListSection({ section, parentId, record, featureName, tra
|
|
|
338
338
|
// A truncated fetch means `sortedRows` is a sort of a partial set, not of
|
|
339
339
|
// the full related-row set — the client-side sort above (or even plain
|
|
340
340
|
// unsorted display) would silently claim "these are the top N" when they
|
|
341
|
-
// are really just "the first N in the server's own order"
|
|
341
|
+
// are really just "the first N in the server's own order".
|
|
342
342
|
// `nextCursor` is exactly how the paged envelope marks that: non-null means
|
|
343
343
|
// more rows exist server-side beyond what was fetched.
|
|
344
344
|
// A handler that omits `nextCursor` (or reports a `total` the fetched rows
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Hides the Save button when no field is editable and no extension section
|
|
2
2
|
// contributes to the composed form submit. Extensions that persist via their
|
|
3
|
-
// own dispatcher writes must not opt in
|
|
3
|
+
// own dispatcher writes must not opt in.
|
|
4
4
|
// Explicit-positive per kind (653/1), not `s.kind !== "fields"` — a future
|
|
5
5
|
// third EditSectionViewModel member would otherwise default to "editable"
|
|
6
6
|
// without anyone deciding that on purpose.
|
|
@@ -56,7 +56,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
56
56
|
/** Fires when the form gains or loses unsaved input (field changes or a
|
|
57
57
|
* dirty extension section). Lets a host such as a drawer guard closing. */
|
|
58
58
|
readonly onDirtyChange?: (dirty: boolean) => void;
|
|
59
|
-
/** Copy-link action
|
|
59
|
+
/** Copy-link action — only set in update mode (create mode
|
|
60
60
|
* has no entity id yet, hence no permalink). The callback is already fully
|
|
61
61
|
* bound (URL building + clipboard happen outside, in
|
|
62
62
|
* `@cosmicdrift/kumiko-renderer/web`'s RoutedScreen — this platform-neutral
|
|
@@ -74,7 +74,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
74
74
|
* header menu (drawer, card form, shell without a header slot) they fall
|
|
75
75
|
* back to buttons next to `actions`. */
|
|
76
76
|
readonly menuActions?: readonly RenderEditAction[];
|
|
77
|
-
/** Opens a relatedList section row's drawer-kind action
|
|
77
|
+
/** Opens a relatedList section row's drawer-kind action.
|
|
78
78
|
* RenderEdit has no `schema` to resolve the target actionForm itself —
|
|
79
79
|
* the caller (ProjectionDetailBody, which does have schema) supplies the
|
|
80
80
|
* opener and owns the actual Drawer state/rendering. Only projectionDetail
|
|
@@ -117,7 +117,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
117
117
|
/** Edit-mode "changed" markers also for screens without an entity id
|
|
118
118
|
* (configEdit loads its values from a query, not a record). */
|
|
119
119
|
readonly markChangedFields?: boolean;
|
|
120
|
-
/** Controlled mode
|
|
120
|
+
/** Controlled mode: fires on every values-snapshot change
|
|
121
121
|
* (typing, `patch(...)` from outside) with the current values. `changes`
|
|
122
122
|
* is the delta against the initial values — same semantics as
|
|
123
123
|
* `payloadMode: "changes"` — so a caller never overwrites unseen fields.
|
|
@@ -134,7 +134,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
134
134
|
* happens, so a caller patching dependent fields from inside `onChange`
|
|
135
135
|
* never has to guard against `controls` being undefined. */
|
|
136
136
|
readonly onChange?: (state: RenderEditChangeState<TValues>) => void;
|
|
137
|
-
/** Controlled mode
|
|
137
|
+
/** Controlled mode: called once after mount, hands the
|
|
138
138
|
* caller `patch`/`validate`/`getValues` bound to this RenderEdit
|
|
139
139
|
* instance — addressable from outside without a remount. `patch` merges
|
|
140
140
|
* only the given keys (existing `controller.setValues` semantics),
|
|
@@ -153,7 +153,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
153
153
|
* validation scope (the underlying `useForm` controller is mount-lived);
|
|
154
154
|
* rendering and `controls.validate()` do stay reactive to later changes. */
|
|
155
155
|
readonly fields?: readonly string[];
|
|
156
|
-
/** Locked state
|
|
156
|
+
/** Locked state: every rendered field and the submit button
|
|
157
157
|
* go visibly inactive, no write possible. For cases where input becomes
|
|
158
158
|
* moot — e.g. Solon's editor pointing at an existing record instead of
|
|
159
159
|
* creating a new one. Extension sections are out of scope: RenderEdit has
|
|
@@ -177,7 +177,7 @@ export type RenderEditProps<TValues extends FormValues, TCtx = unknown> = {
|
|
|
177
177
|
/** "form" (default) — every field renders as its Input widget, disabled
|
|
178
178
|
* when `field.readOnly`, unchanged behavior. "text" renders a
|
|
179
179
|
* `field.readOnly` field as plain text instead of a disabled Input
|
|
180
|
-
* (ProjectionDetailBody's read view
|
|
180
|
+
* (ProjectionDetailBody's read view) — editable fields are
|
|
181
181
|
* unaffected either way, so this only changes forms that already have
|
|
182
182
|
* readOnly fields. */
|
|
183
183
|
readonly valueDisplay?: "form" | "text";
|