Files
Dashboard/features/dashboard/view-models/index.ts
T
dejanandClaude Opus 5 99be627dad refactor(dashboard): Seiten von der Datenquelle entkoppeln
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
2026-08-29 17:39:41 +02:00

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;
}