mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
* 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
168 lines
4.7 KiB
TypeScript
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)
|
|
})
|
|
}
|