Files
sim/stores/workflows/persistence.ts
Emir Karabeg 76dbc4a52f Feat/db sync (#94)
* feat(db-sync): added general sync file and implemented environment sync

* improvement(workflows-store): structured workflows store system better and added getter for values across stores

* fix(stores): deleted workflows/types since unused

* improvement(db-sync): added workflow event syncs and debounce

* improvement(db-sync): clean and upgraded db-sync system; environment sync implemented

* improvement(db-sync): added batch sync with registry; init bug needs fixing

* improvement(db-sync): finalized sync system and implemented for workflow

* fix(db-sync): fixed client-side rendering

* improvement(db-sync): created backwards sync system; environment implemented

* improvement(db-sync): added colors to db

* fix(db-sync): color sync with db

* improvement(db-sync): added workflow backwards sync; fixing color bug and race condition

* fix(db-stores): color sync

* feature(db-sync): db-sync complete; need to sync history

* improvement(db-sync): added scheduling

* fix(db-sync): environment sync to db
2025-03-03 19:43:39 -08:00

168 lines
4.7 KiB
TypeScript

/**
* Centralized persistence layer for workflow stores
* Handles localStorage interactions and synchronization
*/
import { STORAGE_KEYS } from '../constants'
import { useWorkflowRegistry } from './registry/store'
import { useSubBlockStore } from './subblock/store'
import { useWorkflowStore } from './workflow/store'
/**
* Save data to localStorage with error handling
*/
export function saveToStorage<T>(key: string, data: T): boolean {
try {
localStorage.setItem(key, JSON.stringify(data))
return true
} catch (error) {
console.error(`Failed to save data to ${key}:`, error)
return false
}
}
/**
* Load data from localStorage with error handling
*/
export function loadFromStorage<T>(key: string): T | null {
try {
const data = localStorage.getItem(key)
return data ? JSON.parse(data) : null
} catch (error) {
console.error(`Failed to load data from ${key}:`, error)
return null
}
}
/**
* Remove data from localStorage with error handling
*/
export function removeFromStorage(key: string): boolean {
try {
localStorage.removeItem(key)
return true
} catch (error) {
console.error(`Failed to remove data from ${key}:`, error)
return false
}
}
/**
* Save workflow state to localStorage
*/
export function saveWorkflowState(workflowId: string, state: any): boolean {
// We need to handle history separately since it's not part of the base WorkflowState
return saveToStorage(STORAGE_KEYS.WORKFLOW(workflowId), state)
}
/**
* Load workflow state from localStorage
*/
export function loadWorkflowState(workflowId: string): any {
return loadFromStorage(STORAGE_KEYS.WORKFLOW(workflowId))
}
/**
* Save subblock values to localStorage
*/
export function saveSubblockValues(workflowId: string, values: any): boolean {
return saveToStorage(STORAGE_KEYS.SUBBLOCK(workflowId), values)
}
/**
* Load subblock values from localStorage
*/
export function loadSubblockValues(workflowId: string): any {
return loadFromStorage(STORAGE_KEYS.SUBBLOCK(workflowId))
}
/**
* Save registry to localStorage
*/
export function saveRegistry(registry: any): boolean {
return saveToStorage(STORAGE_KEYS.REGISTRY, registry)
}
/**
* Load registry from localStorage
*/
export function loadRegistry(): any {
return loadFromStorage(STORAGE_KEYS.REGISTRY)
}
/**
* Initialize all stores from localStorage
* This is the main initialization function that should be called once at app startup
*/
export function initializeStores(): void {
if (typeof window === 'undefined') return
// Initialize registry first
const workflows = loadRegistry()
if (workflows) {
useWorkflowRegistry.setState({ workflows })
// If there's an active workflow ID in the registry, load it
const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
if (activeWorkflowId) {
// Load workflow state
const workflowState = loadWorkflowState(activeWorkflowId)
if (workflowState) {
// Initialize workflow store with saved state
useWorkflowStore.setState(workflowState)
// Initialize subblock store with workflow values
const subblockValues = loadSubblockValues(activeWorkflowId)
if (subblockValues) {
useSubBlockStore.setState((state) => ({
workflowValues: {
...state.workflowValues,
[activeWorkflowId]: subblockValues,
},
}))
} else if (workflowState.blocks) {
// If no saved subblock values, initialize from blocks
useSubBlockStore.getState().initializeFromWorkflow(activeWorkflowId, workflowState.blocks)
}
}
}
}
// Setup unload persistence
setupUnloadPersistence()
}
/**
* Setup persistence for page unload events
*/
export function setupUnloadPersistence(): void {
if (typeof window === 'undefined') return
window.addEventListener('beforeunload', () => {
const currentId = useWorkflowRegistry.getState().activeWorkflowId
if (currentId) {
// Save workflow state
const currentState = useWorkflowStore.getState()
// Save the complete state including history which is added by middleware
saveWorkflowState(currentId, {
blocks: currentState.blocks,
edges: currentState.edges,
loops: currentState.loops,
isDeployed: currentState.isDeployed,
deployedAt: currentState.deployedAt,
lastSaved: Date.now(),
history: currentState.history,
})
// Save subblock values
const subblockValues = useSubBlockStore.getState().workflowValues[currentId]
if (subblockValues) {
saveSubblockValues(currentId, subblockValues)
}
}
// Save registry
saveRegistry(useWorkflowRegistry.getState().workflows)
})
}