@cosmicdrift/kumiko-renderer 0.385.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 +28 -5
- 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 +43 -44
- 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
package/LICENSE
CHANGED
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
controlling, or under common control with the Licensor ("Affiliates"), or
|
|
23
|
-
contractors acting on their behalf. The Licensor remains free to use the
|
|
24
|
-
Licensed Work for any purpose, including for the operation of kumiko.rocks.
|
|
25
|
-
|
|
26
|
-
Change Date: 2030-05-05
|
|
27
|
-
Change License: Apache License, Version 2.0
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Terms
|
|
31
|
-
|
|
32
|
-
The Licensor hereby grants you the right to copy, modify, create derivative works,
|
|
33
|
-
redistribute, and make non-production use of the Licensed Work. The Licensor may
|
|
34
|
-
make an Additional Use Grant, above, permitting limited production use.
|
|
35
|
-
|
|
36
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
-
available distribution of the Licensed Work under this License, whichever comes
|
|
38
|
-
first, this License will convert to the Change License.
|
|
39
|
-
|
|
40
|
-
This Business Source License governs use of the Licensed Work in all cases, except
|
|
41
|
-
as to any use that is explicitly granted in the Additional Use Grant above or
|
|
42
|
-
under the Change License after the Change Date.
|
|
43
|
-
|
|
44
|
-
If your use of the Licensed Work does not comply with the requirements of this
|
|
45
|
-
License, you must cease use of the Licensed Work immediately.
|
|
46
|
-
|
|
47
|
-
All copies of the Licensed Work, and all derivative works thereof, must include
|
|
48
|
-
this License.
|
|
49
|
-
|
|
50
|
-
This License does not grant you any right, title, or interest in any trademark,
|
|
51
|
-
logo, or branding of the Licensor, except as required to comply with this License.
|
|
52
|
-
|
|
53
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
54
|
-
“AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
55
|
-
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
56
|
-
TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
|
|
57
|
-
ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marc Frost
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -28,11 +28,11 @@ export declare function ActionFormBody({ schema, screen, translate, entityId, in
|
|
|
28
28
|
readonly translate?: Translate;
|
|
29
29
|
/** Record id from the route path; the source of the `load` query's id. */
|
|
30
30
|
readonly entityId?: string;
|
|
31
|
-
/** Row-drawer usage (RowAction kind:"drawer"
|
|
31
|
+
/** Row-drawer usage (RowAction kind:"drawer"): prefill extracted
|
|
32
32
|
* from the clicked row, applied on top of searchParams through the same
|
|
33
33
|
* renderableFields/sensitive gates (see mergeSearchParamsIntoInitial). */
|
|
34
34
|
readonly initialOverrides?: Readonly<Record<string, unknown>>;
|
|
35
|
-
/** Drawer-hosted usage (toolbarAction kind:"drawer"
|
|
35
|
+
/** Drawer-hosted usage (toolbarAction kind:"drawer"): called
|
|
36
36
|
* instead of the redirect-based navigation on successful submit, so the
|
|
37
37
|
* host closes the drawer + refetches its list regardless of whether
|
|
38
38
|
* `screen.redirect` is set — a full-page redirect would navigate away
|
|
@@ -112,7 +112,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
|
|
|
112
112
|
// A drawer-hosted form is not a navigation target, so it never takes a handoff.
|
|
113
113
|
const handoffValues = onSuccess === undefined ? pendingHandoff : undefined;
|
|
114
114
|
// This screen has no entity, so a money field here declares its own currency
|
|
115
|
-
// source (
|
|
115
|
+
// source (boot-enforced) — without one the form would seed a bare
|
|
116
116
|
// `0` the handler's schema rejects. When a tenant-declared field's config
|
|
117
117
|
// query errors or holds no value there is no entity default to use, and
|
|
118
118
|
// submitting a guessed currency would mis-book the amount — block instead.
|
|
@@ -251,7 +251,7 @@ export function ActionFormBody({ schema, screen, translate, entityId, initialOve
|
|
|
251
251
|
return () => navigateToReturnOr(nav, returnTarget, () => nav.navigate({ screenId: lastSegment(target) }));
|
|
252
252
|
}, [nav, screen.redirect, screen.cancelTarget, onCancelOverride, returnTarget]);
|
|
253
253
|
// Rendering the form before a tenant-declared currency lands would show the
|
|
254
|
-
// fallback and, on a fast click, submit it
|
|
254
|
+
// fallback and, on a fast click, submit it — hold instead.
|
|
255
255
|
if (currencyLoading) {
|
|
256
256
|
return _jsx(QueryLoadingBanner, {});
|
|
257
257
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { ActionFormScreenDefinition, EntityDefinition, EntityEditScreenDefinition, FieldDefinition, SecretMintConfirmStep, SecretMintScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
-
/**
|
|
3
|
-
* ActionForm
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
/** Builds a minimal EntityDefinition from the inline fields of an
|
|
3
|
+
* ActionForm or SecretMint screen. RenderEdit and computeEditViewModel
|
|
4
|
+
* iterate over entity.fields at render time; all other EntityDefinition
|
|
5
|
+
* fields remain undefined. */
|
|
6
6
|
export declare function synthesizeActionFormEntity(fields: Readonly<Record<string, FieldDefinition>>): EntityDefinition;
|
|
7
7
|
/** Fields the form may seed and submit. An excluded field the layout does not show
|
|
8
8
|
* would otherwise reach the payload through its `default`, and the handler rejects it. */
|
|
9
9
|
export declare function actionFormSubmittableFields(screen: ActionFormScreenDefinition): Readonly<Record<string, FieldDefinition>>;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
* "entityEdit"
|
|
13
|
-
*
|
|
10
|
+
/** Converts an ActionFormScreenDefinition or SecretMintScreenDefinition to
|
|
11
|
+
* the EntityEditScreen shape expected by RenderEdit. `type` is set to
|
|
12
|
+
* "entityEdit" to satisfy the type constraint, and `entity` is pinned to
|
|
13
|
+
* the pseudo-name because RenderEdit does not read that field. */
|
|
14
14
|
export declare function synthesizeActionFormScreen(screen: ActionFormScreenDefinition | SecretMintScreenDefinition): EntityEditScreenDefinition;
|
|
15
15
|
/** Separate id (`${screen.id}:confirm`) keeps this confirm-form screen from
|
|
16
16
|
* colliding with the mint-form screen's draft key. */
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
// Shim
|
|
1
|
+
// Shim for ActionForm rendering.
|
|
2
2
|
//
|
|
3
|
-
// RenderEdit
|
|
4
|
-
// `screen: EntityEditScreenDefinition`
|
|
5
|
-
// `entity.fields`
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// reused werden kann ohne den Stack zu duplizieren.
|
|
3
|
+
// RenderEdit currently requires an `entity: EntityDefinition` and a
|
|
4
|
+
// `screen: EntityEditScreenDefinition` pair, but internally uses only
|
|
5
|
+
// `entity.fields` and `screen.layout`. ActionForm screens have neither an
|
|
6
|
+
// entity reference nor `type: "entityEdit"`; these helpers reshape the input
|
|
7
|
+
// so RenderEdit can be reused without duplicating the rendering stack.
|
|
9
8
|
//
|
|
10
|
-
//
|
|
11
|
-
// defaultCurrency
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// entity-Lookup), also ist der Server-Pfad davon nicht betroffen.
|
|
9
|
+
// This workaround becomes invalid if RenderEdit starts reading
|
|
10
|
+
// entity.transitions, idType, defaultCurrency, or softDelete, or if a future
|
|
11
|
+
// boot validator cross-references the schema.entities map. At that point,
|
|
12
|
+
// RenderActionForm should accept `fields` directly. The boot validator already
|
|
13
|
+
// handles actionForm independently without an entity lookup, so the server path
|
|
14
|
+
// is unaffected.
|
|
17
15
|
import { ACTION_FORM_PSEUDO_ENTITY, isFieldsEditSection, normalizeEditField, sectionFieldSpecs, } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
18
|
-
/**
|
|
19
|
-
* ActionForm
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
/** Builds a minimal EntityDefinition from the inline fields of an
|
|
17
|
+
* ActionForm or SecretMint screen. RenderEdit and computeEditViewModel
|
|
18
|
+
* iterate over entity.fields at render time; all other EntityDefinition
|
|
19
|
+
* fields remain undefined. */
|
|
22
20
|
export function synthesizeActionFormEntity(fields) {
|
|
23
21
|
return { fields };
|
|
24
22
|
}
|
|
@@ -68,10 +66,10 @@ export function actionFormSubmittableFields(screen) {
|
|
|
68
66
|
: []));
|
|
69
67
|
return Object.fromEntries(Object.entries(screen.fields).filter(([name]) => inLayout.has(name) || !excluded.includes(name)));
|
|
70
68
|
}
|
|
71
|
-
/**
|
|
72
|
-
*
|
|
73
|
-
* "entityEdit"
|
|
74
|
-
*
|
|
69
|
+
/** Converts an ActionFormScreenDefinition or SecretMintScreenDefinition to
|
|
70
|
+
* the EntityEditScreen shape expected by RenderEdit. `type` is set to
|
|
71
|
+
* "entityEdit" to satisfy the type constraint, and `entity` is pinned to
|
|
72
|
+
* the pseudo-name because RenderEdit does not read that field. */
|
|
75
73
|
export function synthesizeActionFormScreen(screen) {
|
|
76
74
|
return {
|
|
77
75
|
id: screen.id,
|
|
@@ -2,10 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
// Cross-feature schema access for components that need to resolve a
|
|
3
3
|
// screen owned by a DIFFERENT feature than the one they're rendering
|
|
4
4
|
// under — e.g. a reference field opening the target entity's create
|
|
5
|
-
// screen
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// screen. `createKumikoApp` provides the full `app.features` list;
|
|
6
|
+
// components elsewhere in the render tree default to an empty list (no
|
|
7
|
+
// cross-feature schema known, e.g. outside `createKumikoApp` or in
|
|
8
|
+
// isolated tests).
|
|
9
9
|
import { createContext, useContext } from "react";
|
|
10
10
|
const AppFeaturesContext = createContext([]);
|
|
11
11
|
export function AppFeaturesProvider({ features, children }) {
|
|
@@ -17,14 +17,12 @@ export type ColumnRenderersProviderProps = {
|
|
|
17
17
|
readonly value: ColumnRenderersMap;
|
|
18
18
|
};
|
|
19
19
|
export declare function ColumnRenderersProvider({ children, value, }: ColumnRenderersProviderProps): ReactNode;
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Default-Type-Renderer zurück.
|
|
20
|
+
/** Looks up the component for a renderer key. Returns undefined when `name` is
|
|
21
|
+
* empty/undefined (the caller has no __component renderer), or when no provider
|
|
22
|
+
* is mounted or the key is absent from the map. The caller (DataTable.renderCell)
|
|
23
|
+
* then logs a warning and falls back to the default type renderer.
|
|
25
24
|
*
|
|
26
|
-
* `name`
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* Caller einen Stub-Key wie `""` reichen muss. */
|
|
25
|
+
* `name` is optional so callers can invoke the hook unconditionally—Rules of
|
|
26
|
+
* Hooks prohibit a function branch that skips the hook. This keeps the call to
|
|
27
|
+
* a single line without requiring the caller to provide a stub key such as `""`. */
|
|
30
28
|
export declare function useColumnRenderer(name?: string): ColumnRendererComponent | undefined;
|
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// Column-Renderer-Map: client-side
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// Column-Renderer-Map: client-side lookup for ListColumn columns that specify a
|
|
3
|
+
// PlatformComponent renderer (`{ react: { __component: "Name" } }`) in the schema
|
|
4
|
+
// instead of a string function. createKumikoApp in renderer/web collects all
|
|
5
|
+
// clientFeatures.columnRenderers and mounts the provider; the DataTable cell
|
|
6
|
+
// renderer looks up the component through `useColumnRenderer(name)`.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// client-seitig.
|
|
8
|
+
// Like CustomScreensProvider, the renderer web bootstrap mounts both providers
|
|
9
|
+
// at the same location. Schemas remain serializable: the component is referenced
|
|
10
|
+
// only by string key, while the map exists solely on the client.
|
|
12
11
|
import { createContext, useContext } from "react";
|
|
13
12
|
const ColumnRenderersContext = createContext(undefined);
|
|
14
13
|
export function ColumnRenderersProvider({ children, value, }) {
|
|
15
14
|
return (_jsx(ColumnRenderersContext.Provider, { value: value, children: children }));
|
|
16
15
|
}
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Default-Type-Renderer zurück.
|
|
16
|
+
/** Looks up the component for a renderer key. Returns undefined when `name` is
|
|
17
|
+
* empty/undefined (the caller has no __component renderer), or when no provider
|
|
18
|
+
* is mounted or the key is absent from the map. The caller (DataTable.renderCell)
|
|
19
|
+
* then logs a warning and falls back to the default type renderer.
|
|
22
20
|
*
|
|
23
|
-
* `name`
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* Caller einen Stub-Key wie `""` reichen muss. */
|
|
21
|
+
* `name` is optional so callers can invoke the hook unconditionally—Rules of
|
|
22
|
+
* Hooks prohibit a function branch that skips the hook. This keeps the call to
|
|
23
|
+
* a single line without requiring the caller to provide a stub key such as `""`. */
|
|
27
24
|
export function useColumnRenderer(name) {
|
|
28
25
|
const map = useContext(ColumnRenderersContext);
|
|
29
26
|
if (name === undefined || name === "")
|
|
@@ -15,7 +15,7 @@ import { buildInitialValues } from "./entity-edit-prefill.js";
|
|
|
15
15
|
import { layoutEditFields } from "./layout-fields.js";
|
|
16
16
|
import { QueryErrorBanner, QueryLoadingBanner } from "./query-state-banners.js";
|
|
17
17
|
// A money-typed config-edit field renders through RenderField's entityEdit
|
|
18
|
-
// `{amount, currency}` payload shape (render-field.tsx
|
|
18
|
+
// `{amount, currency}` payload shape (render-field.tsx), but
|
|
19
19
|
// `ConfigKeyType` (write-helpers.ts validateType) only ever knows
|
|
20
20
|
// number/boolean/text/select — a config value is always a bare scalar.
|
|
21
21
|
// Unwrap back to the amount before it hits config:write:set.
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { ConfigEditScreenDefinition, EntityDefinition, EntityEditScreenDefinition } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Felder bleiben undefined. */
|
|
3
|
+
/** Builds a minimal EntityDefinition from the ConfigEdit screen's inline
|
|
4
|
+
* fields. RenderEdit + computeEditViewModel iterate over entity.fields
|
|
5
|
+
* at render time; all other EntityDefinition fields remain undefined. */
|
|
7
6
|
export declare function synthesizeConfigEditEntity(fields: ConfigEditScreenDefinition["fields"]): EntityDefinition;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
/** Converts a ConfigEditScreenDefinition to the EntityEditScreen shape
|
|
8
|
+
* expected by RenderEdit. `type` is set to "entityEdit" to satisfy the
|
|
9
|
+
* type constraint; `entity` is pinned to the pseudo-name — RenderEdit
|
|
10
|
+
* does not read this field. */
|
|
12
11
|
export declare function synthesizeConfigEditScreen(screen: ConfigEditScreenDefinition): EntityEditScreenDefinition;
|
|
13
12
|
/** Client-side range check for number keys with declared bounds, so an
|
|
14
13
|
* out-of-range value surfaces on its field instead of as the server's
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
// Shim
|
|
1
|
+
// Shim for the ConfigEdit renderer (analogous to action-form-shim.ts).
|
|
2
2
|
//
|
|
3
|
-
// RenderEdit
|
|
4
|
-
// `screen: EntityEditScreenDefinition`
|
|
5
|
-
// `entity.fields`
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// ad-hoc um, damit RenderEdit reused werden kann.
|
|
3
|
+
// RenderEdit requires an `entity: EntityDefinition` +
|
|
4
|
+
// `screen: EntityEditScreenDefinition` pair, but internally uses only
|
|
5
|
+
// `entity.fields` and `screen.layout` for rendering. ConfigEdit screens
|
|
6
|
+
// have neither an entity reference nor `type: "entityEdit"` — these two
|
|
7
|
+
// helpers reshape the data input ad hoc so RenderEdit can be reused.
|
|
9
8
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
9
|
+
// The same debt reservation as in action-form-shim applies: if RenderEdit
|
|
10
|
+
// starts accessing entity.transitions / idType / softDelete, or a future
|
|
11
|
+
// boot validator cross-references the schema.entities map, these type lies
|
|
12
|
+
// will fail silently. At that point, a real RenderConfigEdit component
|
|
13
|
+
// that takes fields directly is needed.
|
|
15
14
|
import * as z from "zod";
|
|
16
15
|
import { I18N_KEY_PARAM } from "../headless/index.js";
|
|
17
16
|
const CONFIG_EDIT_PSEUDO_ENTITY = "__config-edit__";
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Felder bleiben undefined. */
|
|
17
|
+
/** Builds a minimal EntityDefinition from the ConfigEdit screen's inline
|
|
18
|
+
* fields. RenderEdit + computeEditViewModel iterate over entity.fields
|
|
19
|
+
* at render time; all other EntityDefinition fields remain undefined. */
|
|
22
20
|
export function synthesizeConfigEditEntity(fields) {
|
|
23
21
|
return { fields };
|
|
24
22
|
}
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
/** Converts a ConfigEditScreenDefinition to the EntityEditScreen shape
|
|
24
|
+
* expected by RenderEdit. `type` is set to "entityEdit" to satisfy the
|
|
25
|
+
* type constraint; `entity` is pinned to the pseudo-name — RenderEdit
|
|
26
|
+
* does not read this field. */
|
|
29
27
|
export function synthesizeConfigEditScreen(screen) {
|
|
30
28
|
return {
|
|
31
29
|
id: screen.id,
|
|
@@ -5,7 +5,7 @@ export type CustomScreensProviderProps = {
|
|
|
5
5
|
readonly value: CustomScreensMap;
|
|
6
6
|
};
|
|
7
7
|
export declare function CustomScreensProvider({ children, value }: CustomScreensProviderProps): ReactNode;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
/** Looks up the component for a custom screen. Returns undefined
|
|
9
|
+
* when neither a provider is mounted nor screenId is in the map—the
|
|
10
|
+
* caller (KumikoScreen) then displays its placeholder banner. */
|
|
11
11
|
export declare function useCustomScreenComponent(screenId: string): ComponentType | undefined;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// Custom-
|
|
3
|
-
// `custom`. KumikoScreen
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// Custom-screen component map: client-side lookup for screens of type
|
|
3
|
+
// `custom`. KumikoScreen looks up `screen.id` (or qn) here and renders
|
|
4
|
+
// the matching component. createKumikoApp in renderer/web collects all
|
|
5
|
+
// clientFeatures.components and mounts the provider; tests that check
|
|
6
|
+
// individual custom screens mount the provider directly.
|
|
7
7
|
import { createContext, useContext } from "react";
|
|
8
8
|
const CustomScreensContext = createContext(undefined);
|
|
9
9
|
export function CustomScreensProvider({ children, value }) {
|
|
10
10
|
return _jsx(CustomScreensContext.Provider, { value: value, children: children });
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
/** Looks up the component for a custom screen. Returns undefined
|
|
13
|
+
* when neither a provider is mounted nor screenId is in the map—the
|
|
14
|
+
* caller (KumikoScreen) then displays its placeholder banner. */
|
|
15
15
|
export function useCustomScreenComponent(screenId) {
|
|
16
16
|
const map = useContext(CustomScreensContext);
|
|
17
17
|
if (map === undefined)
|
|
@@ -11,6 +11,6 @@ export type DashboardBodyProviderProps = {
|
|
|
11
11
|
readonly value: ComponentType<DashboardBodyProps>;
|
|
12
12
|
};
|
|
13
13
|
export declare function DashboardBodyProvider({ children, value }: DashboardBodyProviderProps): ReactNode;
|
|
14
|
-
/** Undefined
|
|
15
|
-
*
|
|
14
|
+
/** Undefined when no platform package has registered a dashboard body;
|
|
15
|
+
* KumikoScreen then displays its placeholder banner. */
|
|
16
16
|
export declare function useDashboardBody(): ComponentType<DashboardBodyProps> | undefined;
|
|
@@ -4,8 +4,8 @@ const DashboardBodyContext = createContext(undefined);
|
|
|
4
4
|
export function DashboardBodyProvider({ children, value }) {
|
|
5
5
|
return _jsx(DashboardBodyContext.Provider, { value: value, children: children });
|
|
6
6
|
}
|
|
7
|
-
/** Undefined
|
|
8
|
-
*
|
|
7
|
+
/** Undefined when no platform package has registered a dashboard body;
|
|
8
|
+
* KumikoScreen then displays its placeholder banner. */
|
|
9
9
|
export function useDashboardBody() {
|
|
10
10
|
return useContext(DashboardBodyContext);
|
|
11
11
|
}
|
|
@@ -5,8 +5,8 @@ import { useMemo } from "react";
|
|
|
5
5
|
import { rendererWarn } from "../dev-console.js";
|
|
6
6
|
import { useQuery } from "../hooks/use-query.js";
|
|
7
7
|
// `defaultCurrency` is entityEdit-only — it enables the `{amount, currency}`
|
|
8
|
-
// write shape
|
|
9
|
-
// `moneyCurrencyOverrides`
|
|
8
|
+
// write shape; config-edit's plain-number contract needs bare `0`.
|
|
9
|
+
// `moneyCurrencyOverrides` replaces `defaultCurrency` per field name
|
|
10
10
|
// — used for a `money` field that declares `currency: { kind: "tenant" }`, so
|
|
11
11
|
// its empty initial value carries the tenant's own currency instead of the
|
|
12
12
|
// entity-wide default.
|
|
@@ -51,7 +51,7 @@ export function buildInitialValues(fields, defaultCurrency, moneyCurrencyOverrid
|
|
|
51
51
|
return out;
|
|
52
52
|
}
|
|
53
53
|
// A `money` field opts a currently-empty value into the tenant-settings
|
|
54
|
-
// bundle's per-tenant currency
|
|
54
|
+
// bundle's per-tenant currency via `currency: { kind: "tenant" }`
|
|
55
55
|
// on its FieldDefinition. Read structurally — renderer only depends on the
|
|
56
56
|
// client-safe FieldDefinition subset, not the concrete MoneyFieldDef/
|
|
57
57
|
// MoneyCurrencySource types, same idiom as the other field-shape narrowings
|
|
@@ -68,7 +68,7 @@ export function tenantCurrencyMoneyFieldNames(fields) {
|
|
|
68
68
|
}
|
|
69
69
|
// Resolves what a tenant-declared money field's currency should be, from the
|
|
70
70
|
// same `config:query:values` query ConfigEditBody already uses. Never falls
|
|
71
|
-
// back to "EUR" while the query is genuinely still in flight
|
|
71
|
+
// back to "EUR" while the query is genuinely still in flight — a
|
|
72
72
|
// screen with no tenant-declared money field, or a query that errored or
|
|
73
73
|
// returned no value for the key, resolves immediately instead of blocking.
|
|
74
74
|
function resolveTenantCurrency(fieldNames, query, fallback) {
|
|
@@ -88,8 +88,8 @@ function resolveTenantCurrency(fieldNames, query, fallback) {
|
|
|
88
88
|
? { status: "unresolved" }
|
|
89
89
|
: { status: "ready", currency: fallback };
|
|
90
90
|
}
|
|
91
|
-
// A money field naming a fixed ISO code (`currency: { kind: "literal", code }
|
|
92
|
-
//
|
|
91
|
+
// A money field naming a fixed ISO code (`currency: { kind: "literal", code }`)
|
|
92
|
+
// resolves with no query at all. Read structurally, same idiom as
|
|
93
93
|
// tenantCurrencyMoneyFieldNames above.
|
|
94
94
|
export function literalCurrencyOverrides(fields) {
|
|
95
95
|
const out = {};
|
|
@@ -105,9 +105,9 @@ export function literalCurrencyOverrides(fields) {
|
|
|
105
105
|
return out;
|
|
106
106
|
}
|
|
107
107
|
// Per-field currency for the money fields that declare their own source: a
|
|
108
|
-
// literal code resolves synchronously
|
|
108
|
+
// literal code resolves synchronously, a `{ kind: "tenant" }` field
|
|
109
109
|
// needs the tenant-settings config query and makes the caller hold the form
|
|
110
|
-
// until it lands
|
|
110
|
+
// until it lands — seeding the fallback meanwhile would render, and
|
|
111
111
|
// on a fast click submit, the wrong currency. Callers pass the tenant field
|
|
112
112
|
// names themselves because an edit form only needs the fetch for fields the
|
|
113
113
|
// record has no stored value for.
|
|
@@ -164,7 +164,7 @@ function warnPrefillParam(message) {
|
|
|
164
164
|
rendererWarn(`[kumiko] ${message}`);
|
|
165
165
|
}
|
|
166
166
|
// An actionForm has no entity and thus no defaultCurrency, so a bare-number
|
|
167
|
-
// prefill would stay a number the handler's zod schema rejects
|
|
167
|
+
// prefill would stay a number the handler's zod schema rejects.
|
|
168
168
|
function coerceMoneyValue(raw, fieldName, defaultCurrency) {
|
|
169
169
|
if (raw === null || raw === undefined)
|
|
170
170
|
return undefined;
|
|
@@ -52,7 +52,7 @@ function EntityEditCreateBody({ schema, screen, entity, translate, onSaved, }) {
|
|
|
52
52
|
// returnTo would fight that.
|
|
53
53
|
const returnTarget = screen.singleton === true ? undefined : returnTargetParam;
|
|
54
54
|
const entityDefaultCurrency = entity.defaultCurrency ?? "EUR";
|
|
55
|
-
// A money field declaring `currency: { kind: "tenant" }`
|
|
55
|
+
// A money field declaring `currency: { kind: "tenant" }` resolves
|
|
56
56
|
// its empty-value currency from the tenant-settings config key instead of
|
|
57
57
|
// entityDefaultCurrency — `enabled` keeps the query a no-op for entities
|
|
58
58
|
// without any such field.
|
|
@@ -117,7 +117,7 @@ function EntityEditCreateBody({ schema, screen, entity, translate, onSaved, }) {
|
|
|
117
117
|
}
|
|
118
118
|
}, [nav, screen.redirect, schema, appFeatures, navigateToList, onSaved, returnTarget]);
|
|
119
119
|
// Never seed a tenant-declared money field with entityDefaultCurrency while
|
|
120
|
-
// its real tenant currency is still in flight
|
|
120
|
+
// its real tenant currency is still in flight — wait instead.
|
|
121
121
|
if (currencyLoading) {
|
|
122
122
|
return _jsx(QueryLoadingBanner, {});
|
|
123
123
|
}
|
|
@@ -172,7 +172,7 @@ function EntityEditUpdateForm({ schema, screen, entity, entityId, record, onRelo
|
|
|
172
172
|
// error and the user reloads.
|
|
173
173
|
const recordVersion = versionOf(record);
|
|
174
174
|
const entityDefaultCurrency = entity.defaultCurrency ?? "EUR";
|
|
175
|
-
// A money field declaring `currency: { kind: "tenant" }`
|
|
175
|
+
// A money field declaring `currency: { kind: "tenant" }` resolves
|
|
176
176
|
// its empty-value currency from the tenant-settings config key instead of
|
|
177
177
|
// entityDefaultCurrency — `enabled` keeps the query a no-op for entities
|
|
178
178
|
// without any such field. A record's own stored value (below) always wins
|
|
@@ -333,7 +333,7 @@ function EntityEditUpdateForm({ schema, screen, entity, entityId, record, onRelo
|
|
|
333
333
|
return undefined;
|
|
334
334
|
}, [dispatcher, deleteCommand, entityId, navigateToList, onDeleted, returnTarget, nav]);
|
|
335
335
|
// Never seed a tenant-declared money field with entityDefaultCurrency while
|
|
336
|
-
// its real tenant currency is still in flight
|
|
336
|
+
// its real tenant currency is still in flight — wait instead. A
|
|
337
337
|
// stored (non-empty) value is unaffected — it never reaches this branch's
|
|
338
338
|
// fallback because `initial` above already prefers `record[name]`.
|
|
339
339
|
if (currencyLoading) {
|
|
@@ -298,7 +298,7 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
298
298
|
// drift apart.
|
|
299
299
|
const runNavigate = useCallback((action, row) => {
|
|
300
300
|
if (action.entity !== undefined) {
|
|
301
|
-
// Entity targets
|
|
301
|
+
// Entity targets only resolve in the NavApi implementation
|
|
302
302
|
// against ALL features (resolveTarget in renderer/web/nav.tsx); this
|
|
303
303
|
// package only knows `schema` (the one calling feature) and cannot look up
|
|
304
304
|
// detailFor across features itself.
|
|
@@ -499,8 +499,8 @@ function EntityListBody({ schema, screen, entity, translate, onRowClick, }) {
|
|
|
499
499
|
// the entity has searchable fields (dead toolbar slot otherwise — the
|
|
500
500
|
// server search index has nothing to filter). Gated on
|
|
501
501
|
// schema.searchAdapterMissing !== true regardless of source (explicit or
|
|
502
|
-
// auto) — a search bar the server can't serve would 422 at request-time
|
|
503
|
-
//
|
|
502
|
+
// auto) — a search bar the server can't serve would 422 at request-time;
|
|
503
|
+
// matches the boot-time check in api/server.ts.
|
|
504
504
|
const searchable = schema.searchAdapterMissing !== true &&
|
|
505
505
|
(screen.searchable ??
|
|
506
506
|
Object.values(entity.fields).some((f) => "searchable" in f && f.searchable === true));
|
|
@@ -3,7 +3,7 @@ export type ExtensionSubmitContext = {
|
|
|
3
3
|
};
|
|
4
4
|
export type ExtensionSubmitResult = {
|
|
5
5
|
readonly isSuccess: boolean;
|
|
6
|
-
/** i18n
|
|
6
|
+
/** i18n key for the error message that the form displays as a banner. */
|
|
7
7
|
readonly errorKey?: string;
|
|
8
8
|
};
|
|
9
9
|
export type ExtensionFormSubmitHandler = (ctx: ExtensionSubmitContext) => Promise<ExtensionSubmitResult>;
|