widgettdc-api / apps /matrix-frontend /src /hooks /useDashboardSnapshots.ts
Kraft102's picture
fix: sql.js Docker/Alpine compatibility layer for PatternMemory and FailureMemory
5a81b95
import { useState, useEffect, useCallback } from 'react';
import { saveSnapshot, getSnapshots, deleteSnapshot } from '@/lib/indexedDB';
import { DashboardWidget } from '@/pages/Dashboard';
import { toast } from '@/hooks/use-toast';
export interface DashboardSnapshot {
id: string;
dashboardId: string;
name: string;
data: {
widgets: DashboardWidget[];
filters?: any;
timestamp: number;
};
createdAt: number;
}
export function useDashboardSnapshots(dashboardId: string = 'default') {
const [snapshots, setSnapshots] = useState<DashboardSnapshot[]>([]);
const [isLoading, setIsLoading] = useState(true);
const loadSnapshots = useCallback(async () => {
try {
const loaded = await getSnapshots(dashboardId);
setSnapshots(loaded.sort((a, b) => b.createdAt - a.createdAt));
} catch (e) {
console.error('Failed to load snapshots:', e);
} finally {
setIsLoading(false);
}
}, [dashboardId]);
useEffect(() => {
loadSnapshots();
}, [loadSnapshots]);
const createSnapshot = useCallback(async (
name: string,
widgets: DashboardWidget[],
filters?: any
): Promise<DashboardSnapshot> => {
const snapshot: DashboardSnapshot = {
id: `snapshot-${Date.now()}`,
dashboardId,
name,
data: {
widgets: widgets.map(w => ({ ...w })),
filters,
timestamp: Date.now(),
},
createdAt: Date.now(),
};
await saveSnapshot(snapshot);
setSnapshots(prev => [snapshot, ...prev]);
toast({
title: "Snapshot Created",
description: `"${name}" has been saved`,
});
return snapshot;
}, [dashboardId]);
const removeSnapshot = useCallback(async (snapshotId: string) => {
await deleteSnapshot(snapshotId);
setSnapshots(prev => prev.filter(s => s.id !== snapshotId));
toast({
title: "Snapshot Deleted",
description: "Snapshot has been removed",
});
}, []);
const restoreSnapshot = useCallback((snapshotId: string): DashboardWidget[] | null => {
const snapshot = snapshots.find(s => s.id === snapshotId);
if (!snapshot) return null;
toast({
title: "Snapshot Restored",
description: `Restored "${snapshot.name}"`,
});
return snapshot.data.widgets.map(w => ({
...w,
id: `widget-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
}));
}, [snapshots]);
const compareSnapshots = useCallback((id1: string, id2: string) => {
const snap1 = snapshots.find(s => s.id === id1);
const snap2 = snapshots.find(s => s.id === id2);
if (!snap1 || !snap2) return null;
const widgets1 = new Set(snap1.data.widgets.map(w => w.type));
const widgets2 = new Set(snap2.data.widgets.map(w => w.type));
const added = [...widgets2].filter(w => !widgets1.has(w));
const removed = [...widgets1].filter(w => !widgets2.has(w));
const unchanged = [...widgets1].filter(w => widgets2.has(w));
return {
added,
removed,
unchanged,
countDiff: snap2.data.widgets.length - snap1.data.widgets.length,
};
}, [snapshots]);
return {
snapshots,
isLoading,
createSnapshot,
removeSnapshot,
restoreSnapshot,
compareSnapshots,
refreshSnapshots: loadSnapshots,
};
}