feat(quick-260916-bwo): Dashboard-Raster verdoppelt (24 Spalten, 20 px, 8 px Abstand), Konstanten x2, einmalige Umrechnung gespeicherter Anordnungen mit Marker __gridVersion
- dashboard-grid.tsx: COLS 24/20/12/8/2, rowHeight 20, margin 8 (containerPadding folgt), Rueckfallwerte 4 - widget-registry.tsx: alle 32 Werte in WIDGET_CONSTRAINTS verdoppelt - grid-layout-migration.ts (neu): migrateGridLayouts/withGridVersion, Marker nur im JSON, Idempotenz (T-BWO-02) - dashboard-store.ts: Umrechnung beim Laden, Sofort-Speichern mit Marker, withGridVersion bei jedem saveLayout - Tests: Migration 7 (neu), Store 6 (neu), Registry +1 (Tabelle), Grid +2 (Props ueber Mock), API-Spec +2 (Durchreichung __gridVersion, timeFontSizePt) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -2,6 +2,7 @@ import { create } from 'zustand';
|
||||
import * as api from '@/lib/dashboard-api';
|
||||
import type { WidgetType } from '@/components/dashboard/widget-registry';
|
||||
import { WIDGET_CONSTRAINTS } from '@/components/dashboard/widget-registry';
|
||||
import { migrateGridLayouts, withGridVersion } from '@/lib/grid-layout-migration';
|
||||
|
||||
export interface WidgetInstance {
|
||||
id: string;
|
||||
@@ -28,6 +29,14 @@ interface DashboardState {
|
||||
/**
|
||||
* Dashboard Zustand store. NO persist middleware — layout comes from DB (D-05).
|
||||
* Save only on exiting edit mode (D-01), not on every drag.
|
||||
*
|
||||
* quick-260916-bwo: Gespeicherte Anordnungen in alten Raster-Einheiten werden
|
||||
* beim Laden einmalig umgerechnet (`migrateGridLayouts`) und sofort mit dem
|
||||
* Marker `__gridVersion` zurueckgeschrieben. Der Marker lebt NUR im
|
||||
* gespeicherten JSON, nie im Zustand (dieser Store iteriert mit Object.keys
|
||||
* ueber die Breakpoints). Fehlt der Marker beim Speichern, wird beim naechsten
|
||||
* Laden erneut verdoppelt — deshalb `withGridVersion` an BEIDEN Speicherstellen
|
||||
* (Sofort-Speichern nach der Umrechnung und `saveLayout`), T-BWO-02.
|
||||
*/
|
||||
export const useDashboardStore = create<DashboardState>()((set, get) => ({
|
||||
layouts: { lg: [], md: [], sm: [], xs: [], xxs: [] },
|
||||
@@ -108,15 +117,26 @@ export const useDashboardStore = create<DashboardState>()((set, get) => ({
|
||||
loadDashboard: async () => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const [layouts, widgets] = await Promise.all([
|
||||
const [rawLayouts, widgets] = await Promise.all([
|
||||
api.fetchLayout(),
|
||||
api.fetchWidgets(),
|
||||
]);
|
||||
const { layouts: migratedLayouts, migrated } = migrateGridLayouts(rawLayouts);
|
||||
set({
|
||||
layouts: layouts as DashboardState['layouts'],
|
||||
layouts: migratedLayouts,
|
||||
widgets,
|
||||
isLoading: false,
|
||||
});
|
||||
// Umgerechnete Anordnung SOFORT mit Marker persistieren — nach dem set,
|
||||
// damit die Oberflaeche unabhaengig vom Speichern rendert; eigener
|
||||
// try/catch, damit ein Speicherfehler NICHT als Ladefehler erscheint.
|
||||
if (migrated) {
|
||||
try {
|
||||
await api.saveLayout(withGridVersion(migratedLayouts));
|
||||
} catch (err) {
|
||||
console.error('Failed to persist migrated layout:', err);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
set({
|
||||
error: 'Failed to load dashboard',
|
||||
@@ -127,7 +147,7 @@ export const useDashboardStore = create<DashboardState>()((set, get) => ({
|
||||
|
||||
saveLayout: async () => {
|
||||
try {
|
||||
await api.saveLayout(get().layouts);
|
||||
await api.saveLayout(withGridVersion(get().layouts));
|
||||
set({ isDirty: false });
|
||||
} catch (err) {
|
||||
console.error('Failed to save layout:', err);
|
||||
|
||||
Reference in New Issue
Block a user