diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx
index 85560a2105..0815cbfabd 100644
--- a/app/(auth)/login/page.tsx
+++ b/app/(auth)/login/page.tsx
@@ -17,7 +17,7 @@ import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { client } from '@/lib/auth-client'
import { useNotificationStore } from '@/stores/notifications/store'
-import { NotificationList } from '@/app/w/components/notifications/notifications'
+import { NotificationList } from '@/app/w/[id]/components/notifications/notifications'
export default function LoginPage() {
const router = useRouter()
diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx
index 2d9e63751b..c7074ab631 100644
--- a/app/(auth)/signup/page.tsx
+++ b/app/(auth)/signup/page.tsx
@@ -17,7 +17,7 @@ import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { client } from '@/lib/auth-client'
import { useNotificationStore } from '@/stores/notifications/store'
-import { NotificationList } from '@/app/w/components/notifications/notifications'
+import { NotificationList } from '@/app/w/[id]/components/notifications/notifications'
export default function SignupPage() {
const router = useRouter()
diff --git a/app/w/components/chat/chat.tsx b/app/w/[id]/components/chat/chat.tsx
similarity index 100%
rename from app/w/components/chat/chat.tsx
rename to app/w/[id]/components/chat/chat.tsx
diff --git a/app/w/components/console/components/console-entry/console-entry.tsx b/app/w/[id]/components/console/components/console-entry/console-entry.tsx
similarity index 100%
rename from app/w/components/console/components/console-entry/console-entry.tsx
rename to app/w/[id]/components/console/components/console-entry/console-entry.tsx
diff --git a/app/w/components/console/components/json-view/json-view.tsx b/app/w/[id]/components/console/components/json-view/json-view.tsx
similarity index 100%
rename from app/w/components/console/components/json-view/json-view.tsx
rename to app/w/[id]/components/console/components/json-view/json-view.tsx
diff --git a/app/w/components/console/console.tsx b/app/w/[id]/components/console/console.tsx
similarity index 100%
rename from app/w/components/console/console.tsx
rename to app/w/[id]/components/console/console.tsx
diff --git a/app/w/components/control-bar/components/history-dropdown-item/history-dropdown-item.tsx b/app/w/[id]/components/control-bar/components/history-dropdown-item/history-dropdown-item.tsx
similarity index 100%
rename from app/w/components/control-bar/components/history-dropdown-item/history-dropdown-item.tsx
rename to app/w/[id]/components/control-bar/components/history-dropdown-item/history-dropdown-item.tsx
diff --git a/app/w/components/control-bar/components/notification-dropdown-item/notification-dropdown-item.tsx b/app/w/[id]/components/control-bar/components/notification-dropdown-item/notification-dropdown-item.tsx
similarity index 100%
rename from app/w/components/control-bar/components/notification-dropdown-item/notification-dropdown-item.tsx
rename to app/w/[id]/components/control-bar/components/notification-dropdown-item/notification-dropdown-item.tsx
diff --git a/app/w/components/control-bar/control-bar.tsx b/app/w/[id]/components/control-bar/control-bar.tsx
similarity index 100%
rename from app/w/components/control-bar/control-bar.tsx
rename to app/w/[id]/components/control-bar/control-bar.tsx
diff --git a/app/w/[id]/components/error/index.tsx b/app/w/[id]/components/error/index.tsx
new file mode 100644
index 0000000000..cd4b0eb5b0
--- /dev/null
+++ b/app/w/[id]/components/error/index.tsx
@@ -0,0 +1,114 @@
+'use client'
+
+import { Component, ReactNode, useEffect } from 'react'
+import { BotIcon } from 'lucide-react'
+import { Card } from '@/components/ui/card'
+
+// ======== Shared Error UI Component ========
+interface ErrorUIProps {
+ title?: string
+ message?: string
+ onReset?: () => void
+ fullScreen?: boolean
+}
+
+export function ErrorUI({
+ title = 'Workflow Error',
+ message = 'This workflow encountered an error and is currently unavailable. Please try again later or create a new workflow.',
+ onReset,
+ fullScreen = false,
+}: ErrorUIProps) {
+ const containerClass = fullScreen
+ ? 'flex items-center justify-center w-full h-screen bg-muted/40'
+ : 'flex items-center justify-center w-full h-full bg-muted/40'
+
+ return (
+
+
+
+
+
+ {title}
+ {message}
+ {onReset && (
+
+ )}
+
+
+ )
+}
+
+// ======== React Error Boundary Component ========
+interface ErrorBoundaryProps {
+ children: ReactNode
+ fallback?: ReactNode
+}
+
+interface ErrorBoundaryState {
+ hasError: boolean
+ error?: Error
+}
+
+export class ErrorBoundary extends Component {
+ public state: ErrorBoundaryState = {
+ hasError: false,
+ }
+
+ public static getDerivedStateFromError(error: Error): ErrorBoundaryState {
+ return { hasError: true, error }
+ }
+
+ public render() {
+ if (this.state.hasError) {
+ return this.props.fallback ||
+ }
+
+ return this.props.children
+ }
+}
+
+// ======== Next.js Error Page Component ========
+interface NextErrorProps {
+ error: Error & { digest?: string }
+ reset: () => void
+}
+
+export function NextError({ error, reset }: NextErrorProps) {
+ useEffect(() => {
+ // Optionally log the error to an error reporting service
+ console.error('Workflow error:', error)
+ }, [error])
+
+ return
+}
+
+// ======== Next.js Global Error Page Component ========
+export function NextGlobalError({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string }
+ reset: () => void
+}) {
+ useEffect(() => {
+ console.error('Global workspace error:', error)
+ }, [error])
+
+ return (
+
+
+
+
+
+ )
+}
diff --git a/app/w/components/notifications/notifications.tsx b/app/w/[id]/components/notifications/notifications.tsx
similarity index 100%
rename from app/w/components/notifications/notifications.tsx
rename to app/w/[id]/components/notifications/notifications.tsx
diff --git a/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx b/app/w/[id]/components/toolbar/components/toolbar-block/toolbar-block.tsx
similarity index 94%
rename from app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx
rename to app/w/[id]/components/toolbar/components/toolbar-block/toolbar-block.tsx
index b84ac8d001..b774b3e291 100644
--- a/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx
+++ b/app/w/[id]/components/toolbar/components/toolbar-block/toolbar-block.tsx
@@ -1,4 +1,4 @@
-import type { BlockConfig } from '../../../../../../blocks/types'
+import type { BlockConfig } from '@/blocks/types'
export type ToolbarBlockProps = {
config: BlockConfig
diff --git a/app/w/components/toolbar/components/toolbar-tabs/toolbar-tabs.tsx b/app/w/[id]/components/toolbar/components/toolbar-tabs/toolbar-tabs.tsx
similarity index 100%
rename from app/w/components/toolbar/components/toolbar-tabs/toolbar-tabs.tsx
rename to app/w/[id]/components/toolbar/components/toolbar-tabs/toolbar-tabs.tsx
diff --git a/app/w/components/toolbar/toolbar.tsx b/app/w/[id]/components/toolbar/toolbar.tsx
similarity index 96%
rename from app/w/components/toolbar/toolbar.tsx
rename to app/w/[id]/components/toolbar/toolbar.tsx
index 39d64d36b1..60fc9ac3dd 100644
--- a/app/w/components/toolbar/toolbar.tsx
+++ b/app/w/[id]/components/toolbar/toolbar.tsx
@@ -5,8 +5,8 @@ import { PanelRight, PanelRightClose, Search } from 'lucide-react'
import { Input } from '@/components/ui/input'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
-import { getAllBlocks, getBlocksByCategory } from '../../../../blocks'
-import { BlockCategory, BlockConfig } from '../../../../blocks/types'
+import { getAllBlocks, getBlocksByCategory } from '@/blocks'
+import { BlockCategory, BlockConfig } from '@/blocks/types'
import { ToolbarBlock } from './components/toolbar-block/toolbar-block'
import { ToolbarTabs } from './components/toolbar-tabs/toolbar-tabs'
diff --git a/app/w/[id]/components/workflow-block/components/connection-blocks/connection-blocks.tsx b/app/w/[id]/components/workflow-block/components/connection-blocks/connection-blocks.tsx
index 75b18558a2..899f9c1f55 100644
--- a/app/w/[id]/components/workflow-block/components/connection-blocks/connection-blocks.tsx
+++ b/app/w/[id]/components/workflow-block/components/connection-blocks/connection-blocks.tsx
@@ -1,5 +1,5 @@
import { Card } from '@/components/ui/card'
-import { ConnectedBlock, useBlockConnections } from '@/app/w/hooks/use-block-connections'
+import { ConnectedBlock, useBlockConnections } from '@/app/w/[id]/hooks/use-block-connections'
interface ConnectionBlocksProps {
blockId: string
diff --git a/app/w/[id]/components/custom-edge/custom-edge.tsx b/app/w/[id]/components/workflow-edge/workflow-edge.tsx
similarity index 98%
rename from app/w/[id]/components/custom-edge/custom-edge.tsx
rename to app/w/[id]/components/workflow-edge/workflow-edge.tsx
index 6208068e8b..90251aa5fb 100644
--- a/app/w/[id]/components/custom-edge/custom-edge.tsx
+++ b/app/w/[id]/components/workflow-edge/workflow-edge.tsx
@@ -1,7 +1,7 @@
import { X } from 'lucide-react'
import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath } from 'reactflow'
-export const CustomEdge = ({
+export const WorkflowEdge = ({
id,
sourceX,
sourceY,
diff --git a/app/w/hooks/use-block-connections.ts b/app/w/[id]/hooks/use-block-connections.ts
similarity index 100%
rename from app/w/hooks/use-block-connections.ts
rename to app/w/[id]/hooks/use-block-connections.ts
diff --git a/app/w/hooks/use-workflow-execution.ts b/app/w/[id]/hooks/use-workflow-execution.ts
similarity index 100%
rename from app/w/hooks/use-workflow-execution.ts
rename to app/w/[id]/hooks/use-workflow-execution.ts
diff --git a/app/w/[id]/layout.tsx b/app/w/[id]/layout.tsx
new file mode 100644
index 0000000000..d5aa91522f
--- /dev/null
+++ b/app/w/[id]/layout.tsx
@@ -0,0 +1,19 @@
+import { Chat } from './components/chat/chat'
+import { Console } from './components/console/console'
+import { ControlBar } from './components/control-bar/control-bar'
+import { ErrorBoundary } from './components/error'
+import { Toolbar } from './components/toolbar/toolbar'
+
+export default function WorkflowLayout({ children }: { children: React.ReactNode }) {
+ return (
+ <>
+
+
+
+
+
+ {children}
+
+ >
+ )
+}
diff --git a/app/w/[id]/workflow.tsx b/app/w/[id]/workflow.tsx
index c926c3c5d1..e182c7d0bd 100644
--- a/app/w/[id]/workflow.tsx
+++ b/app/w/[id]/workflow.tsx
@@ -17,11 +17,11 @@ import { useGeneralStore } from '@/stores/settings/general/store'
import { getSyncManagers, initializeSyncManagers, isSyncInitialized } from '@/stores/sync-registry'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
-import { NotificationList } from '@/app/w/components/notifications/notifications'
+import { NotificationList } from '@/app/w/[id]/components/notifications/notifications'
import { getBlock } from '../../../blocks'
-import { ErrorBoundary } from '../components/error-boundary/error-boundary'
-import { CustomEdge } from './components/custom-edge/custom-edge'
+import { ErrorBoundary } from './components/error/index'
import { WorkflowBlock } from './components/workflow-block/workflow-block'
+import { WorkflowEdge } from './components/workflow-edge/workflow-edge'
import { LoopInput } from './components/workflow-loop/components/loop-input/loop-input'
import { LoopLabel } from './components/workflow-loop/components/loop-label/loop-label'
import { createLoopNode, getRelativeLoopPosition } from './components/workflow-loop/workflow-loop'
@@ -32,7 +32,7 @@ const nodeTypes: NodeTypes = {
loopLabel: LoopLabel,
loopInput: LoopInput,
}
-const edgeTypes: EdgeTypes = { custom: CustomEdge }
+const edgeTypes: EdgeTypes = { workflowEdge: WorkflowEdge }
function WorkflowContent() {
// State
@@ -194,7 +194,7 @@ function WorkflowContent() {
addEdge({
...connection,
id: crypto.randomUUID(),
- type: 'custom',
+ type: 'workflowEdge',
})
}
},
@@ -284,7 +284,7 @@ function WorkflowContent() {
// Transform edges to include selection state
const edgesWithSelection = edges.map((edge) => ({
...edge,
- type: edge.type || 'custom',
+ type: edge.type || 'workflowEdge',
data: {
selectedEdgeId,
onDelete: (edgeId: string) => {
diff --git a/app/w/components/error-boundary/error-boundary.tsx b/app/w/components/error-boundary/error-boundary.tsx
deleted file mode 100644
index 7dcea32cf7..0000000000
--- a/app/w/components/error-boundary/error-boundary.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-'use client'
-
-import { Component, ReactNode } from 'react'
-import { BotIcon } from 'lucide-react'
-import { Card } from '@/components/ui/card'
-
-interface Props {
- children: ReactNode
- fallback?: ReactNode
-}
-
-interface State {
- hasError: boolean
- error?: Error
-}
-
-export class ErrorBoundary extends Component {
- public state: State = {
- hasError: false,
- }
-
- public static getDerivedStateFromError(error: Error): State {
- return { hasError: true, error }
- }
-
- public render() {
- if (this.state.hasError) {
- return (
- this.props.fallback || (
-
-
-
-
-
- Workflow Error
-
- This workflow encountered an error and is currently unavailable. Please try again
- later or create a new workflow.
-
-
-
- )
- )
- }
-
- return this.props.children
- }
-}
diff --git a/app/w/providers/providers.tsx b/app/w/components/providers/providers.tsx
similarity index 100%
rename from app/w/providers/providers.tsx
rename to app/w/components/providers/providers.tsx
diff --git a/app/w/providers/theme-provider.tsx b/app/w/components/providers/theme-provider.tsx
similarity index 100%
rename from app/w/providers/theme-provider.tsx
rename to app/w/components/providers/theme-provider.tsx
diff --git a/app/w/error.tsx b/app/w/error.tsx
index a2f876dfcb..adac0456b8 100644
--- a/app/w/error.tsx
+++ b/app/w/error.tsx
@@ -1,38 +1,5 @@
'use client'
-import { useEffect } from 'react'
-import { BotIcon } from 'lucide-react'
-import { Card } from '@/components/ui/card'
+import { NextError } from './[id]/components/error'
-interface ErrorProps {
- error: Error & { digest?: string }
- reset: () => void
-}
-
-export default function Error({ error, reset }: ErrorProps) {
- useEffect(() => {
- // Optionally log the error to an error reporting service
- console.error('Workflow error:', error)
- }, [error])
-
- return (
-
-
-
-
-
- Workflow Error
-
- This workflow encountered an error and is currently unavailable. Please try again later or
- create a new workflow.
-
-
-
-
- )
-}
+export default NextError
diff --git a/app/w/global-error.tsx b/app/w/global-error.tsx
index 021c162fd9..9c7bd97575 100644
--- a/app/w/global-error.tsx
+++ b/app/w/global-error.tsx
@@ -1,41 +1,5 @@
'use client'
-import { useEffect } from 'react'
-import { BotIcon } from 'lucide-react'
-import { Card } from '@/components/ui/card'
+import { NextGlobalError } from './[id]/components/error'
-export default function GlobalError({
- error,
- reset,
-}: {
- error: Error & { digest?: string }
- reset: () => void
-}) {
- useEffect(() => {
- console.error('Global workspace error:', error)
- }, [error])
-
- return (
-
-
-
-
-
-
-
- Application Error
-
- Something went wrong with the application. Please try again later.
-
-
-
-
-
-
- )
-}
+export default NextGlobalError
diff --git a/app/w/layout.tsx b/app/w/layout.tsx
index 3b826aab04..7028ce8775 100644
--- a/app/w/layout.tsx
+++ b/app/w/layout.tsx
@@ -1,10 +1,5 @@
-import { Chat } from './components/chat/chat'
-import { Console } from './components/console/console'
-import { ControlBar } from './components/control-bar/control-bar'
-import { ErrorBoundary } from './components/error-boundary/error-boundary'
+import Providers from './components/providers/providers'
import { Sidebar } from './components/sidebar/sidebar'
-import { Toolbar } from './components/toolbar/toolbar'
-import Providers from './providers/providers'
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
return (
@@ -13,17 +8,7 @@ export default function WorkspaceLayout({ children }: { children: React.ReactNod
-
-
-
-
-
-
-
- {children}
-
-
-
+ {children}
)