Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
This commit is contained in:
193
admin-ui/js/core/workflow-persistence.js
Normal file
193
admin-ui/js/core/workflow-persistence.js
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Workflow Persistence - Phase 8 Enterprise Pattern
|
||||
*
|
||||
* Saves and restores workflow states to localStorage and server,
|
||||
* enabling crash recovery and session restoration.
|
||||
*/
|
||||
|
||||
import store from '../stores/app-store.js';
|
||||
|
||||
class WorkflowPersistence {
|
||||
constructor() {
|
||||
this.storageKey = 'dss-workflow-state';
|
||||
this.maxSnapshots = 10;
|
||||
this.autoSaveInterval = 30000; // 30 seconds
|
||||
this.isAutosaving = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a workflow snapshot of current state
|
||||
*/
|
||||
snapshot() {
|
||||
const state = store.get();
|
||||
const snapshot = {
|
||||
id: `snapshot-${Date.now()}`,
|
||||
timestamp: new Date().toISOString(),
|
||||
data: {
|
||||
currentPage: state.currentPage,
|
||||
sidebarOpen: state.sidebarOpen,
|
||||
user: state.user,
|
||||
team: state.team,
|
||||
role: state.role,
|
||||
figmaConnected: state.figmaConnected,
|
||||
figmaFileKey: state.figmaFileKey,
|
||||
selectedProject: state.projects[0]?.id || null,
|
||||
}
|
||||
};
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save snapshot to localStorage with versioning
|
||||
*/
|
||||
saveSnapshot(snapshot = null) {
|
||||
try {
|
||||
const snap = snapshot || this.snapshot();
|
||||
const snapshots = this.getSnapshots();
|
||||
|
||||
// Keep only latest N snapshots
|
||||
snapshots.unshift(snap);
|
||||
snapshots.splice(this.maxSnapshots);
|
||||
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(snapshots));
|
||||
return snap.id;
|
||||
} catch (e) {
|
||||
console.error('[WorkflowPersistence] Failed to save snapshot:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all saved snapshots
|
||||
*/
|
||||
getSnapshots() {
|
||||
try {
|
||||
const stored = localStorage.getItem(this.storageKey);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
} catch (e) {
|
||||
console.warn('[WorkflowPersistence] Failed to load snapshots:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get latest snapshot
|
||||
*/
|
||||
getLatestSnapshot() {
|
||||
const snapshots = this.getSnapshots();
|
||||
return snapshots[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snapshot by ID
|
||||
*/
|
||||
getSnapshot(id) {
|
||||
const snapshots = this.getSnapshots();
|
||||
return snapshots.find(s => s.id === id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore workflow from snapshot
|
||||
*/
|
||||
restoreSnapshot(id) {
|
||||
const snapshot = this.getSnapshot(id);
|
||||
if (!snapshot) {
|
||||
console.warn('[WorkflowPersistence] Snapshot not found:', id);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = snapshot.data;
|
||||
store.set({
|
||||
currentPage: data.currentPage,
|
||||
sidebarOpen: data.sidebarOpen,
|
||||
user: data.user,
|
||||
team: data.team,
|
||||
role: data.role,
|
||||
figmaConnected: data.figmaConnected,
|
||||
figmaFileKey: data.figmaFileKey,
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('[WorkflowPersistence] Failed to restore snapshot:', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all snapshots
|
||||
*/
|
||||
clearSnapshots() {
|
||||
localStorage.removeItem(this.storageKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete specific snapshot
|
||||
*/
|
||||
deleteSnapshot(id) {
|
||||
const snapshots = this.getSnapshots();
|
||||
const filtered = snapshots.filter(s => s.id !== id);
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(filtered));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start auto-saving workflow every N milliseconds
|
||||
*/
|
||||
startAutoSave(interval = this.autoSaveInterval) {
|
||||
if (this.isAutosaving) return;
|
||||
|
||||
this.isAutosaving = true;
|
||||
this.autoSaveTimer = setInterval(() => {
|
||||
this.saveSnapshot();
|
||||
}, interval);
|
||||
|
||||
console.log('[WorkflowPersistence] Auto-save enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop auto-saving
|
||||
*/
|
||||
stopAutoSave() {
|
||||
if (this.autoSaveTimer) {
|
||||
clearInterval(this.autoSaveTimer);
|
||||
this.isAutosaving = false;
|
||||
console.log('[WorkflowPersistence] Auto-save disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export snapshots as JSON file
|
||||
*/
|
||||
exportSnapshots() {
|
||||
const snapshots = this.getSnapshots();
|
||||
const data = {
|
||||
exportDate: new Date().toISOString(),
|
||||
version: '1.0',
|
||||
snapshots: snapshots
|
||||
};
|
||||
return JSON.stringify(data, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import snapshots from JSON data
|
||||
*/
|
||||
importSnapshots(jsonData) {
|
||||
try {
|
||||
const data = JSON.parse(jsonData);
|
||||
if (!Array.isArray(data.snapshots)) {
|
||||
throw new Error('Invalid snapshot format');
|
||||
}
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(data.snapshots));
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('[WorkflowPersistence] Failed to import snapshots:', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export singleton
|
||||
const persistence = new WorkflowPersistence();
|
||||
|
||||
export { WorkflowPersistence };
|
||||
export default persistence;
|
||||
Reference in New Issue
Block a user