Die Seiten holten ihre Zahlen selbst aus einem globalen Store. HiveGrid Cloud
verlangt reine Screens nach dem Muster <XPage vm={} actions={} /> — jede Seite
hätte beim Einbau auseinandergenommen werden müssen.
Neue Schichtung:
view-models/<seite>.vm.ts baue<Seite>VM(daten, filter) → VMState<…>
reine Funktion, kein React, kein Store
pages/<Seite>.tsx ({ vm, optionen }) → JSX wird portiert
routes/<Seite>Route.tsx Store + Builder + Seite wird ersetzt
view-models/index.ts spiegelt VMState wortgleich aus @hivegrid/view-models;
beim Einbau ist es ein Import-Wechsel. Der Loader ruft denselben Builder mit
echten Daten, die Seiten bleiben unberührt.
Dabei abgefallen: die fünf Seitenzustände (idle · loading · ready · empty ·
error) über SeitenZustand — bisher lief der Prototyp nur im Zustand "Daten da",
in der Cloud sind alle fünf DoD-Pflicht. Die Filterleiste bekommt ihre
Auswahllisten jetzt als Prop (in der Software die Facetten aus dem Loader)
statt sie selbst aus dem Datensatz zu ziehen.
Store- und Rohdatenzugriff gibt es damit ausschließlich in routes/. Alle sechs
Seiten rendern pixelgleich; typecheck, lint und build sind grün.
Nicht geändert: Next.js bleibt. Im gesamten Projekt gibt es vier
Next-spezifische Importe, alle in AppShell und app/layout — beide Dateien
entfallen beim Einbau ohnehin, weil die Cloud Shell und Root-Layout mitbringt.
Ein Framework-Wechsel wäre Aufwand ohne Ertrag.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
/**
|
|
* View-Model-Vertrag.
|
|
*
|
|
* Wortgleicher Spiegel von `VMState` aus `@hivegrid/view-models` in HiveGrid
|
|
* Cloud (`packages/view-models/src/index.ts`). Beim Einbau wird dieser Import
|
|
* gegen das echte Paket getauscht — die Seiten selbst ändern sich dabei nicht.
|
|
*
|
|
* Warum das hier überhaupt steht: Die Cloud trennt strikt zwischen Route und
|
|
* Screen. Die Route besitzt Loader, Actions und Realtime; die Screen-Komponente
|
|
* ist rein und bekommt alles als Prop (`<XPage vm={} actions={} />`). Eine
|
|
* Komponente, die sich ihre Daten selbst aus einem Store holt, muss beim Einbau
|
|
* auseinandergenommen werden — genau das soll dieser Prototyp ersparen.
|
|
*/
|
|
|
|
export type VMStatus = "idle" | "loading" | "ready" | "empty" | "error";
|
|
|
|
export type VMState<T> =
|
|
| { status: "idle"; data?: undefined; error?: undefined }
|
|
| { status: "loading"; data?: T; error?: undefined }
|
|
| { status: "ready"; data: T; error?: undefined }
|
|
| { status: "empty"; data?: undefined; error?: undefined }
|
|
| { status: "error"; data?: T; error: { messageKey: string; code?: string } };
|
|
|
|
/** Kurzform für den Normalfall im Prototyp: Daten liegen vor. */
|
|
export function bereit<T>(data: T): VMState<T> {
|
|
return { status: "ready", data };
|
|
}
|
|
|
|
/** Kein Datensatz für die aktuelle Auswahl — nicht dasselbe wie ein Fehler. */
|
|
export function leer<T>(): VMState<T> {
|
|
return { status: "empty" };
|
|
}
|
|
|
|
/**
|
|
* Aktionen einer Seite.
|
|
*
|
|
* Im Prototyp lösen sie einen Hinweis-Toast aus; in der Software werden daraus
|
|
* Navigationen und Schreibpfade. Wichtig ist die Form: Der Screen ruft einen
|
|
* Callback auf, er kennt weder Router noch Fetcher.
|
|
*/
|
|
export interface SeitenAktionen {
|
|
/** Absprung in eine Arbeitsliste, z. B. aus dem Handlungsbedarf. */
|
|
readonly onAbsprung?: (ziel: string, kontext?: string) => void;
|
|
/** Datensatz in der Tabelle geöffnet. */
|
|
readonly onZeileOeffnen?: (id: string) => void;
|
|
/** Ansicht neu laden. */
|
|
readonly onAktualisieren?: () => void;
|
|
}
|