Files
DataClaw/frontend/src/store/dashboardStore.ts
T

94 lines
3.0 KiB
TypeScript
Raw Normal View History

2026-03-14 15:52:27 +08:00
import { create } from 'zustand';
2026-03-15 17:57:09 +08:00
import type { ChartSpec } from './visualizationStore';
2026-03-14 15:52:27 +08:00
type ChartRow = Record<string, unknown>;
type GridLayout = { i: string; x: number; y: number; w: number; h: number };
export interface ChartConfig {
id: string;
title: string;
2026-03-17 11:47:30 +08:00
type: 'bar' | 'line' | 'table';
2026-03-14 15:52:27 +08:00
data: ChartRow[];
sql: string;
2026-03-15 17:57:09 +08:00
chartSpec?: ChartSpec | null;
2026-03-14 15:52:27 +08:00
layout: GridLayout;
}
interface DashboardState {
charts: ChartConfig[];
2026-03-16 16:12:35 +08:00
addChart: (chart: Omit<ChartConfig, 'layout'>, projectId: number) => void;
removeChart: (id: string, projectId: number) => void;
updateLayout: (layouts: GridLayout[], projectId: number) => void;
loadCharts: (projectId: number) => void;
2026-03-14 15:52:27 +08:00
}
2026-03-16 16:12:35 +08:00
const DASHBOARD_STORAGE_KEY_PREFIX = 'dashboard_charts_v1_project_';
2026-03-15 18:11:26 +08:00
2026-03-16 16:12:35 +08:00
function getStorageKey(projectId: number) {
return `${DASHBOARD_STORAGE_KEY_PREFIX}${projectId}`;
}
function loadChartsFromStorage(projectId: number): ChartConfig[] {
2026-03-15 18:11:26 +08:00
if (typeof window === 'undefined') return [];
try {
2026-03-16 16:12:35 +08:00
const raw = window.localStorage.getItem(getStorageKey(projectId));
2026-03-15 18:11:26 +08:00
if (!raw) return [];
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed)) return [];
return parsed
.filter((item): item is ChartConfig => Boolean(item?.id && item?.layout))
.map((item) => ({
...item,
layout: {
i: item.layout.i,
x: Number.isFinite(item.layout.x) ? item.layout.x : 0,
y: Number.isFinite(item.layout.y) ? item.layout.y : 0,
w: Number.isFinite(item.layout.w) ? item.layout.w : 4,
h: Number.isFinite(item.layout.h) ? item.layout.h : 4,
},
}));
} catch {
return [];
}
}
2026-03-16 16:12:35 +08:00
function saveChartsToStorage(charts: ChartConfig[], projectId: number) {
2026-03-15 18:11:26 +08:00
if (typeof window === 'undefined') return;
2026-03-16 16:12:35 +08:00
window.localStorage.setItem(getStorageKey(projectId), JSON.stringify(charts));
2026-03-15 18:11:26 +08:00
}
2026-03-16 16:12:35 +08:00
export const useDashboardStore = create<DashboardState>((set, get) => ({
charts: [],
loadCharts: (projectId) => {
set({ charts: loadChartsFromStorage(projectId) });
},
addChart: (chart, projectId) => set((state) => {
2026-03-15 18:11:26 +08:00
const colSize = 4;
const cols = 12 / colSize;
const index = state.charts.length;
2026-03-14 15:52:27 +08:00
const newLayout: GridLayout = {
i: chart.id,
2026-03-15 18:11:26 +08:00
x: (index % cols) * colSize,
y: Math.floor(index / cols) * 4,
w: colSize,
2026-03-15 18:04:23 +08:00
h: 4,
2026-03-14 15:52:27 +08:00
};
2026-03-15 18:11:26 +08:00
const nextCharts = [...state.charts, { ...chart, layout: newLayout }];
2026-03-16 16:12:35 +08:00
saveChartsToStorage(nextCharts, projectId);
return { charts: nextCharts };
}),
removeChart: (id, projectId) => set((state) => {
const nextCharts = state.charts.filter((c) => c.id !== id);
saveChartsToStorage(nextCharts, projectId);
2026-03-15 18:11:26 +08:00
return { charts: nextCharts };
2026-03-14 15:52:27 +08:00
}),
2026-03-16 16:12:35 +08:00
updateLayout: (layouts, projectId) => set((state) => {
2026-03-15 18:11:26 +08:00
const nextCharts = state.charts.map((chart) => {
2026-03-14 15:52:27 +08:00
const layout = layouts.find((l) => l.i === chart.id);
return layout ? { ...chart, layout } : chart;
2026-03-15 18:11:26 +08:00
});
2026-03-16 16:12:35 +08:00
saveChartsToStorage(nextCharts, projectId);
2026-03-15 18:11:26 +08:00
return { charts: nextCharts };
}),
2026-03-14 15:52:27 +08:00
}));