diff --git a/app/w/[id]/workflow.tsx b/app/w/[id]/workflow.tsx index cb40fa053..80cb238bb 100644 --- a/app/w/[id]/workflow.tsx +++ b/app/w/[id]/workflow.tsx @@ -115,6 +115,8 @@ function WorkflowCanvas() { } = useWorkflowStore() const { addNotification } = useNotificationStore() + const params = useParams() + // Convert blocks to ReactFlow nodes using local selectedBlockId const nodes = Object.values(blocks).map((block) => ({ id: block.id, @@ -256,10 +258,6 @@ function WorkflowCanvas() { return () => window.removeEventListener('keydown', handleKeyDown) }, [canUndo, canRedo, undo, redo]) - // useEffect(() => { - // addNotification('console', 'Welcome to the workflow editor!') - // }, []) - return (
diff --git a/app/w/components/control-bar/components/notification-dropdown-item.tsx b/app/w/components/control-bar/components/notification-dropdown-item.tsx index 179e2cefe..e39afbcab 100644 --- a/app/w/components/control-bar/components/notification-dropdown-item.tsx +++ b/app/w/components/control-bar/components/notification-dropdown-item.tsx @@ -8,6 +8,7 @@ import { import { useNotificationStore } from '@/stores/notifications/notifications-store' import { cn } from '@/lib/utils' import { ErrorIcon } from '@/components/icons' +import { useState, useEffect } from 'react' interface NotificationDropdownItemProps { id: string @@ -34,6 +35,14 @@ export function NotificationDropdownItem({ }: NotificationDropdownItemProps) { const { showNotification } = useNotificationStore() const Icon = NotificationIcon[type] + const [, forceUpdate] = useState({}) + + // Update the time display every minute + useEffect(() => { + const interval = setInterval(() => forceUpdate({}), 60000) + return () => clearInterval(interval) + }, []) + const timeAgo = formatDistanceToNow(timestamp, { addSuffix: true }) // Truncate message if it's too long diff --git a/app/w/components/control-bar/control-bar.tsx b/app/w/components/control-bar/control-bar.tsx index 6a781bd2e..91ecc14c4 100644 --- a/app/w/components/control-bar/control-bar.tsx +++ b/app/w/components/control-bar/control-bar.tsx @@ -19,13 +19,18 @@ import { useWorkflowRegistry } from '@/stores/workflow/workflow-registry' import { useRouter } from 'next/navigation' export function ControlBar() { - const { notifications } = useNotificationStore() + const { notifications, getWorkflowNotifications } = useNotificationStore() const { history, undo, redo } = useWorkflowStore() const [, forceUpdate] = useState({}) const { isExecuting, handleRunWorkflow } = useWorkflowExecution() const { workflows, removeWorkflow, activeWorkflowId } = useWorkflowRegistry() const router = useRouter() + // Get notifications for current workflow + const workflowNotifications = activeWorkflowId + ? getWorkflowNotifications(activeWorkflowId) + : notifications // Show all if no workflow is active + const handleDeleteWorkflow = () => { if (!activeWorkflowId) return const newWorkflows = { ...workflows } @@ -120,7 +125,7 @@ export function ControlBar() { - {notifications.length === 0 ? ( + {workflowNotifications.length === 0 ? ( No new notifications @@ -128,15 +133,12 @@ export function ControlBar() { ) : ( - {[...notifications] + {[...workflowNotifications] .sort((a, b) => b.timestamp - a.timestamp) .map((notification) => ( ))} diff --git a/app/w/hooks/use-workflow-execution.ts b/app/w/hooks/use-workflow-execution.ts index 869364ee7..38ef1a0ae 100644 --- a/app/w/hooks/use-workflow-execution.ts +++ b/app/w/hooks/use-workflow-execution.ts @@ -4,11 +4,13 @@ import { Serializer } from '@/serializer' import { Executor } from '@/executor' import { ExecutionResult } from '@/executor/types' import { useNotificationStore } from '@/stores/notifications/notifications-store' +import { useWorkflowRegistry } from '@/stores/workflow/workflow-registry' export function useWorkflowExecution() { const [isExecuting, setIsExecuting] = useState(false) const [executionResult, setExecutionResult] = useState(null) const { blocks, edges } = useWorkflowStore() + const { activeWorkflowId } = useWorkflowRegistry() const { addNotification } = useNotificationStore() const handleRunWorkflow = useCallback(async () => { @@ -31,12 +33,13 @@ export function useWorkflowExecution() { const result = await executor.execute(crypto.randomUUID()) setExecutionResult(result) - // Show execution result + // Show execution result with workflowId addNotification( result.success ? 'console' : 'error', result.success ? 'Workflow completed successfully' - : `Failed to execute workflow: ${result.error}` + : `Failed to execute workflow: ${result.error}`, + activeWorkflowId ) // Log detailed result to console @@ -58,11 +61,11 @@ export function useWorkflowExecution() { data: {}, error: errorMessage }) - addNotification('error', `Failed to execute workflow: ${errorMessage}`) + addNotification('error', `Failed to execute workflow: ${errorMessage}`, activeWorkflowId) } finally { setIsExecuting(false) } - }, [blocks, edges, addNotification]) + }, [blocks, edges, addNotification, activeWorkflowId]) return { isExecuting, executionResult, handleRunWorkflow } } \ No newline at end of file diff --git a/stores/notifications/notifications-store.ts b/stores/notifications/notifications-store.ts index ead27dbf8..4c6d5cfa3 100644 --- a/stores/notifications/notifications-store.ts +++ b/stores/notifications/notifications-store.ts @@ -3,39 +3,75 @@ import { devtools } from 'zustand/middleware' import { NotificationType, Notification, NotificationStore } from './types' import { getTimestamp } from '@/lib/utils' +const STORAGE_KEY = 'workflow-notifications' + +// Helper to load persisted notifications +const loadPersistedNotifications = (): Notification[] => { + if (typeof window === 'undefined') return [] + const saved = localStorage.getItem(STORAGE_KEY) + return saved ? JSON.parse(saved) : [] +} + +// Helper to save notifications to localStorage +const persistNotifications = (notifications: Notification[]) => { + if (typeof window === 'undefined') return + localStorage.setItem(STORAGE_KEY, JSON.stringify(notifications)) +} + export const useNotificationStore = create()( devtools( - (set) => ({ - notifications: [], - addNotification: (type, message) => { + (set, get) => ({ + notifications: loadPersistedNotifications(), + + addNotification: (type, message, workflowId) => { const notification: Notification = { id: typeof window === 'undefined' ? '1' : crypto.randomUUID(), type, message, timestamp: getTimestamp(), isVisible: true, + workflowId } - set((state) => ({ - notifications: [...state.notifications, notification], - })) + set((state) => { + const newNotifications = [...state.notifications, notification] + persistNotifications(newNotifications) + return { notifications: newNotifications } + }) }, + hideNotification: (id) => - set((state) => ({ - notifications: state.notifications.map((n) => + set((state) => { + const newNotifications = state.notifications.map((n) => n.id === id ? { ...n, isVisible: false } : n - ), - })), + ) + persistNotifications(newNotifications) + return { notifications: newNotifications } + }), + showNotification: (id) => - set((state) => ({ - notifications: state.notifications.map((n) => + set((state) => { + const newNotifications = state.notifications.map((n) => n.id === id ? { ...n, isVisible: true } : n - ), - })), + ) + persistNotifications(newNotifications) + return { notifications: newNotifications } + }), + removeNotification: (id) => - set((state) => ({ - notifications: state.notifications.filter((n) => n.id !== id), - })), - clearNotifications: () => set({ notifications: [] }), + set((state) => { + const newNotifications = state.notifications.filter((n) => n.id !== id) + persistNotifications(newNotifications) + return { notifications: newNotifications } + }), + + clearNotifications: () => { + persistNotifications([]) + set({ notifications: [] }) + }, + + getWorkflowNotifications: (workflowId) => { + return get().notifications.filter(n => n.workflowId === workflowId) + } }), { name: 'notification-store' } ) diff --git a/stores/notifications/types.ts b/stores/notifications/types.ts index dfa434a25..699793b10 100644 --- a/stores/notifications/types.ts +++ b/stores/notifications/types.ts @@ -6,13 +6,15 @@ export interface Notification { message: string timestamp: number isVisible: boolean + workflowId: string | null } export interface NotificationStore { notifications: Notification[] - addNotification: (type: NotificationType, message: string) => void + addNotification: (type: NotificationType, message: string, workflowId: string | null) => void hideNotification: (id: string) => void showNotification: (id: string) => void removeNotification: (id: string) => void clearNotifications: () => void + getWorkflowNotifications: (workflowId: string) => Notification[] } \ No newline at end of file