@octo-cyber/workflow 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controllers/ai-workflow-session.controller.d.ts +19 -0
- package/dist/controllers/ai-workflow-session.controller.d.ts.map +1 -0
- package/dist/controllers/ai-workflow-session.controller.js +135 -0
- package/dist/controllers/ai-workflow-session.controller.js.map +1 -0
- package/dist/controllers/credential.controller.d.ts +68 -0
- package/dist/controllers/credential.controller.d.ts.map +1 -0
- package/dist/controllers/credential.controller.js +303 -0
- package/dist/controllers/credential.controller.js.map +1 -0
- package/dist/controllers/index.d.ts +3 -0
- package/dist/controllers/index.d.ts.map +1 -0
- package/dist/controllers/index.js +8 -0
- package/dist/controllers/index.js.map +1 -0
- package/dist/controllers/workflow-ai.controller.d.ts +23 -0
- package/dist/controllers/workflow-ai.controller.d.ts.map +1 -0
- package/dist/controllers/workflow-ai.controller.js +164 -0
- package/dist/controllers/workflow-ai.controller.js.map +1 -0
- package/dist/controllers/workflow.controller.d.ts +66 -0
- package/dist/controllers/workflow.controller.d.ts.map +1 -0
- package/dist/controllers/workflow.controller.js +239 -0
- package/dist/controllers/workflow.controller.js.map +1 -0
- package/dist/core/expression-resolver.d.ts +49 -0
- package/dist/core/expression-resolver.d.ts.map +1 -0
- package/dist/core/expression-resolver.js +113 -0
- package/dist/core/expression-resolver.js.map +1 -0
- package/dist/core/node-registry.d.ts +24 -0
- package/dist/core/node-registry.d.ts.map +1 -0
- package/dist/core/node-registry.js +62 -0
- package/dist/core/node-registry.js.map +1 -0
- package/dist/core/workflow-executor.d.ts +50 -0
- package/dist/core/workflow-executor.d.ts.map +1 -0
- package/dist/core/workflow-executor.js +458 -0
- package/dist/core/workflow-executor.js.map +1 -0
- package/dist/entities/ai-workflow-session.entity.d.ts +17 -0
- package/dist/entities/ai-workflow-session.entity.d.ts.map +1 -0
- package/dist/entities/ai-workflow-session.entity.js +70 -0
- package/dist/entities/ai-workflow-session.entity.js.map +1 -0
- package/dist/entities/ai-workflow-version.entity.d.ts +18 -0
- package/dist/entities/ai-workflow-version.entity.d.ts.map +1 -0
- package/dist/entities/ai-workflow-version.entity.js +71 -0
- package/dist/entities/ai-workflow-version.entity.js.map +1 -0
- package/dist/entities/credential-definition.entity.d.ts +17 -0
- package/dist/entities/credential-definition.entity.d.ts.map +1 -0
- package/dist/entities/credential-definition.entity.js +66 -0
- package/dist/entities/credential-definition.entity.js.map +1 -0
- package/dist/entities/index.d.ts +9 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +22 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/workflow-definition.entity.d.ts +20 -0
- package/dist/entities/workflow-definition.entity.d.ts.map +1 -0
- package/dist/entities/workflow-definition.entity.js +85 -0
- package/dist/entities/workflow-definition.entity.js.map +1 -0
- package/dist/entities/workflow-execution.entity.d.ts +26 -0
- package/dist/entities/workflow-execution.entity.d.ts.map +1 -0
- package/dist/entities/workflow-execution.entity.js +99 -0
- package/dist/entities/workflow-execution.entity.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/dist/n8n/cipher/cipher.d.ts +11 -0
- package/dist/n8n/cipher/cipher.d.ts.map +1 -0
- package/dist/n8n/cipher/cipher.js +54 -0
- package/dist/n8n/cipher/cipher.js.map +1 -0
- package/dist/n8n/controllers/n8n-session.controller.d.ts +20 -0
- package/dist/n8n/controllers/n8n-session.controller.d.ts.map +1 -0
- package/dist/n8n/controllers/n8n-session.controller.js +84 -0
- package/dist/n8n/controllers/n8n-session.controller.js.map +1 -0
- package/dist/n8n/index.d.ts +8 -0
- package/dist/n8n/index.d.ts.map +1 -0
- package/dist/n8n/index.js +14 -0
- package/dist/n8n/index.js.map +1 -0
- package/dist/n8n/launcher/n8n-launcher.d.ts +41 -0
- package/dist/n8n/launcher/n8n-launcher.d.ts.map +1 -0
- package/dist/n8n/launcher/n8n-launcher.js +186 -0
- package/dist/n8n/launcher/n8n-launcher.js.map +1 -0
- package/dist/n8n/nodes/OctoClaudeCliTool.node.d.ts +13 -0
- package/dist/n8n/nodes/OctoClaudeCliTool.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoClaudeCliTool.node.js +103 -0
- package/dist/n8n/nodes/OctoClaudeCliTool.node.js.map +1 -0
- package/dist/n8n/nodes/OctoCliChatModel.node.d.ts +14 -0
- package/dist/n8n/nodes/OctoCliChatModel.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoCliChatModel.node.js +431 -0
- package/dist/n8n/nodes/OctoCliChatModel.node.js.map +1 -0
- package/dist/n8n/nodes/OctoCodexCliTool.node.d.ts +13 -0
- package/dist/n8n/nodes/OctoCodexCliTool.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoCodexCliTool.node.js +100 -0
- package/dist/n8n/nodes/OctoCodexCliTool.node.js.map +1 -0
- package/dist/n8n/nodes/OctoGeminiCliTool.node.d.ts +13 -0
- package/dist/n8n/nodes/OctoGeminiCliTool.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoGeminiCliTool.node.js +91 -0
- package/dist/n8n/nodes/OctoGeminiCliTool.node.js.map +1 -0
- package/dist/n8n/nodes/OctoKnowledge.node.d.ts +6 -0
- package/dist/n8n/nodes/OctoKnowledge.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoKnowledge.node.js +95 -0
- package/dist/n8n/nodes/OctoKnowledge.node.js.map +1 -0
- package/dist/n8n/nodes/OctoNotification.node.d.ts +6 -0
- package/dist/n8n/nodes/OctoNotification.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoNotification.node.js +72 -0
- package/dist/n8n/nodes/OctoNotification.node.js.map +1 -0
- package/dist/n8n/nodes/OctoSyncBridge.node.d.ts +6 -0
- package/dist/n8n/nodes/OctoSyncBridge.node.d.ts.map +1 -0
- package/dist/n8n/nodes/OctoSyncBridge.node.js +60 -0
- package/dist/n8n/nodes/OctoSyncBridge.node.js.map +1 -0
- package/dist/n8n/nodes/n8n-node-types.d.ts +111 -0
- package/dist/n8n/nodes/n8n-node-types.d.ts.map +1 -0
- package/dist/n8n/nodes/n8n-node-types.js +30 -0
- package/dist/n8n/nodes/n8n-node-types.js.map +1 -0
- package/dist/n8n/nodes/octo-cli-chat-model.svg +23 -0
- package/dist/n8n/nodes/package.json +16 -0
- package/dist/n8n/proxy/css-injector.d.ts +3 -0
- package/dist/n8n/proxy/css-injector.d.ts.map +1 -0
- package/dist/n8n/proxy/css-injector.js +62 -0
- package/dist/n8n/proxy/css-injector.js.map +1 -0
- package/dist/n8n/proxy/n8n-proxy.middleware.d.ts +12 -0
- package/dist/n8n/proxy/n8n-proxy.middleware.d.ts.map +1 -0
- package/dist/n8n/proxy/n8n-proxy.middleware.js +131 -0
- package/dist/n8n/proxy/n8n-proxy.middleware.js.map +1 -0
- package/dist/n8n/proxy/n8n-theme.css +45 -0
- package/dist/n8n/sync/n8n-user-sync.service.d.ts +75 -0
- package/dist/n8n/sync/n8n-user-sync.service.d.ts.map +1 -0
- package/dist/n8n/sync/n8n-user-sync.service.js +286 -0
- package/dist/n8n/sync/n8n-user-sync.service.js.map +1 -0
- package/dist/n8n/watcher/n8n-execution-watcher.d.ts +39 -0
- package/dist/n8n/watcher/n8n-execution-watcher.d.ts.map +1 -0
- package/dist/n8n/watcher/n8n-execution-watcher.js +110 -0
- package/dist/n8n/watcher/n8n-execution-watcher.js.map +1 -0
- package/dist/nodes/code.node.d.ts +24 -0
- package/dist/nodes/code.node.d.ts.map +1 -0
- package/dist/nodes/code.node.js +150 -0
- package/dist/nodes/code.node.js.map +1 -0
- package/dist/nodes/error-trigger.node.d.ts +15 -0
- package/dist/nodes/error-trigger.node.d.ts.map +1 -0
- package/dist/nodes/error-trigger.node.js +53 -0
- package/dist/nodes/error-trigger.node.js.map +1 -0
- package/dist/nodes/execute-command.node.d.ts +9 -0
- package/dist/nodes/execute-command.node.d.ts.map +1 -0
- package/dist/nodes/execute-command.node.js +81 -0
- package/dist/nodes/execute-command.node.js.map +1 -0
- package/dist/nodes/filter.node.d.ts +10 -0
- package/dist/nodes/filter.node.d.ts.map +1 -0
- package/dist/nodes/filter.node.js +95 -0
- package/dist/nodes/filter.node.js.map +1 -0
- package/dist/nodes/http-request.node.d.ts +11 -0
- package/dist/nodes/http-request.node.d.ts.map +1 -0
- package/dist/nodes/http-request.node.js +139 -0
- package/dist/nodes/http-request.node.js.map +1 -0
- package/dist/nodes/if.node.d.ts +13 -0
- package/dist/nodes/if.node.d.ts.map +1 -0
- package/dist/nodes/if.node.js +137 -0
- package/dist/nodes/if.node.js.map +1 -0
- package/dist/nodes/index.d.ts +12 -0
- package/dist/nodes/index.d.ts.map +1 -0
- package/dist/nodes/index.js +26 -0
- package/dist/nodes/index.js.map +1 -0
- package/dist/nodes/manual-trigger.node.d.ts +10 -0
- package/dist/nodes/manual-trigger.node.d.ts.map +1 -0
- package/dist/nodes/manual-trigger.node.js +36 -0
- package/dist/nodes/manual-trigger.node.js.map +1 -0
- package/dist/nodes/merge.node.d.ts +15 -0
- package/dist/nodes/merge.node.d.ts.map +1 -0
- package/dist/nodes/merge.node.js +99 -0
- package/dist/nodes/merge.node.js.map +1 -0
- package/dist/nodes/noop.node.d.ts +12 -0
- package/dist/nodes/noop.node.d.ts.map +1 -0
- package/dist/nodes/noop.node.js +32 -0
- package/dist/nodes/noop.node.js.map +1 -0
- package/dist/nodes/placeholder.node.d.ts +10 -0
- package/dist/nodes/placeholder.node.d.ts.map +1 -0
- package/dist/nodes/placeholder.node.js +50 -0
- package/dist/nodes/placeholder.node.js.map +1 -0
- package/dist/nodes/remove-duplicates.node.d.ts +9 -0
- package/dist/nodes/remove-duplicates.node.d.ts.map +1 -0
- package/dist/nodes/remove-duplicates.node.js +68 -0
- package/dist/nodes/remove-duplicates.node.js.map +1 -0
- package/dist/nodes/respond-to-webhook.node.d.ts +14 -0
- package/dist/nodes/respond-to-webhook.node.d.ts.map +1 -0
- package/dist/nodes/respond-to-webhook.node.js +116 -0
- package/dist/nodes/respond-to-webhook.node.js.map +1 -0
- package/dist/nodes/schedule-trigger.node.d.ts +9 -0
- package/dist/nodes/schedule-trigger.node.d.ts.map +1 -0
- package/dist/nodes/schedule-trigger.node.js +67 -0
- package/dist/nodes/schedule-trigger.node.js.map +1 -0
- package/dist/nodes/set.node.d.ts +12 -0
- package/dist/nodes/set.node.d.ts.map +1 -0
- package/dist/nodes/set.node.js +81 -0
- package/dist/nodes/set.node.js.map +1 -0
- package/dist/nodes/sort.node.d.ts +9 -0
- package/dist/nodes/sort.node.d.ts.map +1 -0
- package/dist/nodes/sort.node.js +61 -0
- package/dist/nodes/sort.node.js.map +1 -0
- package/dist/nodes/split-in-batches.node.d.ts +9 -0
- package/dist/nodes/split-in-batches.node.d.ts.map +1 -0
- package/dist/nodes/split-in-batches.node.js +53 -0
- package/dist/nodes/split-in-batches.node.js.map +1 -0
- package/dist/nodes/split-out.node.d.ts +9 -0
- package/dist/nodes/split-out.node.d.ts.map +1 -0
- package/dist/nodes/split-out.node.js +76 -0
- package/dist/nodes/split-out.node.js.map +1 -0
- package/dist/nodes/switch.node.d.ts +16 -0
- package/dist/nodes/switch.node.d.ts.map +1 -0
- package/dist/nodes/switch.node.js +156 -0
- package/dist/nodes/switch.node.js.map +1 -0
- package/dist/nodes/wait.node.d.ts +12 -0
- package/dist/nodes/wait.node.d.ts.map +1 -0
- package/dist/nodes/wait.node.js +81 -0
- package/dist/nodes/wait.node.js.map +1 -0
- package/dist/nodes/webhook.node.d.ts +9 -0
- package/dist/nodes/webhook.node.d.ts.map +1 -0
- package/dist/nodes/webhook.node.js +69 -0
- package/dist/nodes/webhook.node.js.map +1 -0
- package/dist/services/ai-workflow-session.service.d.ts +31 -0
- package/dist/services/ai-workflow-session.service.d.ts.map +1 -0
- package/dist/services/ai-workflow-session.service.js +118 -0
- package/dist/services/ai-workflow-session.service.js.map +1 -0
- package/dist/services/credential.service.d.ts +57 -0
- package/dist/services/credential.service.d.ts.map +1 -0
- package/dist/services/credential.service.js +155 -0
- package/dist/services/credential.service.js.map +1 -0
- package/dist/services/index.d.ts +10 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +14 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/push.service.d.ts +60 -0
- package/dist/services/push.service.d.ts.map +1 -0
- package/dist/services/push.service.js +121 -0
- package/dist/services/push.service.js.map +1 -0
- package/dist/services/workflow-ai.service.d.ts +61 -0
- package/dist/services/workflow-ai.service.d.ts.map +1 -0
- package/dist/services/workflow-ai.service.js +219 -0
- package/dist/services/workflow-ai.service.js.map +1 -0
- package/dist/services/workflow-context.service.d.ts +32 -0
- package/dist/services/workflow-context.service.d.ts.map +1 -0
- package/dist/services/workflow-context.service.js +155 -0
- package/dist/services/workflow-context.service.js.map +1 -0
- package/dist/services/workflow-engine.service.d.ts +90 -0
- package/dist/services/workflow-engine.service.d.ts.map +1 -0
- package/dist/services/workflow-engine.service.js +305 -0
- package/dist/services/workflow-engine.service.js.map +1 -0
- package/dist/services/workflow.service.d.ts +84 -0
- package/dist/services/workflow.service.d.ts.map +1 -0
- package/dist/services/workflow.service.js +241 -0
- package/dist/services/workflow.service.js.map +1 -0
- package/dist/triggers/cron-trigger.d.ts +39 -0
- package/dist/triggers/cron-trigger.d.ts.map +1 -0
- package/dist/triggers/cron-trigger.js +137 -0
- package/dist/triggers/cron-trigger.js.map +1 -0
- package/dist/triggers/index.d.ts +3 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +8 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/webhook-trigger.d.ts +51 -0
- package/dist/triggers/webhook-trigger.d.ts.map +1 -0
- package/dist/triggers/webhook-trigger.js +122 -0
- package/dist/triggers/webhook-trigger.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node.types.d.ts +313 -0
- package/dist/types/node.types.d.ts.map +1 -0
- package/dist/types/node.types.js +23 -0
- package/dist/types/node.types.js.map +1 -0
- package/dist/types/workflow.types.d.ts +153 -0
- package/dist/types/workflow.types.d.ts.map +1 -0
- package/dist/types/workflow.types.js +44 -0
- package/dist/types/workflow.types.js.map +1 -0
- package/dist/utils/n8n-converter.d.ts +52 -0
- package/dist/utils/n8n-converter.d.ts.map +1 -0
- package/dist/utils/n8n-converter.js +107 -0
- package/dist/utils/n8n-converter.js.map +1 -0
- package/dist/utils/n8n-node-map.d.ts +6 -0
- package/dist/utils/n8n-node-map.d.ts.map +1 -0
- package/dist/utils/n8n-node-map.js +59 -0
- package/dist/utils/n8n-node-map.js.map +1 -0
- package/dist/workflow.module.d.ts +40 -0
- package/dist/workflow.module.d.ts.map +1 -0
- package/dist/workflow.module.js +240 -0
- package/dist/workflow.module.js.map +1 -0
- package/package.json +97 -0
- package/web/components/ChatPanel.tsx +344 -0
- package/web/components/N8nIframe.tsx +119 -0
- package/web/components/SessionPanel.tsx +301 -0
- package/web/components/ToolPanel.tsx +404 -0
- package/web/components/WorkflowDiff.tsx +161 -0
- package/web/components/WorkflowGraph.tsx +158 -0
- package/web/components/WorkflowPreviewPanel.tsx +186 -0
- package/web/hooks/use-n8n-session.ts +46 -0
- package/web/index.ts +29 -0
- package/web/manifest.ts +16 -0
- package/web/messages/en-US.json +94 -0
- package/web/messages/zh-CN.json +94 -0
- package/web/pages/AiDesignPage.tsx +215 -0
- package/web/pages/CredentialsPage.tsx +7 -0
- package/web/pages/ExecutionsPage.tsx +7 -0
- package/web/pages/WorkflowsPage.tsx +7 -0
- package/web/services/workflow-ai-service.ts +173 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { useTranslations } from 'next-intl'
|
|
5
|
+
import { Badge } from '@octo-cyber/ui/components/ui/badge'
|
|
6
|
+
|
|
7
|
+
interface WorkflowDiffProps {
|
|
8
|
+
originalJson: string
|
|
9
|
+
modifiedJson: string
|
|
10
|
+
className?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface DiffResult {
|
|
14
|
+
nodesAdded: string[]
|
|
15
|
+
nodesRemoved: string[]
|
|
16
|
+
nodesModified: string[]
|
|
17
|
+
connectionsChanged: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function computeDiff(originalJson: string, modifiedJson: string): DiffResult {
|
|
21
|
+
const result: DiffResult = {
|
|
22
|
+
nodesAdded: [],
|
|
23
|
+
nodesRemoved: [],
|
|
24
|
+
nodesModified: [],
|
|
25
|
+
connectionsChanged: false,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const original = JSON.parse(originalJson) as Record<string, unknown>
|
|
30
|
+
const modified = JSON.parse(modifiedJson) as Record<string, unknown>
|
|
31
|
+
|
|
32
|
+
const origNodes = (original.nodes as Array<{ name: string }>) ?? []
|
|
33
|
+
const modNodes = (modified.nodes as Array<{ name: string }>) ?? []
|
|
34
|
+
|
|
35
|
+
const origNodeNames = new Set(origNodes.map((n) => n.name))
|
|
36
|
+
const modNodeNames = new Set(modNodes.map((n) => n.name))
|
|
37
|
+
|
|
38
|
+
for (const name of modNodeNames) {
|
|
39
|
+
if (!origNodeNames.has(name)) {
|
|
40
|
+
result.nodesAdded.push(name)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const name of origNodeNames) {
|
|
45
|
+
if (!modNodeNames.has(name)) {
|
|
46
|
+
result.nodesRemoved.push(name)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check for modified nodes (same name, different params)
|
|
51
|
+
for (const modNode of modNodes) {
|
|
52
|
+
const origNode = origNodes.find((n) => n.name === modNode.name)
|
|
53
|
+
if (origNode && JSON.stringify(origNode) !== JSON.stringify(modNode)) {
|
|
54
|
+
result.nodesModified.push(modNode.name)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Compare connections
|
|
59
|
+
const origConn = JSON.stringify(original.connections ?? {})
|
|
60
|
+
const modConn = JSON.stringify(modified.connections ?? {})
|
|
61
|
+
result.connectionsChanged = origConn !== modConn
|
|
62
|
+
} catch {
|
|
63
|
+
// invalid JSON
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function WorkflowDiff({
|
|
70
|
+
originalJson,
|
|
71
|
+
modifiedJson,
|
|
72
|
+
className,
|
|
73
|
+
}: WorkflowDiffProps) {
|
|
74
|
+
const t = useTranslations('workflows.aiDesign')
|
|
75
|
+
const diff = useMemo(
|
|
76
|
+
() => computeDiff(originalJson, modifiedJson),
|
|
77
|
+
[originalJson, modifiedJson],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const hasChanges =
|
|
81
|
+
diff.nodesAdded.length > 0 ||
|
|
82
|
+
diff.nodesRemoved.length > 0 ||
|
|
83
|
+
diff.nodesModified.length > 0 ||
|
|
84
|
+
diff.connectionsChanged
|
|
85
|
+
|
|
86
|
+
if (!hasChanges) {
|
|
87
|
+
return (
|
|
88
|
+
<div className={`p-4 text-center text-sm text-muted-foreground ${className ?? ''}`}>
|
|
89
|
+
{t('noChanges')}
|
|
90
|
+
</div>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div className={`space-y-3 ${className ?? ''}`}>
|
|
96
|
+
{diff.nodesAdded.length > 0 && (
|
|
97
|
+
<DiffSection
|
|
98
|
+
label={t('nodesAdded')}
|
|
99
|
+
items={diff.nodesAdded}
|
|
100
|
+
color="green"
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
{diff.nodesRemoved.length > 0 && (
|
|
104
|
+
<DiffSection
|
|
105
|
+
label={t('nodesRemoved')}
|
|
106
|
+
items={diff.nodesRemoved}
|
|
107
|
+
color="red"
|
|
108
|
+
/>
|
|
109
|
+
)}
|
|
110
|
+
{diff.nodesModified.length > 0 && (
|
|
111
|
+
<DiffSection
|
|
112
|
+
label={t('nodesModified')}
|
|
113
|
+
items={diff.nodesModified}
|
|
114
|
+
color="yellow"
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
117
|
+
{diff.connectionsChanged && (
|
|
118
|
+
<div className="rounded-md border border-border p-2">
|
|
119
|
+
<Badge variant="outline" className="text-xs">
|
|
120
|
+
{t('connectionsChanged')}
|
|
121
|
+
</Badge>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function DiffSection({
|
|
129
|
+
label,
|
|
130
|
+
items,
|
|
131
|
+
color,
|
|
132
|
+
}: {
|
|
133
|
+
label: string
|
|
134
|
+
items: string[]
|
|
135
|
+
color: 'green' | 'red' | 'yellow'
|
|
136
|
+
}) {
|
|
137
|
+
const colorMap = {
|
|
138
|
+
green: 'border-green-500/30 bg-green-500/5',
|
|
139
|
+
red: 'border-red-500/30 bg-red-500/5',
|
|
140
|
+
yellow: 'border-yellow-500/30 bg-yellow-500/5',
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const badgeMap = {
|
|
144
|
+
green: 'bg-green-500/10 text-green-600 dark:text-green-400',
|
|
145
|
+
red: 'bg-red-500/10 text-red-600 dark:text-red-400',
|
|
146
|
+
yellow: 'bg-yellow-500/10 text-yellow-600 dark:text-yellow-400',
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div className={`rounded-md border p-2 ${colorMap[color]}`}>
|
|
151
|
+
<p className="mb-1 text-xs font-medium text-muted-foreground">{label}</p>
|
|
152
|
+
<div className="flex flex-wrap gap-1">
|
|
153
|
+
{items.map((item) => (
|
|
154
|
+
<span key={item} className={`rounded px-1.5 py-0.5 text-xs ${badgeMap[color]}`}>
|
|
155
|
+
{item}
|
|
156
|
+
</span>
|
|
157
|
+
))}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import {
|
|
5
|
+
ReactFlow,
|
|
6
|
+
Background,
|
|
7
|
+
Controls,
|
|
8
|
+
type Node,
|
|
9
|
+
type Edge,
|
|
10
|
+
Position,
|
|
11
|
+
} from '@xyflow/react'
|
|
12
|
+
import '@xyflow/react/dist/style.css'
|
|
13
|
+
|
|
14
|
+
interface N8nNode {
|
|
15
|
+
name: string
|
|
16
|
+
type: string
|
|
17
|
+
position: [number, number]
|
|
18
|
+
parameters?: Record<string, unknown>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface N8nConnection {
|
|
22
|
+
node: string
|
|
23
|
+
type: string
|
|
24
|
+
index: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface N8nWorkflowJson {
|
|
28
|
+
name?: string
|
|
29
|
+
nodes?: N8nNode[]
|
|
30
|
+
connections?: Record<string, { main?: N8nConnection[][] }>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface WorkflowGraphProps {
|
|
34
|
+
workflowJson: string
|
|
35
|
+
className?: string
|
|
36
|
+
diffStatus?: Record<string, 'added' | 'removed' | 'modified'>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getNodeColor(type: string): string {
|
|
40
|
+
if (type.includes('trigger') || type.includes('Trigger')) return '#e2e8f0'
|
|
41
|
+
if (type.includes('if') || type.includes('switch')) return '#fef3c7'
|
|
42
|
+
if (type.includes('http') || type.includes('Http')) return '#dbeafe'
|
|
43
|
+
if (type.includes('code') || type.includes('Code')) return '#e0e7ff'
|
|
44
|
+
if (type.includes('agent') || type.includes('Agent')) return '#ede9fe'
|
|
45
|
+
return '#f1f5f9'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getDiffBorderColor(
|
|
49
|
+
status: 'added' | 'removed' | 'modified' | undefined,
|
|
50
|
+
): string {
|
|
51
|
+
if (status === 'added') return '#22c55e'
|
|
52
|
+
if (status === 'removed') return '#ef4444'
|
|
53
|
+
if (status === 'modified') return '#eab308'
|
|
54
|
+
return '#94a3b8'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function parseWorkflowToFlow(
|
|
58
|
+
json: string,
|
|
59
|
+
diffStatus?: Record<string, 'added' | 'removed' | 'modified'>,
|
|
60
|
+
): { nodes: Node[]; edges: Edge[] } {
|
|
61
|
+
let parsed: N8nWorkflowJson
|
|
62
|
+
try {
|
|
63
|
+
parsed = JSON.parse(json) as N8nWorkflowJson
|
|
64
|
+
} catch {
|
|
65
|
+
return { nodes: [], edges: [] }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const n8nNodes = parsed.nodes ?? []
|
|
69
|
+
const n8nConnections = parsed.connections ?? {}
|
|
70
|
+
|
|
71
|
+
const nodes: Node[] = n8nNodes.map((n) => {
|
|
72
|
+
const status = diffStatus?.[n.name]
|
|
73
|
+
const shortType = n.type.split('.').pop() ?? n.type
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
id: n.name,
|
|
77
|
+
position: { x: n.position[0], y: n.position[1] },
|
|
78
|
+
data: { label: n.name, type: shortType },
|
|
79
|
+
style: {
|
|
80
|
+
background: getNodeColor(n.type),
|
|
81
|
+
border: `2px solid ${getDiffBorderColor(status)}`,
|
|
82
|
+
borderRadius: '8px',
|
|
83
|
+
padding: '8px 12px',
|
|
84
|
+
fontSize: '12px',
|
|
85
|
+
minWidth: '140px',
|
|
86
|
+
},
|
|
87
|
+
sourcePosition: Position.Right,
|
|
88
|
+
targetPosition: Position.Left,
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const edges: Edge[] = []
|
|
93
|
+
for (const [sourceName, conn] of Object.entries(n8nConnections)) {
|
|
94
|
+
const mainOutputs = conn.main ?? []
|
|
95
|
+
for (let outputIdx = 0; outputIdx < mainOutputs.length; outputIdx++) {
|
|
96
|
+
const targets = mainOutputs[outputIdx] ?? []
|
|
97
|
+
for (const target of targets) {
|
|
98
|
+
const edgeId = `${sourceName}-${outputIdx}-${target.node}-${target.index}`
|
|
99
|
+
const sourceStatus = diffStatus?.[sourceName]
|
|
100
|
+
const targetStatus = diffStatus?.[target.node]
|
|
101
|
+
const isNew = sourceStatus === 'added' || targetStatus === 'added'
|
|
102
|
+
const isRemoved = sourceStatus === 'removed' || targetStatus === 'removed'
|
|
103
|
+
|
|
104
|
+
edges.push({
|
|
105
|
+
id: edgeId,
|
|
106
|
+
source: sourceName,
|
|
107
|
+
target: target.node,
|
|
108
|
+
type: 'smoothstep',
|
|
109
|
+
style: {
|
|
110
|
+
stroke: isNew ? '#22c55e' : isRemoved ? '#ef4444' : '#94a3b8',
|
|
111
|
+
strokeDasharray: isRemoved ? '5,5' : undefined,
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { nodes, edges }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function WorkflowGraph({
|
|
122
|
+
workflowJson,
|
|
123
|
+
className,
|
|
124
|
+
diffStatus,
|
|
125
|
+
}: WorkflowGraphProps) {
|
|
126
|
+
const { nodes, edges } = useMemo(
|
|
127
|
+
() => parseWorkflowToFlow(workflowJson, diffStatus),
|
|
128
|
+
[workflowJson, diffStatus],
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if (nodes.length === 0) {
|
|
132
|
+
return (
|
|
133
|
+
<div className={`flex items-center justify-center text-sm text-muted-foreground ${className ?? ''}`}>
|
|
134
|
+
No workflow nodes to display
|
|
135
|
+
</div>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div className={className} style={{ minHeight: 300 }}>
|
|
141
|
+
<ReactFlow
|
|
142
|
+
nodes={nodes}
|
|
143
|
+
edges={edges}
|
|
144
|
+
fitView
|
|
145
|
+
attributionPosition="bottom-left"
|
|
146
|
+
proOptions={{ hideAttribution: true }}
|
|
147
|
+
nodesDraggable={false}
|
|
148
|
+
nodesConnectable={false}
|
|
149
|
+
elementsSelectable={false}
|
|
150
|
+
panOnDrag
|
|
151
|
+
zoomOnScroll
|
|
152
|
+
>
|
|
153
|
+
<Background />
|
|
154
|
+
<Controls showInteractive={false} />
|
|
155
|
+
</ReactFlow>
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
import { useTranslations } from 'next-intl'
|
|
5
|
+
import { GitCompare, Eye } from 'lucide-react'
|
|
6
|
+
import { Badge } from '@octo-cyber/ui/components/ui/badge'
|
|
7
|
+
import {
|
|
8
|
+
Tabs,
|
|
9
|
+
TabsContent,
|
|
10
|
+
TabsList,
|
|
11
|
+
TabsTrigger,
|
|
12
|
+
} from '@octo-cyber/ui/components/ui/tabs'
|
|
13
|
+
import { WorkflowGraph } from './WorkflowGraph'
|
|
14
|
+
import { WorkflowDiff } from './WorkflowDiff'
|
|
15
|
+
|
|
16
|
+
interface WorkflowPreviewPanelProps {
|
|
17
|
+
/** The latest AI-generated workflow JSON */
|
|
18
|
+
generatedJson: string | null
|
|
19
|
+
/** The original/base workflow JSON (from session's initial state) */
|
|
20
|
+
originalJson: string | null
|
|
21
|
+
className?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Compute diff status map for WorkflowGraph overlay:
|
|
26
|
+
* compares original and modified node sets to determine added/removed/modified.
|
|
27
|
+
*/
|
|
28
|
+
function computeDiffStatus(
|
|
29
|
+
originalJson: string,
|
|
30
|
+
modifiedJson: string,
|
|
31
|
+
): Record<string, 'added' | 'removed' | 'modified'> {
|
|
32
|
+
const status: Record<string, 'added' | 'removed' | 'modified'> = {}
|
|
33
|
+
try {
|
|
34
|
+
const original = JSON.parse(originalJson) as { nodes?: Array<{ name: string }> }
|
|
35
|
+
const modified = JSON.parse(modifiedJson) as { nodes?: Array<{ name: string }> }
|
|
36
|
+
const origNodes = original.nodes ?? []
|
|
37
|
+
const modNodes = modified.nodes ?? []
|
|
38
|
+
const origNames = new Set(origNodes.map((n) => n.name))
|
|
39
|
+
const modNames = new Set(modNodes.map((n) => n.name))
|
|
40
|
+
|
|
41
|
+
for (const name of modNames) {
|
|
42
|
+
if (!origNames.has(name)) {
|
|
43
|
+
status[name] = 'added'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const name of origNames) {
|
|
47
|
+
if (!modNames.has(name)) {
|
|
48
|
+
status[name] = 'removed'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Check modified nodes
|
|
52
|
+
for (const modNode of modNodes) {
|
|
53
|
+
const origNode = origNodes.find((n) => n.name === modNode.name)
|
|
54
|
+
if (origNode && JSON.stringify(origNode) !== JSON.stringify(modNode)) {
|
|
55
|
+
status[modNode.name] = 'modified'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
// invalid JSON
|
|
60
|
+
}
|
|
61
|
+
return status
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function WorkflowPreviewPanel({
|
|
65
|
+
generatedJson,
|
|
66
|
+
originalJson,
|
|
67
|
+
className,
|
|
68
|
+
}: WorkflowPreviewPanelProps) {
|
|
69
|
+
const t = useTranslations('workflows.aiDesign')
|
|
70
|
+
|
|
71
|
+
const hasOriginal = Boolean(originalJson)
|
|
72
|
+
const hasGenerated = Boolean(generatedJson)
|
|
73
|
+
|
|
74
|
+
const diffStatus = useMemo(() => {
|
|
75
|
+
if (!originalJson || !generatedJson) return undefined
|
|
76
|
+
return computeDiffStatus(originalJson, generatedJson)
|
|
77
|
+
}, [originalJson, generatedJson])
|
|
78
|
+
|
|
79
|
+
if (!hasGenerated) {
|
|
80
|
+
return (
|
|
81
|
+
<div className={`flex items-center justify-center border-t border-border bg-muted/20 text-sm text-muted-foreground ${className ?? ''}`}>
|
|
82
|
+
{t('noWorkflowPreview')}
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// If no original (creating from scratch), just show the generated workflow
|
|
88
|
+
if (!hasOriginal) {
|
|
89
|
+
return (
|
|
90
|
+
<div className={`flex flex-col border-t border-border ${className ?? ''}`}>
|
|
91
|
+
<div className="flex items-center gap-2 border-b border-border px-3 py-1.5">
|
|
92
|
+
<Eye className="h-3.5 w-3.5 text-muted-foreground" />
|
|
93
|
+
<span className="text-xs font-medium">{t('workflowPreview')}</span>
|
|
94
|
+
</div>
|
|
95
|
+
<div className="flex-1">
|
|
96
|
+
<WorkflowGraph
|
|
97
|
+
workflowJson={generatedJson!}
|
|
98
|
+
className="h-full w-full"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Has both original and generated: show comparison tabs
|
|
106
|
+
return (
|
|
107
|
+
<div className={`flex flex-col border-t border-border ${className ?? ''}`}>
|
|
108
|
+
<Tabs defaultValue="comparison" className="flex flex-1 flex-col">
|
|
109
|
+
<div className="flex items-center border-b border-border px-3">
|
|
110
|
+
<TabsList className="h-8 bg-transparent">
|
|
111
|
+
<TabsTrigger value="comparison" className="h-7 text-xs">
|
|
112
|
+
<GitCompare className="mr-1 h-3.5 w-3.5" />
|
|
113
|
+
{t('comparison')}
|
|
114
|
+
</TabsTrigger>
|
|
115
|
+
<TabsTrigger value="original" className="h-7 text-xs">
|
|
116
|
+
{t('original')}
|
|
117
|
+
</TabsTrigger>
|
|
118
|
+
<TabsTrigger value="modified" className="h-7 text-xs">
|
|
119
|
+
{t('modified')}
|
|
120
|
+
</TabsTrigger>
|
|
121
|
+
</TabsList>
|
|
122
|
+
|
|
123
|
+
{/* Diff summary badges */}
|
|
124
|
+
{diffStatus && (
|
|
125
|
+
<div className="ml-auto flex gap-1">
|
|
126
|
+
{Object.values(diffStatus).filter((s) => s === 'added').length > 0 && (
|
|
127
|
+
<Badge variant="outline" className="h-5 border-green-500/30 bg-green-500/5 text-[10px] text-green-600 dark:text-green-400">
|
|
128
|
+
+{Object.values(diffStatus).filter((s) => s === 'added').length}
|
|
129
|
+
</Badge>
|
|
130
|
+
)}
|
|
131
|
+
{Object.values(diffStatus).filter((s) => s === 'removed').length > 0 && (
|
|
132
|
+
<Badge variant="outline" className="h-5 border-red-500/30 bg-red-500/5 text-[10px] text-red-600 dark:text-red-400">
|
|
133
|
+
-{Object.values(diffStatus).filter((s) => s === 'removed').length}
|
|
134
|
+
</Badge>
|
|
135
|
+
)}
|
|
136
|
+
{Object.values(diffStatus).filter((s) => s === 'modified').length > 0 && (
|
|
137
|
+
<Badge variant="outline" className="h-5 border-yellow-500/30 bg-yellow-500/5 text-[10px] text-yellow-600 dark:text-yellow-400">
|
|
138
|
+
~{Object.values(diffStatus).filter((s) => s === 'modified').length}
|
|
139
|
+
</Badge>
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<TabsContent value="comparison" className="flex-1 m-0">
|
|
146
|
+
<div className="grid h-full grid-cols-2 divide-x divide-border">
|
|
147
|
+
<div className="relative">
|
|
148
|
+
<span className="absolute left-2 top-1 z-10 text-[10px] font-medium text-muted-foreground">
|
|
149
|
+
{t('original')}
|
|
150
|
+
</span>
|
|
151
|
+
<WorkflowGraph
|
|
152
|
+
workflowJson={originalJson!}
|
|
153
|
+
className="h-full w-full"
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="relative">
|
|
157
|
+
<span className="absolute left-2 top-1 z-10 text-[10px] font-medium text-muted-foreground">
|
|
158
|
+
{t('modified')}
|
|
159
|
+
</span>
|
|
160
|
+
<WorkflowGraph
|
|
161
|
+
workflowJson={generatedJson!}
|
|
162
|
+
diffStatus={diffStatus}
|
|
163
|
+
className="h-full w-full"
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</TabsContent>
|
|
168
|
+
|
|
169
|
+
<TabsContent value="original" className="flex-1 m-0">
|
|
170
|
+
<WorkflowGraph
|
|
171
|
+
workflowJson={originalJson!}
|
|
172
|
+
className="h-full w-full"
|
|
173
|
+
/>
|
|
174
|
+
</TabsContent>
|
|
175
|
+
|
|
176
|
+
<TabsContent value="modified" className="flex-1 m-0">
|
|
177
|
+
<WorkflowGraph
|
|
178
|
+
workflowJson={generatedJson!}
|
|
179
|
+
diffStatus={diffStatus}
|
|
180
|
+
className="h-full w-full"
|
|
181
|
+
/>
|
|
182
|
+
</TabsContent>
|
|
183
|
+
</Tabs>
|
|
184
|
+
</div>
|
|
185
|
+
)
|
|
186
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from 'react'
|
|
4
|
+
|
|
5
|
+
export type N8nErrorType = 'auth' | 'unavailable' | 'network' | 'unknown'
|
|
6
|
+
|
|
7
|
+
interface N8nSessionError {
|
|
8
|
+
type: N8nErrorType
|
|
9
|
+
messageKey: string
|
|
10
|
+
messageParams?: Record<string, string>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function classifyError(status: number): N8nSessionError {
|
|
14
|
+
if (status === 401 || status === 403) {
|
|
15
|
+
return { type: 'auth', messageKey: 'n8nSession.authRequired' }
|
|
16
|
+
}
|
|
17
|
+
if (status === 502 || status === 503 || status === 504) {
|
|
18
|
+
return { type: 'unavailable', messageKey: 'n8nSession.unavailable' }
|
|
19
|
+
}
|
|
20
|
+
return { type: 'unknown', messageKey: 'n8nSession.sessionFailed', messageParams: { status: String(status) } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useN8nSession() {
|
|
24
|
+
const [isReady, setIsReady] = useState(false)
|
|
25
|
+
const [error, setError] = useState<N8nSessionError | null>(null)
|
|
26
|
+
|
|
27
|
+
const ensureSession = useCallback(async () => {
|
|
28
|
+
try {
|
|
29
|
+
setError(null)
|
|
30
|
+
const res = await fetch('/api/n8n/session', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
credentials: 'include',
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if (res.ok) {
|
|
36
|
+
setIsReady(true)
|
|
37
|
+
} else {
|
|
38
|
+
setError(classifyError(res.status))
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
setError({ type: 'network', messageKey: 'n8nSession.networkError' })
|
|
42
|
+
}
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
return { ensureSession, isReady, error }
|
|
46
|
+
}
|
package/web/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @octo-cyber/workflow — Frontend entry point.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports page components and the frontend manifest.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Manifest
|
|
8
|
+
export { workflowFrontendManifest } from './manifest';
|
|
9
|
+
|
|
10
|
+
// i18n Messages
|
|
11
|
+
export { default as workflowMessagesZhCN } from './messages/zh-CN.json';
|
|
12
|
+
export { default as workflowMessagesEnUS } from './messages/en-US.json';
|
|
13
|
+
|
|
14
|
+
// Pages
|
|
15
|
+
export { default as WorkflowsPage } from './pages/WorkflowsPage';
|
|
16
|
+
export { default as CredentialsPage } from './pages/CredentialsPage';
|
|
17
|
+
export { default as ExecutionsPage } from './pages/ExecutionsPage';
|
|
18
|
+
export { default as AiDesignPage } from './pages/AiDesignPage';
|
|
19
|
+
|
|
20
|
+
// Components
|
|
21
|
+
export { N8nIframe } from './components/N8nIframe';
|
|
22
|
+
export { WorkflowDiff } from './components/WorkflowDiff';
|
|
23
|
+
export { SessionPanel } from './components/SessionPanel';
|
|
24
|
+
export { ChatPanel } from './components/ChatPanel';
|
|
25
|
+
export { ToolPanel } from './components/ToolPanel';
|
|
26
|
+
|
|
27
|
+
// Hooks
|
|
28
|
+
export { useN8nSession } from './hooks/use-n8n-session';
|
|
29
|
+
export type { N8nErrorType } from './hooks/use-n8n-session';
|
package/web/manifest.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IFrontendManifest } from '@octo-cyber/core';
|
|
2
|
+
|
|
3
|
+
export const workflowFrontendManifest: IFrontendManifest = {
|
|
4
|
+
moduleId: 'workflow',
|
|
5
|
+
icon: 'Workflow',
|
|
6
|
+
color: 'indigo',
|
|
7
|
+
position: 'main',
|
|
8
|
+
titleKey: 'workflows.title',
|
|
9
|
+
descriptionKey: 'workflows.description',
|
|
10
|
+
pages: [
|
|
11
|
+
{ path: '/workflows', titleKey: 'workflows.pages.list', icon: 'Workflow' },
|
|
12
|
+
{ path: '/workflows/credentials', titleKey: 'workflows.pages.credentials', icon: 'Key' },
|
|
13
|
+
{ path: '/workflows/executions', titleKey: 'workflows.pages.executions', icon: 'Play' },
|
|
14
|
+
{ path: '/workflows/ai-design', titleKey: 'workflows.pages.aiDesign', icon: 'Sparkles' },
|
|
15
|
+
],
|
|
16
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workflows": {
|
|
3
|
+
"loading": "Loading workflow editor...",
|
|
4
|
+
"errors": {
|
|
5
|
+
"auth": {
|
|
6
|
+
"title": "Login Required"
|
|
7
|
+
},
|
|
8
|
+
"unavailable": {
|
|
9
|
+
"title": "n8n Service Unavailable",
|
|
10
|
+
"troubleshootTitle": "Troubleshooting steps:",
|
|
11
|
+
"step1": "Confirm the backend service is running (port 9988)",
|
|
12
|
+
"step2": "Confirm the n8n subprocess is running (port 5678)",
|
|
13
|
+
"step3": "Check the backend logs for n8n startup errors"
|
|
14
|
+
},
|
|
15
|
+
"network": {
|
|
16
|
+
"title": "Network Connection Failed"
|
|
17
|
+
},
|
|
18
|
+
"unknown": {
|
|
19
|
+
"title": "Connection Failed"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"aiDesign": {
|
|
23
|
+
"title": "AI Workflow Design",
|
|
24
|
+
"description": "Describe your automation needs and let AI generate workflow configurations",
|
|
25
|
+
"placeholder": "Describe the workflow you want to create, e.g. \"Send a Slack notification when a new GitHub issue is created\"",
|
|
26
|
+
"inputPlaceholder": "Describe your workflow requirements...",
|
|
27
|
+
"thinking": "AI is designing your workflow...",
|
|
28
|
+
"jsonPreview": "Workflow JSON",
|
|
29
|
+
"copied": "Copied to clipboard",
|
|
30
|
+
"requestFailed": "Failed to generate workflow, please try again",
|
|
31
|
+
"unknownError": "An unknown error occurred",
|
|
32
|
+
"generatedIn": "Generated in",
|
|
33
|
+
"sessions": "Sessions",
|
|
34
|
+
"noSessions": "No sessions yet. Click + to create one.",
|
|
35
|
+
"newSession": "New Design Session",
|
|
36
|
+
"sessionName": "Session Name",
|
|
37
|
+
"sessionNamePlaceholder": "e.g. Email notification workflow",
|
|
38
|
+
"baseWorkflow": "Base Workflow (optional)",
|
|
39
|
+
"selectWorkflow": "Select an existing n8n workflow",
|
|
40
|
+
"newFromScratch": "Create from scratch",
|
|
41
|
+
"create": "Create",
|
|
42
|
+
"cancel": "Cancel",
|
|
43
|
+
"sessionDeleted": "Session deleted",
|
|
44
|
+
"loadSessionsFailed": "Failed to load sessions",
|
|
45
|
+
"deleteSessionFailed": "Failed to delete session",
|
|
46
|
+
"createSessionFailed": "Failed to create session",
|
|
47
|
+
"tools": "Tools",
|
|
48
|
+
"versions": "Versions",
|
|
49
|
+
"apiDocs": "API Docs",
|
|
50
|
+
"aiTool": "AI Tool",
|
|
51
|
+
"model": "Model",
|
|
52
|
+
"defaultModel": "Default",
|
|
53
|
+
"unavailable": "N/A",
|
|
54
|
+
"selectSessionFirst": "Select a session to view version history",
|
|
55
|
+
"rollback": "Rollback",
|
|
56
|
+
"rollbackSuccess": "Rolled back successfully",
|
|
57
|
+
"rollbackFailed": "Rollback failed",
|
|
58
|
+
"apiDocsDesc": "Select API docs to include as context for the AI",
|
|
59
|
+
"estimatedTokens": "Estimated tokens",
|
|
60
|
+
"apply": "Apply",
|
|
61
|
+
"applyConfirmTitle": "Apply Workflow to n8n?",
|
|
62
|
+
"applyConfirmDesc": "This will deactivate the workflow, update it with the new JSON, and you can manually reactivate it afterwards.",
|
|
63
|
+
"applyConfirmNoWorkflow": "This session has no linked n8n workflow. Please create a session from an existing workflow to use the apply feature.",
|
|
64
|
+
"applyConfirm": "Apply",
|
|
65
|
+
"applySuccess": "Workflow applied to n8n successfully",
|
|
66
|
+
"applyFailed": "Failed to apply workflow to n8n",
|
|
67
|
+
"noLinkedWorkflow": "No linked n8n workflow. JSON has been saved.",
|
|
68
|
+
"noChanges": "No changes detected",
|
|
69
|
+
"nodesAdded": "Nodes added",
|
|
70
|
+
"nodesRemoved": "Nodes removed",
|
|
71
|
+
"nodesModified": "Nodes modified",
|
|
72
|
+
"connectionsChanged": "Connections changed",
|
|
73
|
+
"n8nWorkflows": "n8n Workflows",
|
|
74
|
+
"noN8nWorkflows": "No n8n workflows found",
|
|
75
|
+
"loadN8nWorkflowsFailed": "Failed to load n8n workflows",
|
|
76
|
+
"systemPrompt": "System Prompt",
|
|
77
|
+
"systemPromptDesc": "The system prompt used by the AI workflow designer. Updated on server startup.",
|
|
78
|
+
"loadPromptFailed": "Failed to load system prompt",
|
|
79
|
+
"close": "Close",
|
|
80
|
+
"workflowPreview": "Workflow Preview",
|
|
81
|
+
"comparison": "Comparison",
|
|
82
|
+
"original": "Original",
|
|
83
|
+
"modified": "Modified",
|
|
84
|
+
"noWorkflowPreview": "Generate a workflow to see the preview",
|
|
85
|
+
"viewPrompt": "View Prompt"
|
|
86
|
+
},
|
|
87
|
+
"n8nSession": {
|
|
88
|
+
"authRequired": "Please log in before using the workflow editor",
|
|
89
|
+
"unavailable": "n8n service is not running. Please check if the backend service is running properly",
|
|
90
|
+
"sessionFailed": "n8n session creation failed ({status})",
|
|
91
|
+
"networkError": "Unable to connect to the backend service. Please check your network connection"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|