@cosmicdrift/kumiko-renderer 0.327.0 → 0.328.1
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/dist/app/action-form-shim.d.ts +14 -0
- package/{src/app/action-form-shim.ts → dist/app/action-form-shim.js} +26 -44
- package/dist/app/app-features-context.d.ts +8 -0
- package/dist/app/app-features-context.js +16 -0
- package/dist/app/column-renderers.d.ts +30 -0
- package/dist/app/column-renderers.js +34 -0
- package/dist/app/config-edit-shim.d.ts +11 -0
- package/{src/app/config-edit-shim.ts → dist/app/config-edit-shim.js} +12 -25
- package/dist/app/content-editors.d.ts +38 -0
- package/dist/app/content-editors.js +26 -0
- package/dist/app/content-preview.d.ts +11 -0
- package/dist/app/content-preview.js +30 -0
- package/dist/app/custom-screens.d.ts +11 -0
- package/dist/app/custom-screens.js +20 -0
- package/dist/app/dashboard-body.d.ts +16 -0
- package/dist/app/dashboard-body.js +11 -0
- package/dist/app/extension-form-submit.d.ts +32 -0
- package/dist/app/extension-form-submit.js +73 -0
- package/dist/app/extension-sections.d.ts +72 -0
- package/dist/app/extension-sections.js +34 -0
- package/dist/app/feature-schema.d.ts +4 -0
- package/{src/app/feature-schema.ts → dist/app/feature-schema.js} +12 -22
- package/dist/app/form-schema.d.ts +4 -0
- package/dist/app/form-schema.js +85 -0
- package/dist/app/kumiko-screen.d.ts +43 -0
- package/dist/app/kumiko-screen.js +2206 -0
- package/dist/app/layout-fields.d.ts +3 -0
- package/dist/app/layout-fields.js +20 -0
- package/dist/app/list-facets.d.ts +48 -0
- package/dist/app/list-facets.js +185 -0
- package/dist/app/nav.d.ts +61 -0
- package/dist/app/nav.js +139 -0
- package/dist/app/projection-detail-shim.d.ts +8 -0
- package/dist/app/projection-detail-shim.js +71 -0
- package/dist/app/projection-list-shim.d.ts +13 -0
- package/{src/app/projection-list-shim.ts → dist/app/projection-list-shim.js} +26 -38
- package/dist/app/qn.d.ts +7 -0
- package/{src/app/qn.ts → dist/app/qn.js} +9 -11
- package/dist/app/qualify-screen-id.d.ts +2 -0
- package/{src/app/qualify-screen-id.ts → dist/app/qualify-screen-id.js} +5 -6
- package/dist/app/reference-facet-bridge.d.ts +10 -0
- package/dist/app/reference-facet-bridge.js +22 -0
- package/dist/app/return-to.d.ts +31 -0
- package/dist/app/return-to.js +188 -0
- package/dist/app/row-actions.d.ts +77 -0
- package/dist/app/row-actions.js +416 -0
- package/dist/app/screen-access.d.ts +8 -0
- package/dist/app/screen-access.js +48 -0
- package/dist/app/secret-mint-body.d.ts +10 -0
- package/dist/app/secret-mint-body.js +140 -0
- package/dist/app/secrets-edit-body.d.ts +8 -0
- package/dist/app/secrets-edit-body.js +76 -0
- package/dist/app/use-embedded-screen.d.ts +6 -0
- package/dist/app/use-embedded-screen.js +19 -0
- package/dist/app/variable-chips.d.ts +7 -0
- package/dist/app/variable-chips.js +16 -0
- package/dist/app/write-failed-error.d.ts +6 -0
- package/dist/app/write-failed-error.js +21 -0
- package/dist/components/embedded-list-field.d.ts +10 -0
- package/dist/components/embedded-list-field.js +259 -0
- package/dist/components/grid-cell-for-field.d.ts +25 -0
- package/dist/components/grid-cell-for-field.js +31 -0
- package/dist/components/multi-select-checkboxes.d.ts +14 -0
- package/dist/components/multi-select-checkboxes.js +36 -0
- package/dist/components/reference-create-dialog.d.ts +13 -0
- package/dist/components/reference-create-dialog.js +46 -0
- package/dist/components/related-list-section.d.ts +25 -0
- package/dist/components/related-list-section.js +273 -0
- package/dist/components/render-edit-action-button.d.ts +22 -0
- package/dist/components/render-edit-action-button.js +43 -0
- package/dist/components/render-edit-logic.d.ts +6 -0
- package/dist/components/render-edit-logic.js +63 -0
- package/dist/components/render-edit-types.d.ts +209 -0
- package/dist/components/render-edit-types.js +1 -0
- package/dist/components/render-edit.d.ts +6 -0
- package/dist/components/render-edit.js +1169 -0
- package/dist/components/render-field.d.ts +38 -0
- package/dist/components/render-field.js +544 -0
- package/dist/components/render-list.d.ts +117 -0
- package/dist/components/render-list.js +232 -0
- package/dist/components/write-form-section.d.ts +17 -0
- package/dist/components/write-form-section.js +104 -0
- package/dist/context/dispatcher-context.d.ts +10 -0
- package/{src/context/dispatcher-context.tsx → dist/context/dispatcher-context.js} +16 -29
- package/dist/context/draft-storage-context.d.ts +12 -0
- package/dist/context/draft-storage-context.js +18 -0
- package/dist/context/user-roles-context.d.ts +7 -0
- package/{src/context/user-roles-context.tsx → dist/context/user-roles-context.js} +7 -15
- package/dist/format-when.d.ts +1 -0
- package/{src/format-when.ts → dist/format-when.js} +7 -7
- package/dist/hooks/reference-limits.d.ts +3 -0
- package/{src/hooks/reference-limits.ts → dist/hooks/reference-limits.js} +0 -1
- package/dist/hooks/use-ai-text.d.ts +52 -0
- package/dist/hooks/use-ai-text.js +90 -0
- package/dist/hooks/use-disclosure.d.ts +7 -0
- package/dist/hooks/use-disclosure.js +8 -0
- package/dist/hooks/use-form.d.ts +7 -0
- package/dist/hooks/use-form.js +36 -0
- package/dist/hooks/use-list-url-state.d.ts +43 -0
- package/dist/hooks/use-list-url-state.js +131 -0
- package/dist/hooks/use-mutation.d.ts +9 -0
- package/dist/hooks/use-mutation.js +37 -0
- package/dist/hooks/use-query.d.ts +14 -0
- package/dist/hooks/use-query.js +118 -0
- package/dist/hooks/use-reference-lookup.d.ts +14 -0
- package/dist/hooks/use-reference-lookup.js +63 -0
- package/dist/hooks/use-store.d.ts +3 -0
- package/dist/hooks/use-store.js +38 -0
- package/dist/hooks/use-stream-handler.d.ts +14 -0
- package/dist/hooks/use-stream-handler.js +93 -0
- package/dist/i18n-defaults.d.ts +2 -0
- package/dist/i18n-defaults.js +201 -0
- package/dist/i18n.d.ts +64 -0
- package/dist/i18n.js +166 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +55 -0
- package/dist/inside-drawer.d.ts +2 -0
- package/dist/inside-drawer.js +9 -0
- package/dist/page-header-slot.d.ts +2 -0
- package/dist/page-header-slot.js +9 -0
- package/dist/primitives.d.ts +1351 -0
- package/dist/primitives.js +73 -0
- package/dist/screen-fills-height.d.ts +3 -0
- package/dist/screen-fills-height.js +3 -0
- package/dist/share-links.d.ts +4 -0
- package/dist/share-links.js +11 -0
- package/dist/sort-by-accessor.d.ts +5 -0
- package/dist/sort-by-accessor.js +16 -0
- package/dist/sse/live-events.d.ts +23 -0
- package/dist/sse/live-events.js +28 -0
- package/dist/tokens.d.ts +83 -0
- package/dist/tokens.js +80 -0
- package/package.json +16 -9
- package/src/changes.json +52 -0
- package/src/__tests__/error-i18n-defaults.test.ts +0 -82
- package/src/__tests__/format-when.test.ts +0 -12
- package/src/__tests__/i18n.test.tsx +0 -283
- package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
- package/src/__tests__/qn.test.ts +0 -83
- package/src/__tests__/share-links.test.ts +0 -26
- package/src/__tests__/sort-by-accessor.test.ts +0 -48
- package/src/__tests__/stringify-nav-params.test.ts +0 -33
- package/src/__tests__/use-list-url-state.test.tsx +0 -250
- package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
- package/src/app/__tests__/action-form-shim.test.ts +0 -137
- package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
- package/src/app/__tests__/config-edit-shim.test.ts +0 -57
- package/src/app/__tests__/content-editors.test.tsx +0 -128
- package/src/app/__tests__/content-preview.test.tsx +0 -184
- package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
- package/src/app/__tests__/entity-edit-jsonb-embedded-submit.test.tsx +0 -239
- package/src/app/__tests__/entity-list-create-singleton.test.tsx +0 -128
- package/src/app/__tests__/entity-list-row-action-entity-target.test.tsx +0 -424
- package/src/app/__tests__/entity-list-row-action-icon.test.tsx +0 -248
- package/src/app/__tests__/entity-list-row-action-kumiko-actions-view.test.tsx +0 -162
- package/src/app/__tests__/entity-list-row-action-refetch.test.tsx +0 -401
- package/src/app/__tests__/entity-list-screen-padding.test.tsx +0 -111
- package/src/app/__tests__/feature-schema.test.ts +0 -40
- package/src/app/__tests__/form-schema.test.ts +0 -247
- package/src/app/__tests__/list-daterange-facet.test.ts +0 -165
- package/src/app/__tests__/list-filter-facets.test.tsx +0 -521
- package/src/app/__tests__/nav.test.ts +0 -198
- package/src/app/__tests__/projection-detail-actions.test.tsx +0 -719
- package/src/app/__tests__/projection-detail-reference-field.test.tsx +0 -165
- package/src/app/__tests__/projection-detail-shim.test.ts +0 -188
- package/src/app/__tests__/projection-detail-singleton.test.tsx +0 -191
- package/src/app/__tests__/projection-list-bad-shape.test.tsx +0 -152
- package/src/app/__tests__/projection-list-reference-column.test.tsx +0 -219
- package/src/app/__tests__/projection-list-search-sort.test.tsx +0 -212
- package/src/app/__tests__/qualified-names.test.ts +0 -37
- package/src/app/__tests__/return-to.test.ts +0 -396
- package/src/app/__tests__/row-actions-navigate-tab.test.ts +0 -223
- package/src/app/__tests__/row-default-edit-action.test.tsx +0 -324
- package/src/app/__tests__/screen-access-allows.test.ts +0 -34
- package/src/app/__tests__/secret-mint-body.test.tsx +0 -404
- package/src/app/__tests__/variable-chips.test.tsx +0 -70
- package/src/app/app-features-context.tsx +0 -25
- package/src/app/column-renderers.tsx +0 -68
- package/src/app/content-editors.tsx +0 -85
- package/src/app/content-preview.tsx +0 -67
- package/src/app/custom-screens.tsx +0 -29
- package/src/app/dashboard-body.tsx +0 -33
- package/src/app/extension-form-submit.tsx +0 -123
- package/src/app/extension-sections.tsx +0 -111
- package/src/app/form-schema.ts +0 -91
- package/src/app/kumiko-screen.tsx +0 -3614
- package/src/app/layout-fields.ts +0 -31
- package/src/app/list-facets.ts +0 -259
- package/src/app/nav.tsx +0 -258
- package/src/app/projection-detail-shim.ts +0 -85
- package/src/app/reference-facet-bridge.tsx +0 -58
- package/src/app/return-to.tsx +0 -234
- package/src/app/row-actions.ts +0 -639
- package/src/app/screen-access.ts +0 -63
- package/src/app/secret-mint-body.tsx +0 -259
- package/src/app/secrets-edit-body.tsx +0 -194
- package/src/app/use-embedded-screen.ts +0 -27
- package/src/app/variable-chips.tsx +0 -39
- package/src/app/write-failed-error.ts +0 -27
- package/src/components/__tests__/embedded-list-field.test.tsx +0 -531
- package/src/components/__tests__/multi-select-checkboxes.test.tsx +0 -162
- package/src/components/__tests__/related-list-section-empty-state.test.tsx +0 -143
- package/src/components/__tests__/related-list-section.test.tsx +0 -1669
- package/src/components/__tests__/render-edit-action-button.test.tsx +0 -205
- package/src/components/__tests__/render-edit-hidden-section.test.tsx +0 -128
- package/src/components/__tests__/render-edit-logic.test.ts +0 -314
- package/src/components/__tests__/render-edit-screen-description.test.tsx +0 -152
- package/src/components/__tests__/render-edit-submit-actions.test.tsx +0 -460
- package/src/components/__tests__/render-field-app-locale.test.tsx +0 -142
- package/src/components/__tests__/render-field-enum-option.test.tsx +0 -99
- package/src/components/__tests__/render-field-icon-derivation.test.tsx +0 -119
- package/src/components/__tests__/render-field-json-format.test.tsx +0 -164
- package/src/components/__tests__/render-field-money-embedded-list-consistency.test.tsx +0 -212
- package/src/components/__tests__/render-field-money-roundtrip.test.tsx +0 -217
- package/src/components/__tests__/render-field-number-grouping.test.tsx +0 -76
- package/src/components/__tests__/render-field-number-unit.test.tsx +0 -227
- package/src/components/__tests__/render-field-password-format.test.tsx +0 -101
- package/src/components/__tests__/render-field-select-display.test.tsx +0 -134
- package/src/components/__tests__/render-field-unit-format.test.tsx +0 -107
- package/src/components/__tests__/render-field-unsupported-types.test.tsx +0 -195
- package/src/components/__tests__/render-list-toolbar-icon-only.test.tsx +0 -146
- package/src/components/__tests__/write-form-section.test.tsx +0 -375
- package/src/components/embedded-list-field.tsx +0 -354
- package/src/components/grid-cell-for-field.tsx +0 -60
- package/src/components/multi-select-checkboxes.tsx +0 -93
- package/src/components/reference-create-dialog.tsx +0 -91
- package/src/components/related-list-section.tsx +0 -467
- package/src/components/render-edit-action-button.tsx +0 -106
- package/src/components/render-edit-logic.ts +0 -85
- package/src/components/render-edit-types.ts +0 -216
- package/src/components/render-edit.tsx +0 -1700
- package/src/components/render-field.tsx +0 -942
- package/src/components/render-list.tsx +0 -561
- package/src/components/write-form-section.tsx +0 -199
- package/src/context/draft-storage-context.tsx +0 -39
- package/src/hooks/__tests__/use-ai-text.test.tsx +0 -177
- package/src/hooks/__tests__/use-disclosure.test.tsx +0 -25
- package/src/hooks/__tests__/use-form.test.tsx +0 -65
- package/src/hooks/__tests__/use-mutation.test.tsx +0 -77
- package/src/hooks/__tests__/use-stream-handler.test.tsx +0 -107
- package/src/hooks/use-ai-text.ts +0 -172
- package/src/hooks/use-disclosure.ts +0 -20
- package/src/hooks/use-form.ts +0 -78
- package/src/hooks/use-list-url-state.ts +0 -171
- package/src/hooks/use-mutation.ts +0 -61
- package/src/hooks/use-query.ts +0 -132
- package/src/hooks/use-reference-lookup.ts +0 -76
- package/src/hooks/use-store.ts +0 -48
- package/src/hooks/use-stream-handler.ts +0 -134
- package/src/i18n-defaults.ts +0 -220
- package/src/i18n.tsx +0 -286
- package/src/index.ts +0 -272
- package/src/primitives.tsx +0 -1446
- package/src/share-links.ts +0 -12
- package/src/sort-by-accessor.ts +0 -20
- package/src/sse/live-events.tsx +0 -56
- package/src/tokens.tsx +0 -170
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// Tier 2.7e-4: Renderer-Side Eagerload für Reference-Felder.
|
|
2
|
-
//
|
|
3
|
-
// Pro Reference-Spalte einer Liste wird einmal `<feature>:query:
|
|
4
|
-
// <refEntity>:list` (limit:200) gerufen, eine Map<uuid, displayValue>
|
|
5
|
-
// gebaut, und der Renderer nutzt sie als Cell-Display-Renderer.
|
|
6
|
-
//
|
|
7
|
-
// Strategy-Trade-offs:
|
|
8
|
-
// - Server-side Drizzle-Joins wären effizienter (eine Query statt
|
|
9
|
-
// N+1), würden aber die executor-API um lookupTables erweitern
|
|
10
|
-
// müssen. Für das MVP geht der Renderer-Side-Pfad vor.
|
|
11
|
-
// - Limit:200 ist eine harte UX-Grenze: bei mehr Entries in der
|
|
12
|
-
// referenced Entity zeigen die letzten Rows nur noch UUIDs.
|
|
13
|
-
// Searchable-Combobox (Tier 2.1c) + Server-Eagerload mit
|
|
14
|
-
// ID-Whitelist heben das später auf.
|
|
15
|
-
//
|
|
16
|
-
// Dieser Hook ist call-stable: Lookup-Map wird durch useQuery's
|
|
17
|
-
// internen Cache shared zwischen List + Edit-Form für die gleiche
|
|
18
|
-
// Entity, Live-Updates kommen via SSE (use-query-live).
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
REFERENCE_LOOKUP_SOURCES,
|
|
22
|
-
SYSTEM_REFERENCE_LABELS,
|
|
23
|
-
} from "@cosmicdrift/kumiko-framework/ui-types";
|
|
24
|
-
import { useMemo } from "react";
|
|
25
|
-
import { toKebab } from "../app/qn";
|
|
26
|
-
import { useTranslation } from "../i18n";
|
|
27
|
-
import { REFERENCE_LIST_LOOKUP_LIMIT } from "./reference-limits";
|
|
28
|
-
import { useQuery } from "./use-query";
|
|
29
|
-
|
|
30
|
-
export type ReferenceLookupMap = ReadonlyMap<string, string>;
|
|
31
|
-
|
|
32
|
-
/** Where a reference target's label rows come from: the central override for
|
|
33
|
-
* that `feature:entity` if one exists, else the entity-convention list
|
|
34
|
-
* handler plus the caller's own label field. */
|
|
35
|
-
export function referenceLookupSource(
|
|
36
|
-
refFeature: string,
|
|
37
|
-
refEntity: string,
|
|
38
|
-
labelField: string,
|
|
39
|
-
): { readonly queryQn: string; readonly labelKey: string } {
|
|
40
|
-
const override = REFERENCE_LOOKUP_SOURCES[`${refFeature}:${refEntity}`];
|
|
41
|
-
if (override !== undefined) return override;
|
|
42
|
-
return {
|
|
43
|
-
queryQn: `${toKebab(refFeature)}:query:${toKebab(refEntity)}:list`,
|
|
44
|
-
labelKey: labelField,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Empty while the query loads (or fails), so callers fall back to the raw id.
|
|
49
|
-
* `featureName` is the reference's target feature, not the screen's. */
|
|
50
|
-
export function useReferenceLookup(
|
|
51
|
-
featureName: string,
|
|
52
|
-
refEntity: string,
|
|
53
|
-
labelField: string,
|
|
54
|
-
): { readonly map: ReferenceLookupMap; readonly loading: boolean } {
|
|
55
|
-
const { queryQn, labelKey } = referenceLookupSource(featureName, refEntity, labelField);
|
|
56
|
-
const result = useQuery<{ rows: ReadonlyArray<Record<string, unknown>> }>(queryQn, {
|
|
57
|
-
limit: REFERENCE_LIST_LOOKUP_LIMIT,
|
|
58
|
-
});
|
|
59
|
-
const translate = useTranslation();
|
|
60
|
-
const systemLabel = SYSTEM_REFERENCE_LABELS[`${featureName}:${refEntity}`];
|
|
61
|
-
const map = useMemo(() => {
|
|
62
|
-
const out = new Map<string, string>();
|
|
63
|
-
for (const row of result.data?.rows ?? []) {
|
|
64
|
-
const id = row["id"];
|
|
65
|
-
if (id === undefined || id === null) continue;
|
|
66
|
-
const idStr = String(id);
|
|
67
|
-
const label = row[labelKey] ?? id;
|
|
68
|
-
out.set(idStr, String(label));
|
|
69
|
-
}
|
|
70
|
-
// System-scope ids (e.g. SYSTEM_TENANT_ID) never have a backing row, so
|
|
71
|
-
// the bulk lookup above never covers them — inject the label directly.
|
|
72
|
-
if (systemLabel !== undefined) out.set(systemLabel.id, translate(systemLabel.labelKey));
|
|
73
|
-
return out;
|
|
74
|
-
}, [result.data, labelKey, systemLabel, translate]);
|
|
75
|
-
return { map, loading: result.loading };
|
|
76
|
-
}
|
package/src/hooks/use-store.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { Store } from "@cosmicdrift/kumiko-headless";
|
|
2
|
-
import { useRef, useSyncExternalStore } from "react";
|
|
3
|
-
|
|
4
|
-
// React-Bindings für Kumikos Store-Primitive (`createStore` aus
|
|
5
|
-
// @cosmicdrift/kumiko-headless). Beide Hooks sind dünne Wrapper um React's
|
|
6
|
-
// useSyncExternalStore — die ganze Subscribe/Notify-Mechanik lebt im
|
|
7
|
-
// Store selbst, hier wird nur React verdrahtet.
|
|
8
|
-
//
|
|
9
|
-
// useStore: gibt den ganzen Snapshot zurück. Re-rendert wenn der
|
|
10
|
-
// Store seine Identität wechselt. Object.is-Gate im Store selbst
|
|
11
|
-
// verhindert no-op-Updates.
|
|
12
|
-
//
|
|
13
|
-
// useStoreSelector: gibt eine abgeleitete Sicht zurück. Selectors die
|
|
14
|
-
// Object-/Array-Literale zurückgeben (z.B. `s => ({ a, b })`) erzeugen
|
|
15
|
-
// pro Render eine neue Identität — useSyncExternalStore würde das als
|
|
16
|
-
// "Change" lesen und in eine Re-Render-Schleife laufen. Der dritte
|
|
17
|
-
// Arg `equals` dient genau dafür: gleiche Auswahl → cached
|
|
18
|
-
// Identität zurück, kein Re-Render.
|
|
19
|
-
|
|
20
|
-
// @wrapper-known semantic-alias
|
|
21
|
-
export function useStore<T>(store: Store<T>): T {
|
|
22
|
-
return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function useStoreSelector<T, S>(
|
|
26
|
-
store: Store<T>,
|
|
27
|
-
select: (snapshot: T) => S,
|
|
28
|
-
equals: (a: S, b: S) => boolean = Object.is,
|
|
29
|
-
): S {
|
|
30
|
-
// Cache der letzten Auswahl. Beim nächsten getSnapshot-Call vergleicht
|
|
31
|
-
// der Wrapper die neu berechnete Auswahl mit dem Cache und gibt — falls
|
|
32
|
-
// gleich — die cached Identität zurück. Das ist der Trick, der
|
|
33
|
-
// Selector-Returns wie `s => ({ a, b })` stabil hält.
|
|
34
|
-
const lastSelected = useRef<S>(undefined as S);
|
|
35
|
-
const initialized = useRef(false);
|
|
36
|
-
|
|
37
|
-
const getSelectedSnapshot = (): S => {
|
|
38
|
-
const next = select(store.getSnapshot());
|
|
39
|
-
if (initialized.current && equals(lastSelected.current, next)) {
|
|
40
|
-
return lastSelected.current;
|
|
41
|
-
}
|
|
42
|
-
lastSelected.current = next;
|
|
43
|
-
initialized.current = true;
|
|
44
|
-
return next;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
return useSyncExternalStore(store.subscribe, getSelectedSnapshot, getSelectedSnapshot);
|
|
48
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import type { DispatcherError } from "@cosmicdrift/kumiko-headless";
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
-
import { useDispatcher } from "../context/dispatcher-context";
|
|
4
|
-
|
|
5
|
-
// React wrapper around dispatcher.stream (#1382). Accumulates yielded
|
|
6
|
-
// chunks into `chunks` (unlike useQuery({live:true}), which only
|
|
7
|
-
// invalidates and re-fetches). Each start() owns an AbortController;
|
|
8
|
-
// a newer start() / unmount aborts the previous run so late chunks
|
|
9
|
-
// cannot clobber fresher state.
|
|
10
|
-
|
|
11
|
-
export type StreamStatus = "idle" | "streaming" | "done" | "error";
|
|
12
|
-
|
|
13
|
-
export type UseStreamHandlerResult<TChunk> = {
|
|
14
|
-
readonly chunks: readonly TChunk[];
|
|
15
|
-
readonly status: StreamStatus;
|
|
16
|
-
readonly error: DispatcherError | null;
|
|
17
|
-
readonly start: (payload?: unknown) => Promise<void>;
|
|
18
|
-
readonly abort: () => void;
|
|
19
|
-
readonly reset: () => void;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type UseStreamHandlerOptions = {
|
|
23
|
-
// When true, start() runs once on mount with the initial payload.
|
|
24
|
-
// Default false — streams are usually user-triggered (unlike queries).
|
|
25
|
-
readonly autoStart?: boolean;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export function useStreamHandler<TChunk = unknown>(
|
|
29
|
-
type: string,
|
|
30
|
-
payload: unknown = {},
|
|
31
|
-
options: UseStreamHandlerOptions = {},
|
|
32
|
-
): UseStreamHandlerResult<TChunk> {
|
|
33
|
-
const dispatcher = useDispatcher();
|
|
34
|
-
const { autoStart = false } = options;
|
|
35
|
-
|
|
36
|
-
const [chunks, setChunks] = useState<readonly TChunk[]>([]);
|
|
37
|
-
const [status, setStatus] = useState<StreamStatus>("idle");
|
|
38
|
-
const [error, setError] = useState<DispatcherError | null>(null);
|
|
39
|
-
|
|
40
|
-
const activeCtrl = useRef<AbortController | null>(null);
|
|
41
|
-
const payloadRef = useRef(payload);
|
|
42
|
-
payloadRef.current = payload;
|
|
43
|
-
|
|
44
|
-
const abort = useCallback((): void => {
|
|
45
|
-
activeCtrl.current?.abort();
|
|
46
|
-
activeCtrl.current = null;
|
|
47
|
-
// User cancel — exit streaming so UI can re-enable the start button.
|
|
48
|
-
setStatus((s) => (s === "streaming" ? "idle" : s));
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
const reset = useCallback((): void => {
|
|
52
|
-
abort();
|
|
53
|
-
setChunks([]);
|
|
54
|
-
setStatus("idle");
|
|
55
|
-
setError(null);
|
|
56
|
-
}, [abort]);
|
|
57
|
-
|
|
58
|
-
// Shared by every abort-detection branch below: only touch status if this
|
|
59
|
-
// run is still the active one (or activeCtrl was already cleared by abort()).
|
|
60
|
-
const settleAborted = useCallback((ctrl: AbortController): void => {
|
|
61
|
-
if (activeCtrl.current === null || activeCtrl.current === ctrl) setStatus("idle");
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
const start = useCallback(
|
|
65
|
-
async (overridePayload?: unknown): Promise<void> => {
|
|
66
|
-
activeCtrl.current?.abort();
|
|
67
|
-
const ctrl = new AbortController();
|
|
68
|
-
activeCtrl.current = ctrl;
|
|
69
|
-
|
|
70
|
-
setChunks([]);
|
|
71
|
-
setError(null);
|
|
72
|
-
setStatus("streaming");
|
|
73
|
-
|
|
74
|
-
const body = overridePayload !== undefined ? overridePayload : payloadRef.current;
|
|
75
|
-
try {
|
|
76
|
-
for await (const chunk of dispatcher.stream<TChunk>(type, body, { signal: ctrl.signal })) {
|
|
77
|
-
// skip: a newer start() already superseded this run
|
|
78
|
-
if (ctrl.signal.aborted) {
|
|
79
|
-
settleAborted(ctrl);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
setChunks((prev) => [...prev, chunk]);
|
|
83
|
-
}
|
|
84
|
-
// skip: aborted after last chunk, don't mark done
|
|
85
|
-
if (ctrl.signal.aborted) {
|
|
86
|
-
settleAborted(ctrl);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
setStatus("done");
|
|
90
|
-
} catch (e) {
|
|
91
|
-
// skip: abort is not an error toast
|
|
92
|
-
if (ctrl.signal.aborted) {
|
|
93
|
-
settleAborted(ctrl);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const mapped = asDispatcherError(e);
|
|
97
|
-
// skip: dispatcher-mapped abort (fetch cancelled)
|
|
98
|
-
if (mapped.code === "aborted") {
|
|
99
|
-
settleAborted(ctrl);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
setError(mapped);
|
|
103
|
-
setStatus("error");
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
[dispatcher, type, settleAborted],
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
// skip: autoStart off — streams are usually user-triggered
|
|
111
|
-
if (!autoStart) return;
|
|
112
|
-
void start();
|
|
113
|
-
}, [autoStart, start]);
|
|
114
|
-
|
|
115
|
-
useEffect(() => {
|
|
116
|
-
return () => {
|
|
117
|
-
activeCtrl.current?.abort();
|
|
118
|
-
};
|
|
119
|
-
}, []);
|
|
120
|
-
|
|
121
|
-
return { chunks, status, error, start, abort, reset };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function asDispatcherError(e: unknown): DispatcherError {
|
|
125
|
-
if (e && typeof e === "object" && "code" in e && "message" in e && "i18nKey" in e) {
|
|
126
|
-
return e as DispatcherError;
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
code: "stream_error",
|
|
130
|
-
httpStatus: 0,
|
|
131
|
-
i18nKey: "errors.unknown",
|
|
132
|
-
message: e instanceof Error ? e.message : String(e),
|
|
133
|
-
};
|
|
134
|
-
}
|
package/src/i18n-defaults.ts
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
// Framework-Default-Bundle. Strings die die Renderer-Components hart
|
|
2
|
-
// brauchen (Save/Cancel/Delete-Buttons, Empty-States, Search-Placeholder,
|
|
3
|
-
// Nav-Toggle-aria-Labels, Validation-Reasons). createKumikoApp hängt das
|
|
4
|
-
// als ALLERLETZTEN Fallback in den LocaleProvider — Apps können
|
|
5
|
-
// einzelne Keys via clientFeatures.translations überschreiben.
|
|
6
|
-
//
|
|
7
|
-
// Convention: alle Keys mit `kumiko.`-Prefix damit sie nicht mit
|
|
8
|
-
// App-Keys kollidieren. Sub-Pfade gruppieren nach Bereich (actions /
|
|
9
|
-
// list / nav / form / validation).
|
|
10
|
-
|
|
11
|
-
import type { TranslationsByLocale } from "./i18n";
|
|
12
|
-
|
|
13
|
-
export const kumikoDefaultTranslations: TranslationsByLocale = {
|
|
14
|
-
en: {
|
|
15
|
-
"kumiko.actions.save": "Save",
|
|
16
|
-
"kumiko.actions.cancel": "Cancel",
|
|
17
|
-
"kumiko.actions.delete": "Delete",
|
|
18
|
-
"kumiko.actions.delete-confirm": "Confirm delete?",
|
|
19
|
-
"kumiko.actions.reload": "Reload",
|
|
20
|
-
"kumiko.actions.create": "New",
|
|
21
|
-
"kumiko.actions.edit": "Edit",
|
|
22
|
-
"kumiko.actions.view": "View",
|
|
23
|
-
"kumiko.actions.copyLink": "Copy link",
|
|
24
|
-
"kumiko.actions.copyLinkCopied": "Copied!",
|
|
25
|
-
"kumiko.actions.next": "Next",
|
|
26
|
-
"kumiko.actions.back": "Back",
|
|
27
|
-
"kumiko.actions.finish": "Finish",
|
|
28
|
-
|
|
29
|
-
"kumiko.wizard.step": "Step {current} of {total}",
|
|
30
|
-
"kumiko.wizard.step-with-title": "Step {current} of {total} · {title}",
|
|
31
|
-
|
|
32
|
-
"kumiko.version.update-available": "A new version is available.",
|
|
33
|
-
|
|
34
|
-
"kumiko.toast.learn-more": "Learn more",
|
|
35
|
-
|
|
36
|
-
"kumiko.field.open-calendar": "Open calendar",
|
|
37
|
-
"kumiko.field.dateField.placeholderYear": "Y",
|
|
38
|
-
"kumiko.field.dateField.placeholderMonth": "M",
|
|
39
|
-
"kumiko.field.dateField.placeholderDay": "D",
|
|
40
|
-
"kumiko.field.time": "Time",
|
|
41
|
-
"kumiko.field.timezone": "Time zone",
|
|
42
|
-
"kumiko.field.locatedTzHint": "Time local to the given location",
|
|
43
|
-
"kumiko.field.reference-created-no-id":
|
|
44
|
-
"Record was created but could not be selected automatically. Please select it manually.",
|
|
45
|
-
"kumiko.field.unsupported": "This field type can't be edited here yet.",
|
|
46
|
-
"kumiko.field.embedded-list.add-row": "Add row",
|
|
47
|
-
"kumiko.field.embedded-list.remove-row": "Remove row",
|
|
48
|
-
"kumiko.field.embedded-list.duplicate-row": "Duplicate row",
|
|
49
|
-
"kumiko.field.embedded-list.move-up": "Move up",
|
|
50
|
-
"kumiko.field.embedded-list.move-down": "Move down",
|
|
51
|
-
"kumiko.field.embedded-list.empty": "No rows yet.",
|
|
52
|
-
"kumiko.field.embedded-list.empty-cta": "Add first row",
|
|
53
|
-
"kumiko.field.embedded-list.paste-rows-truncated":
|
|
54
|
-
"{count} pasted row(s) were dropped (max row count reached).",
|
|
55
|
-
"kumiko.field.embedded-list.paste-cells-unmatched":
|
|
56
|
-
"{count} cell(s) had no matching option and were left unchanged.",
|
|
57
|
-
"kumiko.field.multiSelect.select-all": "Select all",
|
|
58
|
-
"kumiko.field.multiSelect.deselect-all": "Deselect all",
|
|
59
|
-
|
|
60
|
-
"kumiko.list.search-placeholder": "Search…",
|
|
61
|
-
"kumiko.list.empty.title": "No entries yet.",
|
|
62
|
-
"kumiko.list.empty.hint": "Create the first one to get started.",
|
|
63
|
-
"kumiko.list.no-entries": "No entries.",
|
|
64
|
-
"kumiko.list.end-of-list": "— End of list —",
|
|
65
|
-
"kumiko.list.sort.label": "Sort",
|
|
66
|
-
"kumiko.list.sort.unsorted": "Unsorted",
|
|
67
|
-
"kumiko.list.filter.reset": "Reset",
|
|
68
|
-
"kumiko.list.related-list-truncated":
|
|
69
|
-
"Showing the first {count} entries. More are available but not loaded — this list does not paginate.",
|
|
70
|
-
"kumiko.reference.system-tenant": "System",
|
|
71
|
-
"kumiko.reference.system-user": "System",
|
|
72
|
-
|
|
73
|
-
"kumiko.pager.status": "{from}–{to} of {total}",
|
|
74
|
-
"kumiko.pager.previousPage": "Previous page",
|
|
75
|
-
"kumiko.pager.nextPage": "Next page",
|
|
76
|
-
"kumiko.pager.page": "Page {entry}",
|
|
77
|
-
|
|
78
|
-
"kumiko.combobox.search-placeholder": "Search…",
|
|
79
|
-
"kumiko.combobox.empty": "No matches.",
|
|
80
|
-
"kumiko.combobox.loading": "Loading…",
|
|
81
|
-
"kumiko.combobox.placeholder": "—",
|
|
82
|
-
|
|
83
|
-
"kumiko.dashboard.filter.all": "All",
|
|
84
|
-
|
|
85
|
-
"kumiko.app-boot.loading": "Loading…",
|
|
86
|
-
"kumiko.app-boot.unauthorized": "You need to sign in to see this.",
|
|
87
|
-
"kumiko.app-boot.failed": "Couldn't load the app. Check your connection and try again.",
|
|
88
|
-
"kumiko.app-boot.no-open-screen":
|
|
89
|
-
"This app has no screen that's accessible without a role restriction.",
|
|
90
|
-
|
|
91
|
-
"kumiko.widget.loading": "Loading…",
|
|
92
|
-
"kumiko.widget.error.title": "Couldn't load.",
|
|
93
|
-
|
|
94
|
-
"kumiko.widget.upload.uploading": "Uploading…",
|
|
95
|
-
"kumiko.widget.upload.done": "Uploaded",
|
|
96
|
-
"kumiko.widget.upload.error": "Failed",
|
|
97
|
-
"kumiko.widget.upload.rejected-type": "File type not allowed",
|
|
98
|
-
|
|
99
|
-
"kumiko.widget.step-bar.done": "Done",
|
|
100
|
-
|
|
101
|
-
"kumiko.widget.drawer.restore": "Restore drawer width",
|
|
102
|
-
"kumiko.widget.drawer.maximize": "Maximize drawer width",
|
|
103
|
-
"kumiko.widget.drawer.resize": "Resize drawer",
|
|
104
|
-
|
|
105
|
-
"kumiko.widget.floatingPanel.move": "Move panel",
|
|
106
|
-
"kumiko.widget.floatingPanel.resizeTop": "Resize panel from the top edge",
|
|
107
|
-
"kumiko.widget.floatingPanel.resizeRight": "Resize panel from the right edge",
|
|
108
|
-
"kumiko.widget.floatingPanel.resizeBottom": "Resize panel from the bottom edge",
|
|
109
|
-
"kumiko.widget.floatingPanel.resizeLeft": "Resize panel from the left edge",
|
|
110
|
-
|
|
111
|
-
"kumiko.planCard.current": "Current plan",
|
|
112
|
-
"kumiko.planCard.priceUnavailable": "Price not available",
|
|
113
|
-
|
|
114
|
-
"kumiko.nav.expand": "Expand",
|
|
115
|
-
"kumiko.nav.collapse": "Collapse",
|
|
116
|
-
"kumiko.nav.search": "Search navigation…",
|
|
117
|
-
"kumiko.nav.language": "Language",
|
|
118
|
-
|
|
119
|
-
"kumiko.workspace.switch": "Switch workspace",
|
|
120
|
-
// Workspace-Switcher fallback label when activeId points at no visible workspace.
|
|
121
|
-
"kumiko.workspace.select": "Select workspace",
|
|
122
|
-
|
|
123
|
-
"kumiko.dialog.confirm": "Confirm",
|
|
124
|
-
"kumiko.dialog.cancel": "Cancel",
|
|
125
|
-
"kumiko.dialog.close": "Close",
|
|
126
|
-
|
|
127
|
-
"kumiko.aiText.acceptHint": "Tab = accept, Esc = discard",
|
|
128
|
-
"kumiko.aiText.correct": "Correct",
|
|
129
|
-
"kumiko.aiText.translate": "Translate",
|
|
130
|
-
"kumiko.aiText.rewrite": "Rewrite",
|
|
131
|
-
"kumiko.aiText.diff.before": "Before",
|
|
132
|
-
"kumiko.aiText.diff.after": "After",
|
|
133
|
-
"kumiko.aiText.diff.generating": "Generating…",
|
|
134
|
-
"kumiko.aiText.style.formal": "Formal",
|
|
135
|
-
"kumiko.aiText.style.casual": "Casual",
|
|
136
|
-
"kumiko.aiText.style.concise": "Concise",
|
|
137
|
-
"kumiko.aiText.style.expand": "Expand",
|
|
138
|
-
"kumiko.aiText.capExceeded": "Monthly AI limit reached.",
|
|
139
|
-
|
|
140
|
-
"kumiko.rowAction.failed": "Action failed",
|
|
141
|
-
|
|
142
|
-
"kumiko.contentEditor.insertVariable": "Insert {name}",
|
|
143
|
-
"kumiko.contentEditor.preview": "Preview",
|
|
144
|
-
"kumiko.contentEditor.editMode": "Edit",
|
|
145
|
-
"kumiko.contentEditor.bold": "Bold",
|
|
146
|
-
"kumiko.contentEditor.italic": "Italic",
|
|
147
|
-
"kumiko.contentEditor.heading1": "Heading 1",
|
|
148
|
-
"kumiko.contentEditor.heading2": "Heading 2",
|
|
149
|
-
"kumiko.contentEditor.bulletList": "Bullet list",
|
|
150
|
-
"kumiko.contentEditor.orderedList": "Numbered list",
|
|
151
|
-
|
|
152
|
-
"kumiko.config.source.user": "My value",
|
|
153
|
-
"kumiko.config.source.tenant": "Tenant",
|
|
154
|
-
"kumiko.config.source.system": "System",
|
|
155
|
-
"kumiko.config.source.appOverride": "App override",
|
|
156
|
-
"kumiko.config.source.computed": "Computed",
|
|
157
|
-
"kumiko.config.source.default": "Default",
|
|
158
|
-
"kumiko.config.source.missing": "Missing",
|
|
159
|
-
"kumiko.config.cascade.noValue": "No value set",
|
|
160
|
-
"kumiko.config.cascade.activeMarker": "active",
|
|
161
|
-
"kumiko.config.cascade.resetTo": "Reset override ({scope})",
|
|
162
|
-
|
|
163
|
-
"kumiko.form.error.generic": "Something went wrong.",
|
|
164
|
-
"kumiko.form.error.version-conflict":
|
|
165
|
-
"Record was modified in the meantime. Reload and try again.",
|
|
166
|
-
"kumiko.form.extension.save-failed": "A custom field could not be saved.",
|
|
167
|
-
"kumiko.form.draft.resume-multiple":
|
|
168
|
-
"Found multiple open drafts for this form. Which one do you want to resume?",
|
|
169
|
-
"kumiko.form.draft.resume-single":
|
|
170
|
-
"Found an open draft for this form. Do you want to resume it?",
|
|
171
|
-
"kumiko.form.draft.start-new": "Start new",
|
|
172
|
-
|
|
173
|
-
"kumiko.secretMint.title": "Your new secret",
|
|
174
|
-
"kumiko.secretMint.warning":
|
|
175
|
-
"Copy this now — it is shown only this once and cannot be retrieved later.",
|
|
176
|
-
"kumiko.secretMint.confirm": "I have copied it",
|
|
177
|
-
"kumiko.secretMint.copy": "Copy",
|
|
178
|
-
"kumiko.secretMint.copied": "Copied",
|
|
179
|
-
"kumiko.secretMint.done": "Done.",
|
|
180
|
-
|
|
181
|
-
"kumiko.validation.required": "Required.",
|
|
182
|
-
"kumiko.validation.invalid": "Invalid value.",
|
|
183
|
-
"kumiko.validation.too-short": "Too short (at least {min} characters).",
|
|
184
|
-
"kumiko.validation.too-long": "Too long (at most {max} characters).",
|
|
185
|
-
"kumiko.validation.out-of-range": "Value out of allowed range.",
|
|
186
|
-
|
|
187
|
-
"errors.validation.invalid_type": "Invalid value.",
|
|
188
|
-
"errors.validation.too_small": "Too small or too short (minimum: {minimum}).",
|
|
189
|
-
"errors.validation.too_big": "Too big or too long (maximum: {maximum}).",
|
|
190
|
-
"errors.validation.invalid_format": "Invalid format.",
|
|
191
|
-
"errors.validation.not_multiple_of": "Must be a multiple of {divisor}.",
|
|
192
|
-
"errors.validation.unrecognized_keys": "Unknown fields.",
|
|
193
|
-
"errors.validation.invalid_union": "Invalid value.",
|
|
194
|
-
"errors.validation.invalid_key": "Invalid key.",
|
|
195
|
-
"errors.validation.invalid_element": "Invalid entry.",
|
|
196
|
-
"errors.validation.invalid_value": "Invalid choice.",
|
|
197
|
-
"errors.validation.custom": "Invalid value.",
|
|
198
|
-
"errors.validation.unexpected_field": "Unknown field.",
|
|
199
|
-
"errors.validation.out_of_bounds": "Value out of allowed range.",
|
|
200
|
-
"errors.validation.invalid_option": "Invalid choice.",
|
|
201
|
-
"errors.validation.failed": "Validation failed.",
|
|
202
|
-
|
|
203
|
-
"errors.feature.disabled": "This feature is currently unavailable.",
|
|
204
|
-
"errors.access.denied": "You don't have permission to do this.",
|
|
205
|
-
"errors.notFound": "Not found.",
|
|
206
|
-
"errors.conflict": "Conflict — the operation could not be completed.",
|
|
207
|
-
"errors.versionConflict": "The record was modified in the meantime. Reload and try again.",
|
|
208
|
-
"errors.preconditionFailed": "The record changed in the meantime. Reload and try again.",
|
|
209
|
-
"errors.uniqueViolation": "This entry already exists.",
|
|
210
|
-
"errors.unprocessable": "The request could not be processed.",
|
|
211
|
-
"errors.unconfigured": "This feature isn't configured yet.",
|
|
212
|
-
"errors.internal": "Something went wrong. Please try again later.",
|
|
213
|
-
"errors.rate_limited": "Too many requests. Please try again shortly.",
|
|
214
|
-
"errors.cap.exceeded": "Limit reached. Upgrade your plan or wait for the next period.",
|
|
215
|
-
"errors.download.urlMissing": "Download unavailable — please try again.",
|
|
216
|
-
"auth.errors.originNotAllowed": "Requests from this origin are not allowed.",
|
|
217
|
-
"dispatcher.errors.network": "Network error. Please check your connection and try again.",
|
|
218
|
-
"dispatcher.errors.aborted": "Request was cancelled.",
|
|
219
|
-
},
|
|
220
|
-
};
|