mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 15:53:42 +00:00
fix: remove unused variable
This commit is contained in:
parent
0bd9a94337
commit
79bfd525dd
1 changed files with 257 additions and 243 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import { create } from 'zustand';
|
import { create } from "zustand";
|
||||||
import type { ConstellationDocument } from './persistence/types';
|
import type { ConstellationDocument } from "./persistence/types";
|
||||||
import { useGraphStore } from './graphStore';
|
import { useGraphStore } from "./graphStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* History Store - Per-Document Undo/Redo System
|
* History Store - Per-Document Undo/Redo System
|
||||||
|
|
@ -12,14 +12,14 @@ import { useGraphStore } from './graphStore';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface HistoryAction {
|
export interface HistoryAction {
|
||||||
description: string; // Human-readable description (e.g., "Add Person Actor", "Delete Collaborates Relation")
|
description: string; // Human-readable description (e.g., "Add Person Actor", "Delete Collaborates Relation")
|
||||||
timestamp: number; // When the action occurred
|
timestamp: number; // When the action occurred
|
||||||
documentState: ConstellationDocument; // Complete document state after this action
|
documentState: ConstellationDocument; // Complete document state after this action
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DocumentHistory {
|
export interface DocumentHistory {
|
||||||
undoStack: HistoryAction[]; // Past states to restore (most recent at end)
|
undoStack: HistoryAction[]; // Past states to restore (most recent at end)
|
||||||
redoStack: HistoryAction[]; // Future states to restore (most recent at end)
|
redoStack: HistoryAction[]; // Future states to restore (most recent at end)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HistoryStore {
|
interface HistoryStore {
|
||||||
|
|
@ -32,7 +32,10 @@ interface HistoryStore {
|
||||||
|
|
||||||
interface HistoryActions {
|
interface HistoryActions {
|
||||||
// Initialize history for a document
|
// Initialize history for a document
|
||||||
initializeHistory: (documentId: string, initialState: ConstellationDocument) => void;
|
initializeHistory: (
|
||||||
|
documentId: string,
|
||||||
|
initialState: ConstellationDocument,
|
||||||
|
) => void;
|
||||||
|
|
||||||
// Push a new action onto the document's history stack
|
// Push a new action onto the document's history stack
|
||||||
pushAction: (documentId: string, action: HistoryAction) => void;
|
pushAction: (documentId: string, action: HistoryAction) => void;
|
||||||
|
|
@ -70,264 +73,275 @@ interface HistoryActions {
|
||||||
|
|
||||||
const MAX_HISTORY_SIZE = 50;
|
const MAX_HISTORY_SIZE = 50;
|
||||||
|
|
||||||
export const useHistoryStore = create<HistoryStore & HistoryActions>((set, get) => ({
|
export const useHistoryStore = create<HistoryStore & HistoryActions>(
|
||||||
histories: new Map(),
|
(set, get) => ({
|
||||||
maxHistorySize: MAX_HISTORY_SIZE,
|
histories: new Map(),
|
||||||
|
maxHistorySize: MAX_HISTORY_SIZE,
|
||||||
|
|
||||||
initializeHistory: (documentId: string, _initialState: ConstellationDocument) => {
|
initializeHistory: (documentId: string) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const newHistories = new Map(state.histories);
|
const newHistories = new Map(state.histories);
|
||||||
|
|
||||||
// Only initialize if not already present
|
// Only initialize if not already present
|
||||||
if (!newHistories.has(documentId)) {
|
if (!newHistories.has(documentId)) {
|
||||||
newHistories.set(documentId, {
|
newHistories.set(documentId, {
|
||||||
undoStack: [],
|
undoStack: [],
|
||||||
redoStack: [],
|
redoStack: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { histories: newHistories };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
pushAction: (documentId: string, action: HistoryAction) => {
|
||||||
|
set((state) => {
|
||||||
|
const newHistories = new Map(state.histories);
|
||||||
|
const history = newHistories.get(documentId);
|
||||||
|
|
||||||
|
if (!history) {
|
||||||
|
console.warn(`History not initialized for document ${documentId}`);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("📝 pushAction:", {
|
||||||
|
description: action.description,
|
||||||
|
actionStateNodes: action.documentState.graph.nodes.length,
|
||||||
|
actionStateEdges: action.documentState.graph.edges.length,
|
||||||
|
currentUndoStackSize: history.undoStack.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The action.documentState contains the state BEFORE the action was performed
|
||||||
|
// We push this to the undo stack so we can restore it if the user clicks undo
|
||||||
|
const newUndoStack = [...history.undoStack];
|
||||||
|
newUndoStack.push({
|
||||||
|
description: action.description,
|
||||||
|
timestamp: action.timestamp,
|
||||||
|
documentState: JSON.parse(JSON.stringify(action.documentState)), // Deep copy
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trim undo stack if it exceeds max size
|
||||||
|
if (newUndoStack.length > state.maxHistorySize) {
|
||||||
|
newUndoStack.shift(); // Remove oldest
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear redo stack when a new action is performed (can't redo after new action)
|
||||||
|
const newRedoStack: HistoryAction[] = [];
|
||||||
|
|
||||||
|
newHistories.set(documentId, {
|
||||||
|
undoStack: newUndoStack,
|
||||||
|
redoStack: newRedoStack,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("📝 after push:", {
|
||||||
|
description: action.description,
|
||||||
|
newUndoStackSize: newUndoStack.length,
|
||||||
|
topOfStackNodes:
|
||||||
|
newUndoStack[newUndoStack.length - 1]?.documentState.graph.nodes
|
||||||
|
.length,
|
||||||
|
topOfStackEdges:
|
||||||
|
newUndoStack[newUndoStack.length - 1]?.documentState.graph.edges
|
||||||
|
.length,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { histories: newHistories };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
undo: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
|
||||||
|
if (!history || history.undoStack.length === 0) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { histories: newHistories };
|
console.log("⏪ undo:", {
|
||||||
});
|
description:
|
||||||
},
|
history.undoStack[history.undoStack.length - 1].description,
|
||||||
|
undoStackSize: history.undoStack.length,
|
||||||
|
});
|
||||||
|
|
||||||
pushAction: (documentId: string, action: HistoryAction) => {
|
|
||||||
set((state) => {
|
|
||||||
const newHistories = new Map(state.histories);
|
const newHistories = new Map(state.histories);
|
||||||
const history = newHistories.get(documentId);
|
|
||||||
|
|
||||||
if (!history) {
|
// Pop the last action from undo stack - this is the state BEFORE the action
|
||||||
console.warn(`History not initialized for document ${documentId}`);
|
const lastAction = history.undoStack[history.undoStack.length - 1];
|
||||||
return {};
|
const newUndoStack = history.undoStack.slice(0, -1);
|
||||||
}
|
|
||||||
|
|
||||||
console.log('📝 pushAction:', {
|
// Get current state from graphStore and push it to redo stack
|
||||||
description: action.description,
|
const currentGraphState = useGraphStore.getState();
|
||||||
actionStateNodes: action.documentState.graph.nodes.length,
|
const currentStateSnapshot = {
|
||||||
actionStateEdges: action.documentState.graph.edges.length,
|
graph: {
|
||||||
currentUndoStackSize: history.undoStack.length,
|
nodes: currentGraphState.nodes,
|
||||||
|
edges: currentGraphState.edges,
|
||||||
|
nodeTypes: currentGraphState.nodeTypes,
|
||||||
|
edgeTypes: currentGraphState.edgeTypes,
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
version: "1.0" as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newRedoStack = [...history.redoStack];
|
||||||
|
newRedoStack.push({
|
||||||
|
description: lastAction.description,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
documentState: JSON.parse(JSON.stringify(currentStateSnapshot)), // Deep copy
|
||||||
});
|
});
|
||||||
|
|
||||||
// The action.documentState contains the state BEFORE the action was performed
|
// Restore the previous state (deep copy)
|
||||||
// We push this to the undo stack so we can restore it if the user clicks undo
|
const restoredState = JSON.parse(
|
||||||
const newUndoStack = [...history.undoStack];
|
JSON.stringify(lastAction.documentState),
|
||||||
newUndoStack.push({
|
);
|
||||||
description: action.description,
|
|
||||||
timestamp: action.timestamp,
|
console.log("⏪ after undo:", {
|
||||||
documentState: JSON.parse(JSON.stringify(action.documentState)), // Deep copy
|
restoredStateNodes: restoredState.graph.nodes.length,
|
||||||
|
restoredStateEdges: restoredState.graph.edges.length,
|
||||||
|
undoStackSize: newUndoStack.length,
|
||||||
|
redoStackSize: newRedoStack.length,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trim undo stack if it exceeds max size
|
|
||||||
if (newUndoStack.length > state.maxHistorySize) {
|
|
||||||
newUndoStack.shift(); // Remove oldest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear redo stack when a new action is performed (can't redo after new action)
|
|
||||||
const newRedoStack: HistoryAction[] = [];
|
|
||||||
|
|
||||||
newHistories.set(documentId, {
|
newHistories.set(documentId, {
|
||||||
undoStack: newUndoStack,
|
undoStack: newUndoStack,
|
||||||
redoStack: newRedoStack,
|
redoStack: newRedoStack,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('📝 after push:', {
|
set({ histories: newHistories });
|
||||||
description: action.description,
|
|
||||||
newUndoStackSize: newUndoStack.length,
|
|
||||||
topOfStackNodes: newUndoStack[newUndoStack.length - 1]?.documentState.graph.nodes.length,
|
|
||||||
topOfStackEdges: newUndoStack[newUndoStack.length - 1]?.documentState.graph.edges.length,
|
|
||||||
});
|
|
||||||
|
|
||||||
return { histories: newHistories };
|
return restoredState;
|
||||||
});
|
},
|
||||||
},
|
|
||||||
|
|
||||||
undo: (documentId: string) => {
|
redo: (documentId: string) => {
|
||||||
const state = get();
|
const state = get();
|
||||||
const history = state.histories.get(documentId);
|
const history = state.histories.get(documentId);
|
||||||
|
|
||||||
if (!history || history.undoStack.length === 0) {
|
if (!history || history.redoStack.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
console.log('⏪ undo:', {
|
|
||||||
description: history.undoStack[history.undoStack.length - 1].description,
|
|
||||||
undoStackSize: history.undoStack.length,
|
|
||||||
});
|
|
||||||
|
|
||||||
const newHistories = new Map(state.histories);
|
|
||||||
|
|
||||||
// Pop the last action from undo stack - this is the state BEFORE the action
|
|
||||||
const lastAction = history.undoStack[history.undoStack.length - 1];
|
|
||||||
const newUndoStack = history.undoStack.slice(0, -1);
|
|
||||||
|
|
||||||
// Get current state from graphStore and push it to redo stack
|
|
||||||
const currentGraphState = useGraphStore.getState();
|
|
||||||
const currentStateSnapshot = {
|
|
||||||
graph: {
|
|
||||||
nodes: currentGraphState.nodes,
|
|
||||||
edges: currentGraphState.edges,
|
|
||||||
nodeTypes: currentGraphState.nodeTypes,
|
|
||||||
edgeTypes: currentGraphState.edgeTypes,
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
updatedAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
version: '1.0' as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newRedoStack = [...history.redoStack];
|
|
||||||
newRedoStack.push({
|
|
||||||
description: lastAction.description,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
documentState: JSON.parse(JSON.stringify(currentStateSnapshot)), // Deep copy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Restore the previous state (deep copy)
|
|
||||||
const restoredState = JSON.parse(JSON.stringify(lastAction.documentState));
|
|
||||||
|
|
||||||
console.log('⏪ after undo:', {
|
|
||||||
restoredStateNodes: restoredState.graph.nodes.length,
|
|
||||||
restoredStateEdges: restoredState.graph.edges.length,
|
|
||||||
undoStackSize: newUndoStack.length,
|
|
||||||
redoStackSize: newRedoStack.length,
|
|
||||||
});
|
|
||||||
|
|
||||||
newHistories.set(documentId, {
|
|
||||||
undoStack: newUndoStack,
|
|
||||||
redoStack: newRedoStack,
|
|
||||||
});
|
|
||||||
|
|
||||||
set({ histories: newHistories });
|
|
||||||
|
|
||||||
return restoredState;
|
|
||||||
},
|
|
||||||
|
|
||||||
redo: (documentId: string) => {
|
|
||||||
const state = get();
|
|
||||||
const history = state.histories.get(documentId);
|
|
||||||
|
|
||||||
if (!history || history.redoStack.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newHistories = new Map(state.histories);
|
|
||||||
|
|
||||||
// Pop the last action from redo stack
|
|
||||||
const lastAction = history.redoStack[history.redoStack.length - 1];
|
|
||||||
const newRedoStack = history.redoStack.slice(0, -1);
|
|
||||||
|
|
||||||
// Get current state from graphStore and push it to undo stack
|
|
||||||
const currentGraphState = useGraphStore.getState();
|
|
||||||
const currentStateSnapshot = {
|
|
||||||
graph: {
|
|
||||||
nodes: currentGraphState.nodes,
|
|
||||||
edges: currentGraphState.edges,
|
|
||||||
nodeTypes: currentGraphState.nodeTypes,
|
|
||||||
edgeTypes: currentGraphState.edgeTypes,
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
updatedAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
version: '1.0' as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newUndoStack = [...history.undoStack];
|
|
||||||
newUndoStack.push({
|
|
||||||
description: lastAction.description,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
documentState: JSON.parse(JSON.stringify(currentStateSnapshot)), // Deep copy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Trim if exceeds max size
|
|
||||||
if (newUndoStack.length > state.maxHistorySize) {
|
|
||||||
newUndoStack.shift(); // Remove oldest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the future state (deep copy)
|
|
||||||
const restoredState = JSON.parse(JSON.stringify(lastAction.documentState));
|
|
||||||
|
|
||||||
newHistories.set(documentId, {
|
|
||||||
undoStack: newUndoStack,
|
|
||||||
redoStack: newRedoStack,
|
|
||||||
});
|
|
||||||
|
|
||||||
set({ histories: newHistories });
|
|
||||||
|
|
||||||
return restoredState;
|
|
||||||
},
|
|
||||||
|
|
||||||
canUndo: (documentId: string) => {
|
|
||||||
const state = get();
|
|
||||||
const history = state.histories.get(documentId);
|
|
||||||
return history ? history.undoStack.length > 0 : false;
|
|
||||||
},
|
|
||||||
|
|
||||||
canRedo: (documentId: string) => {
|
|
||||||
const state = get();
|
|
||||||
const history = state.histories.get(documentId);
|
|
||||||
return history ? history.redoStack.length > 0 : false;
|
|
||||||
},
|
|
||||||
|
|
||||||
getUndoDescription: (documentId: string) => {
|
|
||||||
const state = get();
|
|
||||||
const history = state.histories.get(documentId);
|
|
||||||
|
|
||||||
if (!history || history.undoStack.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastAction = history.undoStack[history.undoStack.length - 1];
|
|
||||||
return lastAction.description;
|
|
||||||
},
|
|
||||||
|
|
||||||
getRedoDescription: (documentId: string) => {
|
|
||||||
const state = get();
|
|
||||||
const history = state.histories.get(documentId);
|
|
||||||
|
|
||||||
if (!history || history.redoStack.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastAction = history.redoStack[history.redoStack.length - 1];
|
|
||||||
return lastAction.description;
|
|
||||||
},
|
|
||||||
|
|
||||||
clearHistory: (documentId: string) => {
|
|
||||||
set((state) => {
|
|
||||||
const newHistories = new Map(state.histories);
|
|
||||||
const history = newHistories.get(documentId);
|
|
||||||
|
|
||||||
if (history) {
|
|
||||||
newHistories.set(documentId, {
|
|
||||||
undoStack: [],
|
|
||||||
redoStack: [],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { histories: newHistories };
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
removeHistory: (documentId: string) => {
|
|
||||||
set((state) => {
|
|
||||||
const newHistories = new Map(state.histories);
|
const newHistories = new Map(state.histories);
|
||||||
newHistories.delete(documentId);
|
|
||||||
return { histories: newHistories };
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getHistoryStats: (documentId: string) => {
|
// Pop the last action from redo stack
|
||||||
const state = get();
|
const lastAction = history.redoStack[history.redoStack.length - 1];
|
||||||
const history = state.histories.get(documentId);
|
const newRedoStack = history.redoStack.slice(0, -1);
|
||||||
|
|
||||||
if (!history) {
|
// Get current state from graphStore and push it to undo stack
|
||||||
return null;
|
const currentGraphState = useGraphStore.getState();
|
||||||
}
|
const currentStateSnapshot = {
|
||||||
|
graph: {
|
||||||
|
nodes: currentGraphState.nodes,
|
||||||
|
edges: currentGraphState.edges,
|
||||||
|
nodeTypes: currentGraphState.nodeTypes,
|
||||||
|
edgeTypes: currentGraphState.edgeTypes,
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
version: "1.0" as const,
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
const newUndoStack = [...history.undoStack];
|
||||||
undoCount: history.undoStack.length,
|
newUndoStack.push({
|
||||||
redoCount: history.redoStack.length,
|
description: lastAction.description,
|
||||||
};
|
timestamp: Date.now(),
|
||||||
},
|
documentState: JSON.parse(JSON.stringify(currentStateSnapshot)), // Deep copy
|
||||||
}));
|
});
|
||||||
|
|
||||||
|
// Trim if exceeds max size
|
||||||
|
if (newUndoStack.length > state.maxHistorySize) {
|
||||||
|
newUndoStack.shift(); // Remove oldest
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the future state (deep copy)
|
||||||
|
const restoredState = JSON.parse(
|
||||||
|
JSON.stringify(lastAction.documentState),
|
||||||
|
);
|
||||||
|
|
||||||
|
newHistories.set(documentId, {
|
||||||
|
undoStack: newUndoStack,
|
||||||
|
redoStack: newRedoStack,
|
||||||
|
});
|
||||||
|
|
||||||
|
set({ histories: newHistories });
|
||||||
|
|
||||||
|
return restoredState;
|
||||||
|
},
|
||||||
|
|
||||||
|
canUndo: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
return history ? history.undoStack.length > 0 : false;
|
||||||
|
},
|
||||||
|
|
||||||
|
canRedo: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
return history ? history.redoStack.length > 0 : false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUndoDescription: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
|
||||||
|
if (!history || history.undoStack.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastAction = history.undoStack[history.undoStack.length - 1];
|
||||||
|
return lastAction.description;
|
||||||
|
},
|
||||||
|
|
||||||
|
getRedoDescription: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
|
||||||
|
if (!history || history.redoStack.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastAction = history.redoStack[history.redoStack.length - 1];
|
||||||
|
return lastAction.description;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearHistory: (documentId: string) => {
|
||||||
|
set((state) => {
|
||||||
|
const newHistories = new Map(state.histories);
|
||||||
|
const history = newHistories.get(documentId);
|
||||||
|
|
||||||
|
if (history) {
|
||||||
|
newHistories.set(documentId, {
|
||||||
|
undoStack: [],
|
||||||
|
redoStack: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { histories: newHistories };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeHistory: (documentId: string) => {
|
||||||
|
set((state) => {
|
||||||
|
const newHistories = new Map(state.histories);
|
||||||
|
newHistories.delete(documentId);
|
||||||
|
return { histories: newHistories };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getHistoryStats: (documentId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const history = state.histories.get(documentId);
|
||||||
|
|
||||||
|
if (!history) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
undoCount: history.undoStack.length,
|
||||||
|
redoCount: history.redoStack.length,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue