mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +00:00
refactor: establish document as source of truth for node/edge types
Refactors the type management system to properly follow the Workspace→Document→Timeline→Graph hierarchy, where nodeTypes and edgeTypes are owned by the document rather than being independent state in graphStore. Changes: - Add type management actions to workspaceStore (document-level) - Update workspaceStore.saveDocument to stop copying types from graphStore - Modify useActiveDocument to only track node/edge changes for dirty state - Update useGraphWithHistory to route type operations through workspaceStore - Update useDocumentHistory to read/restore types from document Architecture: - Document: Source of truth for types (persistent storage) - graphStore: Synchronized working memory (optimized for React Flow) - useActiveDocument: Bridge that syncs document → graphStore - Type mutations: Always go through workspaceStore, then sync to graphStore This ensures proper data ownership while maintaining graphStore as a performance optimization layer for the UI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5275b52f0a
commit
89117415ed
5 changed files with 248 additions and 31 deletions
|
|
@ -47,7 +47,8 @@ export function useDocumentHistory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current state from stores
|
// Get current state from stores
|
||||||
const graphStore = useGraphStore.getState();
|
const workspaceStore = useWorkspaceStore.getState();
|
||||||
|
const activeDoc = workspaceStore.getActiveDocument();
|
||||||
const timelineStore = useTimelineStore.getState();
|
const timelineStore = useTimelineStore.getState();
|
||||||
const timeline = timelineStore.timelines.get(activeDocumentId);
|
const timeline = timelineStore.timelines.get(activeDocumentId);
|
||||||
|
|
||||||
|
|
@ -56,15 +57,21 @@ export function useDocumentHistory() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!activeDoc) {
|
||||||
|
console.warn('Active document not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a snapshot of the complete document state
|
// Create a snapshot of the complete document state
|
||||||
|
// NOTE: Read types from the document, not from graphStore
|
||||||
const snapshot: DocumentSnapshot = {
|
const snapshot: DocumentSnapshot = {
|
||||||
timeline: {
|
timeline: {
|
||||||
states: new Map(timeline.states), // Clone the Map
|
states: new Map(timeline.states), // Clone the Map
|
||||||
currentStateId: timeline.currentStateId,
|
currentStateId: timeline.currentStateId,
|
||||||
rootStateId: timeline.rootStateId,
|
rootStateId: timeline.rootStateId,
|
||||||
},
|
},
|
||||||
nodeTypes: graphStore.nodeTypes,
|
nodeTypes: activeDoc.nodeTypes,
|
||||||
edgeTypes: graphStore.edgeTypes,
|
edgeTypes: activeDoc.edgeTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Push to history
|
// Push to history
|
||||||
|
|
@ -87,7 +94,8 @@ export function useDocumentHistory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture current state BEFORE undoing
|
// Capture current state BEFORE undoing
|
||||||
const graphStore = useGraphStore.getState();
|
const workspaceStore = useWorkspaceStore.getState();
|
||||||
|
const activeDoc = workspaceStore.getActiveDocument();
|
||||||
const timelineStore = useTimelineStore.getState();
|
const timelineStore = useTimelineStore.getState();
|
||||||
const timeline = timelineStore.timelines.get(activeDocumentId);
|
const timeline = timelineStore.timelines.get(activeDocumentId);
|
||||||
|
|
||||||
|
|
@ -96,14 +104,20 @@ export function useDocumentHistory() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!activeDoc) {
|
||||||
|
console.warn('Active document not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Read types from the document, not from graphStore
|
||||||
const currentSnapshot: DocumentSnapshot = {
|
const currentSnapshot: DocumentSnapshot = {
|
||||||
timeline: {
|
timeline: {
|
||||||
states: new Map(timeline.states),
|
states: new Map(timeline.states),
|
||||||
currentStateId: timeline.currentStateId,
|
currentStateId: timeline.currentStateId,
|
||||||
rootStateId: timeline.rootStateId,
|
rootStateId: timeline.rootStateId,
|
||||||
},
|
},
|
||||||
nodeTypes: graphStore.nodeTypes,
|
nodeTypes: activeDoc.nodeTypes,
|
||||||
edgeTypes: graphStore.edgeTypes,
|
edgeTypes: activeDoc.edgeTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
const restoredState = historyStore.undo(activeDocumentId, currentSnapshot);
|
const restoredState = historyStore.undo(activeDocumentId, currentSnapshot);
|
||||||
|
|
@ -112,7 +126,11 @@ export function useDocumentHistory() {
|
||||||
// Restore complete document state (timeline + types)
|
// Restore complete document state (timeline + types)
|
||||||
timelineStore.loadTimeline(activeDocumentId, restoredState.timeline);
|
timelineStore.loadTimeline(activeDocumentId, restoredState.timeline);
|
||||||
|
|
||||||
// Update graph store types
|
// Update document's types (which will sync to graphStore via workspaceStore)
|
||||||
|
activeDoc.nodeTypes = restoredState.nodeTypes;
|
||||||
|
activeDoc.edgeTypes = restoredState.edgeTypes;
|
||||||
|
|
||||||
|
// Sync to graph store
|
||||||
setNodeTypes(restoredState.nodeTypes);
|
setNodeTypes(restoredState.nodeTypes);
|
||||||
setEdgeTypes(restoredState.edgeTypes);
|
setEdgeTypes(restoredState.edgeTypes);
|
||||||
|
|
||||||
|
|
@ -146,7 +164,8 @@ export function useDocumentHistory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture current state BEFORE redoing
|
// Capture current state BEFORE redoing
|
||||||
const graphStore = useGraphStore.getState();
|
const workspaceStore = useWorkspaceStore.getState();
|
||||||
|
const activeDoc = workspaceStore.getActiveDocument();
|
||||||
const timelineStore = useTimelineStore.getState();
|
const timelineStore = useTimelineStore.getState();
|
||||||
const timeline = timelineStore.timelines.get(activeDocumentId);
|
const timeline = timelineStore.timelines.get(activeDocumentId);
|
||||||
|
|
||||||
|
|
@ -155,14 +174,20 @@ export function useDocumentHistory() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!activeDoc) {
|
||||||
|
console.warn('Active document not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Read types from the document, not from graphStore
|
||||||
const currentSnapshot: DocumentSnapshot = {
|
const currentSnapshot: DocumentSnapshot = {
|
||||||
timeline: {
|
timeline: {
|
||||||
states: new Map(timeline.states),
|
states: new Map(timeline.states),
|
||||||
currentStateId: timeline.currentStateId,
|
currentStateId: timeline.currentStateId,
|
||||||
rootStateId: timeline.rootStateId,
|
rootStateId: timeline.rootStateId,
|
||||||
},
|
},
|
||||||
nodeTypes: graphStore.nodeTypes,
|
nodeTypes: activeDoc.nodeTypes,
|
||||||
edgeTypes: graphStore.edgeTypes,
|
edgeTypes: activeDoc.edgeTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
const restoredState = historyStore.redo(activeDocumentId, currentSnapshot);
|
const restoredState = historyStore.redo(activeDocumentId, currentSnapshot);
|
||||||
|
|
@ -171,7 +196,11 @@ export function useDocumentHistory() {
|
||||||
// Restore complete document state (timeline + types)
|
// Restore complete document state (timeline + types)
|
||||||
timelineStore.loadTimeline(activeDocumentId, restoredState.timeline);
|
timelineStore.loadTimeline(activeDocumentId, restoredState.timeline);
|
||||||
|
|
||||||
// Update graph store types
|
// Update document's types (which will sync to graphStore via workspaceStore)
|
||||||
|
activeDoc.nodeTypes = restoredState.nodeTypes;
|
||||||
|
activeDoc.edgeTypes = restoredState.edgeTypes;
|
||||||
|
|
||||||
|
// Sync to graph store
|
||||||
setNodeTypes(restoredState.nodeTypes);
|
setNodeTypes(restoredState.nodeTypes);
|
||||||
setEdgeTypes(restoredState.edgeTypes);
|
setEdgeTypes(restoredState.edgeTypes);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useCallback, useRef, useEffect } from 'react';
|
import { useCallback, useRef, useEffect } from 'react';
|
||||||
import { useGraphStore } from '../stores/graphStore';
|
import { useGraphStore } from '../stores/graphStore';
|
||||||
|
import { useWorkspaceStore } from '../stores/workspaceStore';
|
||||||
import { useDocumentHistory } from './useDocumentHistory';
|
import { useDocumentHistory } from './useDocumentHistory';
|
||||||
import type { Actor, Relation, NodeTypeConfig, EdgeTypeConfig, RelationData } from '../types';
|
import type { Actor, Relation, NodeTypeConfig, EdgeTypeConfig, RelationData } from '../types';
|
||||||
|
|
||||||
|
|
@ -38,6 +39,13 @@ import type { Actor, Relation, NodeTypeConfig, EdgeTypeConfig, RelationData } fr
|
||||||
*/
|
*/
|
||||||
export function useGraphWithHistory() {
|
export function useGraphWithHistory() {
|
||||||
const graphStore = useGraphStore();
|
const graphStore = useGraphStore();
|
||||||
|
const activeDocumentId = useWorkspaceStore((state) => state.activeDocumentId);
|
||||||
|
const addNodeTypeToDocument = useWorkspaceStore((state) => state.addNodeTypeToDocument);
|
||||||
|
const updateNodeTypeInDocument = useWorkspaceStore((state) => state.updateNodeTypeInDocument);
|
||||||
|
const deleteNodeTypeFromDocument = useWorkspaceStore((state) => state.deleteNodeTypeFromDocument);
|
||||||
|
const addEdgeTypeToDocument = useWorkspaceStore((state) => state.addEdgeTypeToDocument);
|
||||||
|
const updateEdgeTypeInDocument = useWorkspaceStore((state) => state.updateEdgeTypeInDocument);
|
||||||
|
const deleteEdgeTypeFromDocument = useWorkspaceStore((state) => state.deleteEdgeTypeFromDocument);
|
||||||
const { pushToHistory } = useDocumentHistory();
|
const { pushToHistory } = useDocumentHistory();
|
||||||
|
|
||||||
// Track if we're currently restoring from history to prevent recursive history pushes
|
// Track if we're currently restoring from history to prevent recursive history pushes
|
||||||
|
|
@ -169,76 +177,100 @@ export function useGraphWithHistory() {
|
||||||
|
|
||||||
const addNodeType = useCallback(
|
const addNodeType = useCallback(
|
||||||
(nodeType: NodeTypeConfig) => {
|
(nodeType: NodeTypeConfig) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.addNodeType(nodeType);
|
graphStore.addNodeType(nodeType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushToHistory(`Add Node Type: ${nodeType.label}`); // Synchronous push BEFORE mutation
|
pushToHistory(`Add Node Type: ${nodeType.label}`); // Synchronous push BEFORE mutation
|
||||||
graphStore.addNodeType(nodeType);
|
addNodeTypeToDocument(activeDocumentId, nodeType);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, addNodeTypeToDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateNodeType = useCallback(
|
const updateNodeType = useCallback(
|
||||||
(id: string, updates: Partial<Omit<NodeTypeConfig, 'id'>>) => {
|
(id: string, updates: Partial<Omit<NodeTypeConfig, 'id'>>) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.updateNodeType(id, updates);
|
graphStore.updateNodeType(id, updates);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushToHistory('Update Node Type'); // Synchronous push BEFORE mutation
|
pushToHistory('Update Node Type'); // Synchronous push BEFORE mutation
|
||||||
graphStore.updateNodeType(id, updates);
|
updateNodeTypeInDocument(activeDocumentId, id, updates);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, updateNodeTypeInDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteNodeType = useCallback(
|
const deleteNodeType = useCallback(
|
||||||
(id: string) => {
|
(id: string) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.deleteNodeType(id);
|
graphStore.deleteNodeType(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nodeType = graphStore.nodeTypes.find((nt) => nt.id === id);
|
const nodeType = graphStore.nodeTypes.find((nt) => nt.id === id);
|
||||||
pushToHistory(`Delete Node Type: ${nodeType?.label || id}`); // Synchronous push BEFORE mutation
|
pushToHistory(`Delete Node Type: ${nodeType?.label || id}`); // Synchronous push BEFORE mutation
|
||||||
graphStore.deleteNodeType(id);
|
deleteNodeTypeFromDocument(activeDocumentId, id);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, deleteNodeTypeFromDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const addEdgeType = useCallback(
|
const addEdgeType = useCallback(
|
||||||
(edgeType: EdgeTypeConfig) => {
|
(edgeType: EdgeTypeConfig) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.addEdgeType(edgeType);
|
graphStore.addEdgeType(edgeType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushToHistory(`Add Edge Type: ${edgeType.label}`); // Synchronous push BEFORE mutation
|
pushToHistory(`Add Edge Type: ${edgeType.label}`); // Synchronous push BEFORE mutation
|
||||||
graphStore.addEdgeType(edgeType);
|
addEdgeTypeToDocument(activeDocumentId, edgeType);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, addEdgeTypeToDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateEdgeType = useCallback(
|
const updateEdgeType = useCallback(
|
||||||
(id: string, updates: Partial<Omit<EdgeTypeConfig, 'id'>>) => {
|
(id: string, updates: Partial<Omit<EdgeTypeConfig, 'id'>>) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.updateEdgeType(id, updates);
|
graphStore.updateEdgeType(id, updates);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pushToHistory('Update Edge Type'); // Synchronous push BEFORE mutation
|
pushToHistory('Update Edge Type'); // Synchronous push BEFORE mutation
|
||||||
graphStore.updateEdgeType(id, updates);
|
updateEdgeTypeInDocument(activeDocumentId, id, updates);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, updateEdgeTypeInDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteEdgeType = useCallback(
|
const deleteEdgeType = useCallback(
|
||||||
(id: string) => {
|
(id: string) => {
|
||||||
|
if (!activeDocumentId) {
|
||||||
|
console.warn('No active document');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isRestoringRef.current) {
|
if (isRestoringRef.current) {
|
||||||
graphStore.deleteEdgeType(id);
|
graphStore.deleteEdgeType(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const edgeType = graphStore.edgeTypes.find((et) => et.id === id);
|
const edgeType = graphStore.edgeTypes.find((et) => et.id === id);
|
||||||
pushToHistory(`Delete Edge Type: ${edgeType?.label || id}`); // Synchronous push BEFORE mutation
|
pushToHistory(`Delete Edge Type: ${edgeType?.label || id}`); // Synchronous push BEFORE mutation
|
||||||
graphStore.deleteEdgeType(id);
|
deleteEdgeTypeFromDocument(activeDocumentId, id);
|
||||||
},
|
},
|
||||||
[graphStore, pushToHistory]
|
[activeDocumentId, graphStore, pushToHistory, deleteEdgeTypeFromDocument]
|
||||||
);
|
);
|
||||||
|
|
||||||
const clearGraph = useCallback(
|
const clearGraph = useCallback(
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,14 @@ export interface WorkspaceActions {
|
||||||
markDocumentDirty: (documentId: string) => void;
|
markDocumentDirty: (documentId: string) => void;
|
||||||
saveDocument: (documentId: string) => void;
|
saveDocument: (documentId: string) => void;
|
||||||
|
|
||||||
|
// Type management (document-level)
|
||||||
|
addNodeTypeToDocument: (documentId: string, nodeType: NodeTypeConfig) => void;
|
||||||
|
updateNodeTypeInDocument: (documentId: string, typeId: string, updates: Partial<Omit<NodeTypeConfig, 'id'>>) => void;
|
||||||
|
deleteNodeTypeFromDocument: (documentId: string, typeId: string) => void;
|
||||||
|
addEdgeTypeToDocument: (documentId: string, edgeType: EdgeTypeConfig) => void;
|
||||||
|
updateEdgeTypeInDocument: (documentId: string, typeId: string, updates: Partial<Omit<EdgeTypeConfig, 'id'>>) => void;
|
||||||
|
deleteEdgeTypeFromDocument: (documentId: string, typeId: string) => void;
|
||||||
|
|
||||||
// Viewport operations
|
// Viewport operations
|
||||||
saveViewport: (documentId: string, viewport: { x: number; y: number; zoom: number }) => void;
|
saveViewport: (documentId: string, viewport: { x: number; y: number; zoom: number }) => void;
|
||||||
getViewport: (documentId: string) => { x: number; y: number; zoom: number } | undefined;
|
getViewport: (documentId: string) => { x: number; y: number; zoom: number } | undefined;
|
||||||
|
|
|
||||||
|
|
@ -143,17 +143,17 @@ export function useActiveDocument() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark document as dirty when graph changes
|
// Mark document as dirty when graph changes
|
||||||
|
// NOTE: We only track nodes/edges here. Type changes are handled by workspaceStore's
|
||||||
|
// type management actions, which directly mark the document as dirty.
|
||||||
const hasChanges =
|
const hasChanges =
|
||||||
JSON.stringify(graphNodes) !== JSON.stringify(lastSyncedStateRef.current.nodes) ||
|
JSON.stringify(graphNodes) !== JSON.stringify(lastSyncedStateRef.current.nodes) ||
|
||||||
JSON.stringify(graphEdges) !== JSON.stringify(lastSyncedStateRef.current.edges) ||
|
JSON.stringify(graphEdges) !== JSON.stringify(lastSyncedStateRef.current.edges);
|
||||||
JSON.stringify(graphNodeTypes) !== JSON.stringify(lastSyncedStateRef.current.nodeTypes) ||
|
|
||||||
JSON.stringify(graphEdgeTypes) !== JSON.stringify(lastSyncedStateRef.current.edgeTypes);
|
|
||||||
|
|
||||||
if (hasChanges) {
|
if (hasChanges) {
|
||||||
console.log(`Document ${activeDocumentId} has changes, marking as dirty`);
|
console.log(`Document ${activeDocumentId} has changes, marking as dirty`);
|
||||||
markDocumentDirty(activeDocumentId);
|
markDocumentDirty(activeDocumentId);
|
||||||
|
|
||||||
// Update the last synced state
|
// Update the last synced state (keep types for reference, but don't track them for changes)
|
||||||
lastSyncedStateRef.current = {
|
lastSyncedStateRef.current = {
|
||||||
documentId: activeDocumentId,
|
documentId: activeDocumentId,
|
||||||
nodes: graphNodes as Actor[],
|
nodes: graphNodes as Actor[],
|
||||||
|
|
|
||||||
|
|
@ -715,10 +715,9 @@ export const useWorkspaceStore = create<Workspace & WorkspaceActions>((set, get)
|
||||||
if (doc) {
|
if (doc) {
|
||||||
doc.metadata.updatedAt = new Date().toISOString();
|
doc.metadata.updatedAt = new Date().toISOString();
|
||||||
|
|
||||||
// Save global node and edge types from graph store
|
// NOTE: nodeTypes and edgeTypes are already part of the document structure
|
||||||
const graphStore = useGraphStore.getState();
|
// and are managed via workspaceStore's type management actions.
|
||||||
doc.nodeTypes = graphStore.nodeTypes;
|
// We do NOT copy them from graphStore because the document is the source of truth.
|
||||||
doc.edgeTypes = graphStore.edgeTypes;
|
|
||||||
|
|
||||||
// Save timeline data if exists
|
// Save timeline data if exists
|
||||||
const timelineState = useTimelineStore.getState();
|
const timelineState = useTimelineStore.getState();
|
||||||
|
|
@ -882,4 +881,153 @@ export const useWorkspaceStore = create<Workspace & WorkspaceActions>((set, get)
|
||||||
const metadata = state.documentMetadata.get(documentId);
|
const metadata = state.documentMetadata.get(documentId);
|
||||||
return metadata?.viewport;
|
return metadata?.viewport;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Type management - document-level operations
|
||||||
|
addNodeTypeToDocument: (documentId: string, nodeType) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to document's node types
|
||||||
|
doc.nodeTypes = [...doc.nodeTypes, nodeType];
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setNodeTypes(doc.nodeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateNodeTypeInDocument: (documentId: string, typeId: string, updates) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update in document's node types
|
||||||
|
doc.nodeTypes = doc.nodeTypes.map((type) =>
|
||||||
|
type.id === typeId ? { ...type, ...updates } : type
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setNodeTypes(doc.nodeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteNodeTypeFromDocument: (documentId: string, typeId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from document's node types
|
||||||
|
doc.nodeTypes = doc.nodeTypes.filter((type) => type.id !== typeId);
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setNodeTypes(doc.nodeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addEdgeTypeToDocument: (documentId: string, edgeType) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to document's edge types
|
||||||
|
doc.edgeTypes = [...doc.edgeTypes, edgeType];
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setEdgeTypes(doc.edgeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateEdgeTypeInDocument: (documentId: string, typeId: string, updates) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update in document's edge types
|
||||||
|
doc.edgeTypes = doc.edgeTypes.map((type) =>
|
||||||
|
type.id === typeId ? { ...type, ...updates } : type
|
||||||
|
);
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setEdgeTypes(doc.edgeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteEdgeTypeFromDocument: (documentId: string, typeId: string) => {
|
||||||
|
const state = get();
|
||||||
|
const doc = state.documents.get(documentId);
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
console.error(`Document ${documentId} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from document's edge types
|
||||||
|
doc.edgeTypes = doc.edgeTypes.filter((type) => type.id !== typeId);
|
||||||
|
|
||||||
|
// Save document
|
||||||
|
saveDocumentToStorage(documentId, doc);
|
||||||
|
|
||||||
|
// Mark as dirty
|
||||||
|
get().markDocumentDirty(documentId);
|
||||||
|
|
||||||
|
// If this is the active document, sync to graphStore
|
||||||
|
if (documentId === state.activeDocumentId) {
|
||||||
|
useGraphStore.getState().setEdgeTypes(doc.edgeTypes);
|
||||||
|
}
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue