diff --git a/stores/console/store.ts b/stores/console/store.ts index 61998290ae..d165a181bb 100644 --- a/stores/console/store.ts +++ b/stores/console/store.ts @@ -2,6 +2,7 @@ import { create } from 'zustand' import { devtools, persist } from 'zustand/middleware' import { ConsoleEntry, ConsoleStore } from './types' +// MAX across all workflows const MAX_ENTRIES = 50 export const useConsoleStore = create()( diff --git a/stores/notifications/store.ts b/stores/notifications/store.ts index ff9e15c912..461651b5e4 100644 --- a/stores/notifications/store.ts +++ b/stores/notifications/store.ts @@ -3,18 +3,20 @@ import { devtools } from 'zustand/middleware' import { Notification, NotificationStore, NotificationType } from './types' const STORAGE_KEY = 'workflow-notifications' +// Maximum number of notifications to keep across all workflows +const MAX_NOTIFICATIONS = 50 // Helper to load persisted notifications const loadPersistedNotifications = (): Notification[] => { if (typeof window === 'undefined') return [] const saved = localStorage.getItem(STORAGE_KEY) - return saved ? JSON.parse(saved) : [] + return saved ? JSON.parse(saved).slice(0, MAX_NOTIFICATIONS) : [] } // Helper to save notifications to localStorage const persistNotifications = (notifications: Notification[]) => { if (typeof window === 'undefined') return - localStorage.setItem(STORAGE_KEY, JSON.stringify(notifications)) + localStorage.setItem(STORAGE_KEY, JSON.stringify(notifications.slice(0, MAX_NOTIFICATIONS))) } export const useNotificationStore = create()( @@ -36,7 +38,11 @@ export const useNotificationStore = create()( } set((state) => { - const newNotifications = [...state.notifications, notification] + // Add new notification at the start and limit total count + const newNotifications = [notification, ...state.notifications].slice( + 0, + MAX_NOTIFICATIONS + ) persistNotifications(newNotifications) return { notifications: newNotifications } }) diff --git a/stores/workflow/middleware.ts b/stores/workflow/middleware.ts index 71939bb828..e0dbe1cf9c 100644 --- a/stores/workflow/middleware.ts +++ b/stores/workflow/middleware.ts @@ -2,16 +2,20 @@ import { StateCreator } from 'zustand' import { HistoryActions, HistoryEntry, WorkflowHistory } from './history-types' import { WorkflowState, WorkflowStore } from './types' +// MAX for each individual workflow const MAX_HISTORY_LENGTH = 20 +// Types for workflow store with history management capabilities export interface WorkflowStoreWithHistory extends WorkflowStore, HistoryActions { history: WorkflowHistory } +// Higher-order store middleware that adds undo/redo functionality export const withHistory = ( config: StateCreator ): StateCreator => { return (set, get, api) => { + // Initialize store with history tracking const initialState = config(set, get, api) const initialHistoryEntry: HistoryEntry = { state: { @@ -31,9 +35,13 @@ export const withHistory = ( future: [], }, + // Check if undo operation is available canUndo: () => get().history.past.length > 0, + + // Check if redo operation is available canRedo: () => get().history.future.length > 0, + // Restore previous state from history undo: () => { const { history, ...state } = get() if (history.past.length === 0) return @@ -52,6 +60,7 @@ export const withHistory = ( }) }, + // Restore next state from history redo: () => { const { history, ...state } = get() if (history.future.length === 0) return @@ -70,6 +79,7 @@ export const withHistory = ( }) }, + // Reset workflow to empty state clear: () => { const newState = { blocks: {}, @@ -89,6 +99,7 @@ export const withHistory = ( return newState }, + // Jump to specific point in history revertToHistoryState: (index: number) => { const { history, ...state } = get() const allStates = [...history.past, history.present, ...history.future] @@ -113,6 +124,7 @@ export const withHistory = ( } } +// Create a new history entry with current state snapshot export const createHistoryEntry = (state: WorkflowState, action: string): HistoryEntry => ({ state: { blocks: { ...state.blocks }, @@ -123,6 +135,7 @@ export const createHistoryEntry = (state: WorkflowState, action: string): Histor action, }) +// Add new entry to history and maintain history size limit export const pushHistory = ( set: ( partial: diff --git a/stores/workflow/registry/store.ts b/stores/workflow/registry/store.ts index 521ba84f69..3b3f0df37a 100644 --- a/stores/workflow/registry/store.ts +++ b/stores/workflow/registry/store.ts @@ -2,15 +2,18 @@ import { create } from 'zustand' import { devtools } from 'zustand/middleware' import { useWorkflowStore } from '../store' import { WorkflowMetadata, WorkflowRegistry } from './types' +import { generateUniqueName } from './utils' export const useWorkflowRegistry = create()( devtools( (set, get) => ({ + // Store state workflows: {}, activeWorkflowId: null, isLoading: false, error: null, + // Switch to a different workflow and manage state persistence setActiveWorkflow: async (id: string) => { const { workflows } = get() if (!workflows[id]) { @@ -72,6 +75,7 @@ export const useWorkflowRegistry = create()( set({ activeWorkflowId: id, error: null }) }, + // Create new workflow with default starter block addWorkflow: (metadata: WorkflowMetadata) => { const uniqueName = generateUniqueName(get().workflows) const updatedMetadata = { ...metadata, name: uniqueName } @@ -216,6 +220,7 @@ export const useWorkflowRegistry = create()( } }, + // Delete workflow and clean up associated storage removeWorkflow: (id: string) => { set((state) => { const newWorkflows = { ...state.workflows } @@ -277,6 +282,7 @@ export const useWorkflowRegistry = create()( }) }, + // Update workflow metadata updateWorkflow: (id: string, metadata: Partial) => { set((state) => { const workflow = state.workflows[id] @@ -305,25 +311,7 @@ export const useWorkflowRegistry = create()( ) ) -const generateUniqueName = (existingWorkflows: Record): string => { - // Extract numbers from existing workflow names using regex - const numbers = Object.values(existingWorkflows) - .map((w) => { - const match = w.name.match(/Workflow (\d+)/) - return match ? parseInt(match[1]) : 0 - }) - .filter((n) => n > 0) - - if (numbers.length === 0) { - return 'Workflow 1' - } - - // Find the maximum number and add 1 - const nextNumber = Math.max(...numbers) + 1 - return `Workflow ${nextNumber}` -} - -// Initialize registry from localStorage +// Initialize registry from localStorage and set up persistence const initializeRegistry = () => { const savedRegistry = localStorage.getItem('workflow-registry') if (savedRegistry) { diff --git a/stores/workflow/registry/utils.ts b/stores/workflow/registry/utils.ts new file mode 100644 index 0000000000..2b6d5180e1 --- /dev/null +++ b/stores/workflow/registry/utils.ts @@ -0,0 +1,19 @@ +import { WorkflowMetadata } from './types' + +export function generateUniqueName(existingWorkflows: Record): string { + // Extract numbers from existing workflow names using regex + const numbers = Object.values(existingWorkflows) + .map((w) => { + const match = w.name.match(/Workflow (\d+)/) + return match ? parseInt(match[1]) : 0 + }) + .filter((n) => n > 0) + + if (numbers.length === 0) { + return 'Workflow 1' + } + + // Find the maximum number and add 1 + const nextNumber = Math.max(...numbers) + 1 + return `Workflow ${nextNumber}` +}