@xdelivered/emberflow 0.2.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/LICENSE +21 -0
- package/README.md +153 -0
- package/bin/commands.test.ts +185 -0
- package/bin/commands.ts +306 -0
- package/bin/emberflow.mjs +38 -0
- package/bin/init.test.ts +165 -0
- package/bin/init.ts +297 -0
- package/bin/runtime.mjs +105 -0
- package/bin/runtime.test.ts +167 -0
- package/bin/skillTargets.test.ts +108 -0
- package/bin/skillTargets.ts +36 -0
- package/bin/skillTemplates.test.ts +37 -0
- package/bin/tsconfig.json +23 -0
- package/dist/bin/commands.d.ts +24 -0
- package/dist/bin/commands.js +252 -0
- package/dist/bin/init.d.ts +17 -0
- package/dist/bin/init.js +241 -0
- package/dist/bin/runtime.d.mts +39 -0
- package/dist/bin/runtime.mjs +96 -0
- package/dist/bin/skillTargets.d.ts +13 -0
- package/dist/bin/skillTargets.js +22 -0
- package/dist/server/agents/claudeAdapter.d.ts +8 -0
- package/dist/server/agents/claudeAdapter.js +190 -0
- package/dist/server/agents/claudeParse.d.ts +2 -0
- package/dist/server/agents/claudeParse.js +162 -0
- package/dist/server/agents/codexAdapter.d.ts +13 -0
- package/dist/server/agents/codexAdapter.js +174 -0
- package/dist/server/agents/codexParse.d.ts +2 -0
- package/dist/server/agents/codexParse.js +74 -0
- package/dist/server/agents/detect.d.ts +23 -0
- package/dist/server/agents/detect.js +35 -0
- package/dist/server/agents/gitScope.d.ts +24 -0
- package/dist/server/agents/gitScope.js +95 -0
- package/dist/server/agents/modelRejectionHint.d.ts +8 -0
- package/dist/server/agents/modelRejectionHint.js +12 -0
- package/dist/server/agents/prompt.d.ts +79 -0
- package/dist/server/agents/prompt.js +364 -0
- package/dist/server/agents/runManager.d.ts +90 -0
- package/dist/server/agents/runManager.js +259 -0
- package/dist/server/agents/types.d.ts +15 -0
- package/dist/server/agents/types.js +1 -0
- package/dist/server/apiStore.d.ts +60 -0
- package/dist/server/apiStore.js +249 -0
- package/dist/server/auth/enforce.d.ts +1 -0
- package/dist/server/auth/enforce.js +6 -0
- package/dist/server/auth/types.d.ts +1 -0
- package/dist/server/auth/types.js +1 -0
- package/dist/server/auth/verifiers.d.ts +1 -0
- package/dist/server/auth/verifiers.js +4 -0
- package/dist/server/authAttach.d.ts +19 -0
- package/dist/server/authAttach.js +79 -0
- package/dist/server/cli.d.ts +7 -0
- package/dist/server/cli.js +804 -0
- package/dist/server/client.d.ts +130 -0
- package/dist/server/client.js +247 -0
- package/dist/server/environments.d.ts +103 -0
- package/dist/server/environments.js +486 -0
- package/dist/server/flowStore.d.ts +37 -0
- package/dist/server/flowStore.js +117 -0
- package/dist/server/httpOperations.d.ts +32 -0
- package/dist/server/httpOperations.js +62 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1022 -0
- package/dist/server/infrastructure.d.ts +51 -0
- package/dist/server/infrastructure.js +116 -0
- package/dist/server/login.d.ts +21 -0
- package/dist/server/login.js +44 -0
- package/dist/server/mcp.d.ts +1 -0
- package/dist/server/mcp.js +182 -0
- package/dist/server/migrateFlows.d.ts +8 -0
- package/dist/server/migrateFlows.js +25 -0
- package/dist/server/mockHandler.d.ts +15 -0
- package/dist/server/mockHandler.js +35 -0
- package/dist/server/nodesPayload.d.ts +14 -0
- package/dist/server/nodesPayload.js +14 -0
- package/dist/server/normalizeFlow.d.ts +21 -0
- package/dist/server/normalizeFlow.js +48 -0
- package/dist/server/openBrowser.d.ts +8 -0
- package/dist/server/openBrowser.js +16 -0
- package/dist/server/operationResult.d.ts +12 -0
- package/dist/server/operationResult.js +26 -0
- package/dist/server/pathGuard.d.ts +1 -0
- package/dist/server/pathGuard.js +16 -0
- package/dist/server/pathSafety.d.ts +20 -0
- package/dist/server/pathSafety.js +35 -0
- package/dist/server/projectConfig.d.ts +47 -0
- package/dist/server/projectConfig.js +61 -0
- package/dist/server/projectMode.d.ts +26 -0
- package/dist/server/projectMode.js +44 -0
- package/dist/server/redact.d.ts +6 -0
- package/dist/server/redact.js +37 -0
- package/dist/server/runRegistry.d.ts +84 -0
- package/dist/server/runRegistry.js +200 -0
- package/dist/server/runtime/RuntimeAdapter.d.ts +22 -0
- package/dist/server/runtime/RuntimeAdapter.js +1 -0
- package/dist/server/runtime/expressAdapter.d.ts +19 -0
- package/dist/server/runtime/expressAdapter.js +56 -0
- package/dist/server/scenarioTest.d.ts +14 -0
- package/dist/server/scenarioTest.js +66 -0
- package/dist/server/subflowRunner.d.ts +32 -0
- package/dist/server/subflowRunner.js +72 -0
- package/dist/server/testRunner.d.ts +70 -0
- package/dist/server/testRunner.js +151 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +2 -0
- package/dist/src/engine/authVerify.d.ts +33 -0
- package/dist/src/engine/authVerify.js +63 -0
- package/dist/src/engine/diagnostics.d.ts +62 -0
- package/dist/src/engine/diagnostics.js +148 -0
- package/dist/src/engine/executor.d.ts +151 -0
- package/dist/src/engine/executor.js +684 -0
- package/dist/src/engine/httpError.d.ts +7 -0
- package/dist/src/engine/httpError.js +14 -0
- package/dist/src/engine/index.d.ts +11 -0
- package/dist/src/engine/index.js +11 -0
- package/dist/src/engine/output.d.ts +11 -0
- package/dist/src/engine/output.js +20 -0
- package/dist/src/engine/publish.d.ts +30 -0
- package/dist/src/engine/publish.js +95 -0
- package/dist/src/engine/registry.d.ts +34 -0
- package/dist/src/engine/registry.js +67 -0
- package/dist/src/engine/scenarios.d.ts +12 -0
- package/dist/src/engine/scenarios.js +19 -0
- package/dist/src/engine/schemaCheck.d.ts +4 -0
- package/dist/src/engine/schemaCheck.js +34 -0
- package/dist/src/engine/trace.d.ts +12 -0
- package/dist/src/engine/trace.js +12 -0
- package/dist/src/engine/types.d.ts +308 -0
- package/dist/src/engine/types.js +1 -0
- package/dist/src/engine/validation.d.ts +26 -0
- package/dist/src/engine/validation.js +318 -0
- package/dist/src/flows/anomaly-flows.d.ts +23 -0
- package/dist/src/flows/anomaly-flows.js +151 -0
- package/dist/src/flows/city-sweep-flow.d.ts +10 -0
- package/dist/src/flows/city-sweep-flow.js +127 -0
- package/dist/src/flows/login-flow.d.ts +13 -0
- package/dist/src/flows/login-flow.js +145 -0
- package/dist/src/flows/pradar-flows.d.ts +5 -0
- package/dist/src/flows/pradar-flows.js +375 -0
- package/dist/src/flows/weather-flow.d.ts +12 -0
- package/dist/src/flows/weather-flow.js +150 -0
- package/dist/src/lib/pathParams.d.ts +3 -0
- package/dist/src/lib/pathParams.js +6 -0
- package/dist/src/nodes/anomaly.d.ts +2 -0
- package/dist/src/nodes/anomaly.js +556 -0
- package/dist/src/nodes/flow-control.d.ts +7 -0
- package/dist/src/nodes/flow-control.js +270 -0
- package/dist/src/nodes/index.d.ts +3 -0
- package/dist/src/nodes/index.js +20 -0
- package/dist/src/nodes/login.d.ts +7 -0
- package/dist/src/nodes/login.js +158 -0
- package/dist/src/nodes/loops.d.ts +11 -0
- package/dist/src/nodes/loops.js +60 -0
- package/dist/src/nodes/pradar/index.d.ts +7 -0
- package/dist/src/nodes/pradar/index.js +9 -0
- package/dist/src/nodes/pradar/logic.d.ts +189 -0
- package/dist/src/nodes/pradar/logic.js +370 -0
- package/dist/src/nodes/pradar/nodes.d.ts +42 -0
- package/dist/src/nodes/pradar/nodes.js +801 -0
- package/dist/src/nodes/requireAuth.d.ts +20 -0
- package/dist/src/nodes/requireAuth.js +48 -0
- package/dist/src/nodes/response.d.ts +8 -0
- package/dist/src/nodes/response.js +33 -0
- package/dist/src/nodes/weather.d.ts +33 -0
- package/dist/src/nodes/weather.js +260 -0
- package/package.json +92 -0
- package/server/agentRoute.test.ts +157 -0
- package/server/agents/__fixtures__/fake-claude-writer.mjs +23 -0
- package/server/agents/__fixtures__/fake-claude.mjs +55 -0
- package/server/agents/__fixtures__/fake-codex-writer.mjs +27 -0
- package/server/agents/__fixtures__/fake-codex.mjs +52 -0
- package/server/agents/__fixtures__/fake-version-empty.mjs +3 -0
- package/server/agents/__fixtures__/fake-version-fail.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-garbage.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-good.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-hang.mjs +3 -0
- package/server/agents/claudeAdapter.test.ts +127 -0
- package/server/agents/claudeAdapter.ts +212 -0
- package/server/agents/claudeParse.ts +193 -0
- package/server/agents/codexAdapter.test.ts +125 -0
- package/server/agents/codexAdapter.ts +198 -0
- package/server/agents/codexParse.test.ts +58 -0
- package/server/agents/codexParse.ts +126 -0
- package/server/agents/detect.test.ts +65 -0
- package/server/agents/detect.ts +43 -0
- package/server/agents/gitScope.test.ts +129 -0
- package/server/agents/gitScope.ts +110 -0
- package/server/agents/modelRejectionHint.test.ts +30 -0
- package/server/agents/modelRejectionHint.ts +14 -0
- package/server/agents/prompt.test.ts +613 -0
- package/server/agents/prompt.ts +527 -0
- package/server/agents/runManager.test.ts +251 -0
- package/server/agents/runManager.ts +286 -0
- package/server/agents/types.ts +17 -0
- package/server/apiMount.test.ts +591 -0
- package/server/apiStore.test.ts +324 -0
- package/server/apiStore.ts +241 -0
- package/server/auth/enforce.test.ts +61 -0
- package/server/auth/enforce.ts +6 -0
- package/server/auth/types.ts +5 -0
- package/server/auth/verifiers.test.ts +37 -0
- package/server/auth/verifiers.ts +9 -0
- package/server/authAttach.test.ts +175 -0
- package/server/authAttach.ts +99 -0
- package/server/cli.ts +847 -0
- package/server/cliAuth.test.ts +229 -0
- package/server/cliCreate.test.ts +131 -0
- package/server/cliDoctor.test.ts +326 -0
- package/server/cliTest.test.ts +735 -0
- package/server/client.ts +314 -0
- package/server/demoProject.test.ts +29 -0
- package/server/diagnosticsRoute.test.ts +169 -0
- package/server/environments.test.ts +620 -0
- package/server/environments.ts +603 -0
- package/server/environmentsRoute.test.ts +385 -0
- package/server/errorWorkflow.test.ts +205 -0
- package/server/flowStore.test.ts +84 -0
- package/server/flowStore.ts +125 -0
- package/server/httpOperations.test.ts +377 -0
- package/server/httpOperations.ts +96 -0
- package/server/index.ts +1111 -0
- package/server/infrastructure.test.ts +154 -0
- package/server/infrastructure.ts +161 -0
- package/server/infrastructureRoute.test.ts +105 -0
- package/server/login.test.ts +153 -0
- package/server/login.ts +67 -0
- package/server/mcp.ts +278 -0
- package/server/migrateFlows.test.ts +55 -0
- package/server/migrateFlows.ts +23 -0
- package/server/mockHandler.test.ts +138 -0
- package/server/mockHandler.ts +52 -0
- package/server/mockRun.test.ts +367 -0
- package/server/mockServe.test.ts +467 -0
- package/server/nodesPayload.test.ts +29 -0
- package/server/nodesPayload.ts +26 -0
- package/server/normalizeFlow.test.ts +80 -0
- package/server/normalizeFlow.ts +59 -0
- package/server/openBrowser.test.ts +20 -0
- package/server/openBrowser.ts +22 -0
- package/server/operationResult.test.ts +67 -0
- package/server/operationResult.ts +27 -0
- package/server/pathGuard.test.ts +19 -0
- package/server/pathGuard.ts +12 -0
- package/server/pathSafety.test.ts +38 -0
- package/server/pathSafety.ts +33 -0
- package/server/projectConfig.test.ts +67 -0
- package/server/projectConfig.ts +101 -0
- package/server/projectMode.test.ts +106 -0
- package/server/projectMode.ts +59 -0
- package/server/redact.test.ts +88 -0
- package/server/redact.ts +35 -0
- package/server/redactEgress.test.ts +281 -0
- package/server/runRegistry.ts +270 -0
- package/server/runsAuth.test.ts +119 -0
- package/server/runtime/RuntimeAdapter.ts +24 -0
- package/server/runtime/expressAdapter.test.ts +38 -0
- package/server/runtime/expressAdapter.ts +70 -0
- package/server/scenarioTest.test.ts +148 -0
- package/server/scenarioTest.ts +88 -0
- package/server/setupStatus.test.ts +127 -0
- package/server/subflowRunner.ts +104 -0
- package/server/testRunner.ts +216 -0
- package/server/tsconfig.json +20 -0
- package/server/workflowTestRoute.test.ts +297 -0
- package/src/App.tsx +233 -0
- package/src/components/AgentConsole.tsx +461 -0
- package/src/components/BranchRulesEditor.tsx +156 -0
- package/src/components/CreateModal.tsx +275 -0
- package/src/components/Dock.tsx +487 -0
- package/src/components/EnvironmentDialog.tsx +569 -0
- package/src/components/EnvironmentPicker.tsx +357 -0
- package/src/components/EnvironmentsDialog.tsx +144 -0
- package/src/components/ExecutionPager.tsx +67 -0
- package/src/components/InfraPanel.test.tsx +103 -0
- package/src/components/InfraPanel.tsx +171 -0
- package/src/components/Inspector.tsx +1182 -0
- package/src/components/Json.tsx +50 -0
- package/src/components/JsonModal.tsx +52 -0
- package/src/components/LogMessage.tsx +61 -0
- package/src/components/NodeRunModal.tsx +213 -0
- package/src/components/RunLogPanel.tsx +397 -0
- package/src/components/RunbookView.tsx +1085 -0
- package/src/components/Scenarios.tsx +476 -0
- package/src/components/SettingsDialog.tsx +229 -0
- package/src/components/Sidebar.tsx +436 -0
- package/src/components/StatusBar.tsx +302 -0
- package/src/components/Toolbar.tsx +663 -0
- package/src/components/WelcomeDialog.test.tsx +107 -0
- package/src/components/WelcomeDialog.tsx +412 -0
- package/src/components/agentMarkdown.test.tsx +91 -0
- package/src/components/agentMarkdown.tsx +158 -0
- package/src/components/ui/badge.tsx +31 -0
- package/src/components/ui/button.tsx +46 -0
- package/src/components/ui/combobox.tsx +114 -0
- package/src/components/ui/command.tsx +82 -0
- package/src/components/ui/dialog.tsx +73 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/popover.tsx +32 -0
- package/src/components/ui/resizable.tsx +44 -0
- package/src/components/ui/tabs.tsx +36 -0
- package/src/config.ts +4 -0
- package/src/engine/authVerify.ts +81 -0
- package/src/engine/diagnostics.test.ts +437 -0
- package/src/engine/diagnostics.ts +211 -0
- package/src/engine/executor.test.ts +1339 -0
- package/src/engine/executor.ts +840 -0
- package/src/engine/httpError.test.ts +12 -0
- package/src/engine/httpError.ts +16 -0
- package/src/engine/index.ts +11 -0
- package/src/engine/output.ts +21 -0
- package/src/engine/publish.test.ts +176 -0
- package/src/engine/publish.ts +127 -0
- package/src/engine/registry.test.ts +64 -0
- package/src/engine/registry.ts +80 -0
- package/src/engine/scenarios.test.ts +55 -0
- package/src/engine/scenarios.ts +29 -0
- package/src/engine/schemaCheck.test.ts +21 -0
- package/src/engine/schemaCheck.ts +35 -0
- package/src/engine/trace.test.ts +19 -0
- package/src/engine/trace.ts +23 -0
- package/src/engine/types.test.ts +22 -0
- package/src/engine/types.ts +316 -0
- package/src/engine/validation.test.ts +314 -0
- package/src/engine/validation.ts +354 -0
- package/src/flows/anomaly-flows.test.ts +81 -0
- package/src/flows/anomaly-flows.ts +202 -0
- package/src/flows/city-sweep-flow.ts +131 -0
- package/src/flows/flows.test.ts +30 -0
- package/src/flows/login-flow.ts +150 -0
- package/src/flows/pradar-flows.test.ts +204 -0
- package/src/flows/pradar-flows.ts +419 -0
- package/src/flows/weather-flow.ts +154 -0
- package/src/globals.css +147 -0
- package/src/lib/pathParams.test.ts +24 -0
- package/src/lib/pathParams.ts +6 -0
- package/src/lib/registerLens.test.ts +79 -0
- package/src/lib/registerLens.ts +59 -0
- package/src/lib/runbookModel.test.ts +61 -0
- package/src/lib/runbookModel.ts +290 -0
- package/src/lib/runbookProjection.test.ts +417 -0
- package/src/lib/runbookProjection.ts +254 -0
- package/src/lib/useTailAnchor.ts +53 -0
- package/src/lib/utils.ts +7 -0
- package/src/main.tsx +13 -0
- package/src/nodes/anomaly.test.ts +98 -0
- package/src/nodes/anomaly.ts +637 -0
- package/src/nodes/effects-scan.test.ts +44 -0
- package/src/nodes/flow-control.test.ts +280 -0
- package/src/nodes/flow-control.ts +305 -0
- package/src/nodes/index.ts +22 -0
- package/src/nodes/login.test.ts +81 -0
- package/src/nodes/login.ts +186 -0
- package/src/nodes/loops.ts +69 -0
- package/src/nodes/pradar/index.ts +11 -0
- package/src/nodes/pradar/logic.test.ts +288 -0
- package/src/nodes/pradar/logic.ts +582 -0
- package/src/nodes/pradar/nodes.test.ts +146 -0
- package/src/nodes/pradar/nodes.ts +955 -0
- package/src/nodes/requireAuth.test.ts +75 -0
- package/src/nodes/requireAuth.ts +55 -0
- package/src/nodes/response.test.ts +33 -0
- package/src/nodes/response.ts +39 -0
- package/src/nodes/traceDetail.test.ts +39 -0
- package/src/nodes/weather.test.ts +65 -0
- package/src/nodes/weather.ts +306 -0
- package/src/store/agentClient.test.ts +103 -0
- package/src/store/agentClient.ts +131 -0
- package/src/store/apiTree.test.ts +17 -0
- package/src/store/apiTree.ts +73 -0
- package/src/store/builderStore.test.ts +1234 -0
- package/src/store/builderStore.ts +1879 -0
- package/src/store/infraClient.ts +63 -0
- package/src/store/nodeMeta.test.ts +24 -0
- package/src/store/nodeMeta.ts +21 -0
- package/src/store/persistence.test.ts +15 -0
- package/src/store/persistence.ts +54 -0
- package/src/store/serverRunner.ts +381 -0
- package/src/store/setupClient.ts +57 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/studio-dist/assets/index-DNJwW-hM.css +1 -0
- package/studio-dist/assets/index-O26dKRjW.js +65 -0
- package/studio-dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/studio-dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/studio-dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/studio-dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/studio-dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/studio-dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/studio-dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/studio-dist/favicon.svg +1 -0
- package/studio-dist/icons.svg +24 -0
- package/studio-dist/index.html +14 -0
- package/templates/skills/emberflow-basics/SKILL.md +316 -0
- package/templates/skills/emberflow-model-process/SKILL.md +209 -0
- package/templates/skills/emberflow-new-workflow/SKILL.md +211 -0
- package/templates/skills/emberflow-review-workflow/SKILL.md +148 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { CheckIcon, ChevronDownIcon, HistoryIcon, Loader2Icon, Maximize2Icon, ShieldIcon, TheaterIcon, XIcon } from 'lucide-react';
|
|
3
|
+
import { Badge } from '@/components/ui/badge';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import {
|
|
6
|
+
Command,
|
|
7
|
+
CommandEmpty,
|
|
8
|
+
CommandGroup,
|
|
9
|
+
CommandInput,
|
|
10
|
+
CommandItem,
|
|
11
|
+
CommandList,
|
|
12
|
+
} from '@/components/ui/command';
|
|
13
|
+
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
|
14
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
15
|
+
import { useBuilderStore } from '../store/builderStore';
|
|
16
|
+
import { useTailAnchor } from '../lib/useTailAnchor';
|
|
17
|
+
import { ExecutionPager } from './ExecutionPager';
|
|
18
|
+
import { Json } from './Json';
|
|
19
|
+
import { LogMessage } from './LogMessage';
|
|
20
|
+
import { JsonModal } from './JsonModal';
|
|
21
|
+
import { cn } from '@/lib/utils';
|
|
22
|
+
import { filterLogs, formatDuration, payloadOpenByDefault } from '@/lib/registerLens';
|
|
23
|
+
import type { ViewRegister } from '@/lib/registerLens';
|
|
24
|
+
import type { WorkflowRun } from '../engine';
|
|
25
|
+
import { InfraPanel } from './InfraPanel';
|
|
26
|
+
import { fetchInfrastructure, type InfrastructureResponse } from '../store/infraClient';
|
|
27
|
+
import { fetchAvailableAgents } from '../store/agentClient';
|
|
28
|
+
|
|
29
|
+
const statusDot: Record<string, string> = {
|
|
30
|
+
succeeded: 'bg-success',
|
|
31
|
+
failed: 'bg-destructive',
|
|
32
|
+
cancelled: 'bg-muted-foreground',
|
|
33
|
+
running: 'bg-highlight animate-pulse',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function runDuration(run: WorkflowRun, register: ViewRegister): string {
|
|
37
|
+
if (!run.completedAt) return '…';
|
|
38
|
+
const ms = new Date(run.completedAt).getTime() - new Date(run.startedAt).getTime();
|
|
39
|
+
return formatDuration(ms, register);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function runTime(run: WorkflowRun): string {
|
|
43
|
+
return new Date(run.startedAt).toLocaleTimeString();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Environment badge + safe-mode shield for a recorded run. Absent on legacy runs. */
|
|
47
|
+
function EnvChip({ run }: { run: WorkflowRun }) {
|
|
48
|
+
const environments = useBuilderStore((s) => s.environments);
|
|
49
|
+
if (!run.environment) return null;
|
|
50
|
+
const isProtected = environments.find((e) => e.name === run.environment)?.protected ?? false;
|
|
51
|
+
return (
|
|
52
|
+
<span className="flex shrink-0 items-center gap-1">
|
|
53
|
+
<Badge
|
|
54
|
+
variant="outline"
|
|
55
|
+
className={cn(
|
|
56
|
+
'text-[9px]',
|
|
57
|
+
isProtected && 'border-destructive/50 text-destructive-foreground',
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
{run.environment}
|
|
61
|
+
</Badge>
|
|
62
|
+
{run.safeMode && <ShieldIcon className="size-3 text-success" />}
|
|
63
|
+
</span>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Shows the viewed run (latest by default) and lets the user step back in history. */
|
|
68
|
+
function RunPicker() {
|
|
69
|
+
const flowId = useBuilderStore((s) => s.flow.id);
|
|
70
|
+
const register = useBuilderStore((s) => s.viewRegister);
|
|
71
|
+
const run = useBuilderStore((s) => s.run);
|
|
72
|
+
const runHistory = useBuilderStore((s) => s.runHistory);
|
|
73
|
+
const viewRun = useBuilderStore((s) => s.viewRun);
|
|
74
|
+
const [open, setOpen] = useState(false);
|
|
75
|
+
|
|
76
|
+
const runs = runHistory.filter((r) => r.workflowId === flowId);
|
|
77
|
+
if (!run && runs.length === 0) return null;
|
|
78
|
+
|
|
79
|
+
const latestId = runs[0]?.id;
|
|
80
|
+
const viewingLive = run !== null && run.id !== undefined && !runs.some((r) => r.id === run.id);
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
84
|
+
<PopoverTrigger asChild>
|
|
85
|
+
<Button variant="ghost" size="sm" className="ml-auto gap-2 font-normal text-muted-foreground hover:text-foreground">
|
|
86
|
+
{run && (
|
|
87
|
+
<>
|
|
88
|
+
<span className={cn('size-1.5 rounded-full', statusDot[run.status])} />
|
|
89
|
+
<span className="font-mono text-[11px]">
|
|
90
|
+
{runTime(run)} · {runDuration(run, register)}
|
|
91
|
+
</span>
|
|
92
|
+
<EnvChip run={run} />
|
|
93
|
+
{(run.id === latestId || viewingLive) && (
|
|
94
|
+
<Badge variant="outline" className="text-[9px]">latest</Badge>
|
|
95
|
+
)}
|
|
96
|
+
</>
|
|
97
|
+
)}
|
|
98
|
+
{!run && <HistoryIcon className="size-3.5" />}
|
|
99
|
+
<ChevronDownIcon className="size-3 opacity-50" />
|
|
100
|
+
</Button>
|
|
101
|
+
</PopoverTrigger>
|
|
102
|
+
<PopoverContent className="w-72 p-0" align="end">
|
|
103
|
+
<Command>
|
|
104
|
+
<CommandInput placeholder="Search runs…" />
|
|
105
|
+
<CommandList>
|
|
106
|
+
<CommandEmpty>No runs yet.</CommandEmpty>
|
|
107
|
+
<CommandGroup heading={`${runs.length} run${runs.length === 1 ? '' : 's'}`}>
|
|
108
|
+
{runs.map((r, i) => (
|
|
109
|
+
<CommandItem
|
|
110
|
+
key={r.id}
|
|
111
|
+
value={`${runTime(r)} ${r.status} ${r.id}`}
|
|
112
|
+
onSelect={() => {
|
|
113
|
+
viewRun(r.id);
|
|
114
|
+
setOpen(false);
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<CheckIcon
|
|
118
|
+
className={cn('size-3.5', run?.id === r.id ? 'opacity-100' : 'opacity-0')}
|
|
119
|
+
/>
|
|
120
|
+
<span className={cn('size-1.5 shrink-0 rounded-full', statusDot[r.status])} />
|
|
121
|
+
<span className="font-mono text-[11px]">{runTime(r)}</span>
|
|
122
|
+
{r.scenarioName && (
|
|
123
|
+
<Badge variant="outline" className="max-w-28 truncate text-[9px]">
|
|
124
|
+
{r.scenarioName}
|
|
125
|
+
</Badge>
|
|
126
|
+
)}
|
|
127
|
+
{r.errorHandler && (
|
|
128
|
+
<Badge
|
|
129
|
+
variant="outline"
|
|
130
|
+
className="max-w-36 truncate border-warn/40 text-[9px] text-warn"
|
|
131
|
+
title={`Error handler — fired by a failed run of ${r.errorHandler.firedBy}`}
|
|
132
|
+
>
|
|
133
|
+
⚡ handler · {r.errorHandler.firedBy}
|
|
134
|
+
</Badge>
|
|
135
|
+
)}
|
|
136
|
+
{r.mock && (
|
|
137
|
+
<Badge
|
|
138
|
+
variant="outline"
|
|
139
|
+
className="border-warn/40 text-[9px] uppercase text-warn"
|
|
140
|
+
title="This run executed against scenario mocks — nothing real was touched."
|
|
141
|
+
>
|
|
142
|
+
<TheaterIcon className="size-2.5" /> mock
|
|
143
|
+
</Badge>
|
|
144
|
+
)}
|
|
145
|
+
<EnvChip run={r} />
|
|
146
|
+
<span className="ml-auto flex items-center gap-2 font-mono text-[10.5px] text-muted-foreground">
|
|
147
|
+
{runDuration(r, register)}
|
|
148
|
+
{i === 0 && <span className="text-highlight">latest</span>}
|
|
149
|
+
</span>
|
|
150
|
+
</CommandItem>
|
|
151
|
+
))}
|
|
152
|
+
</CommandGroup>
|
|
153
|
+
</CommandList>
|
|
154
|
+
</Command>
|
|
155
|
+
</PopoverContent>
|
|
156
|
+
</Popover>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
function Empty({ children }: { children: React.ReactNode }) {
|
|
162
|
+
return <div className="px-1 py-2.5 text-[12.5px] text-muted-foreground/70">{children}</div>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function OutputTitle({ children }: { children: React.ReactNode }) {
|
|
166
|
+
return (
|
|
167
|
+
<div className="mb-1.5 text-[10px] font-medium uppercase tracking-widest text-muted-foreground">
|
|
168
|
+
{children}
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** A <Json> pane with a hover-revealed "view fullscreen" button — dock panes
|
|
174
|
+
* run small by design, and that's exactly when a full-size look is wanted. */
|
|
175
|
+
function ExpandableJson({ value, onExpand }: { value: unknown; onExpand: () => void }) {
|
|
176
|
+
return (
|
|
177
|
+
<div className="group relative">
|
|
178
|
+
<Json value={value} />
|
|
179
|
+
<Button
|
|
180
|
+
variant="ghost"
|
|
181
|
+
size="icon"
|
|
182
|
+
className="absolute top-1.5 right-1.5 size-6 text-muted-foreground opacity-0 transition-opacity hover:text-foreground group-hover:opacity-100"
|
|
183
|
+
onClick={onExpand}
|
|
184
|
+
aria-label="View full JSON"
|
|
185
|
+
>
|
|
186
|
+
<Maximize2Icon className="size-3.5" />
|
|
187
|
+
</Button>
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The input/output pane pair for a node, given a specific input/output/error triple. */
|
|
193
|
+
function NodeIoPanes({
|
|
194
|
+
label,
|
|
195
|
+
input,
|
|
196
|
+
output,
|
|
197
|
+
error,
|
|
198
|
+
}: {
|
|
199
|
+
label: string;
|
|
200
|
+
input: unknown;
|
|
201
|
+
output: unknown;
|
|
202
|
+
error: string | undefined;
|
|
203
|
+
}) {
|
|
204
|
+
const [modal, setModal] = useState<{ title: string; value: unknown } | null>(null);
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<div className="grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-3.5">
|
|
208
|
+
<div>
|
|
209
|
+
<OutputTitle>{label} · input</OutputTitle>
|
|
210
|
+
{input !== undefined ? (
|
|
211
|
+
<ExpandableJson value={input} onExpand={() => setModal({ title: `${label} · input`, value: input })} />
|
|
212
|
+
) : (
|
|
213
|
+
<Empty>No input captured.</Empty>
|
|
214
|
+
)}
|
|
215
|
+
</div>
|
|
216
|
+
<div>
|
|
217
|
+
<OutputTitle>
|
|
218
|
+
{label} · {error ? 'error' : 'output'}
|
|
219
|
+
</OutputTitle>
|
|
220
|
+
{error ? (
|
|
221
|
+
<pre className="overflow-x-auto rounded-md border border-destructive/50 bg-card p-2.5 font-mono text-[11.5px] text-destructive-foreground">
|
|
222
|
+
{error}
|
|
223
|
+
</pre>
|
|
224
|
+
) : output !== undefined ? (
|
|
225
|
+
<ExpandableJson value={output} onExpand={() => setModal({ title: `${label} · output`, value: output })} />
|
|
226
|
+
) : (
|
|
227
|
+
<Empty>No output captured.</Empty>
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
{modal && (
|
|
231
|
+
<JsonModal
|
|
232
|
+
title={modal.title}
|
|
233
|
+
value={modal.value}
|
|
234
|
+
open
|
|
235
|
+
onOpenChange={(open) => {
|
|
236
|
+
if (!open) setModal(null);
|
|
237
|
+
}}
|
|
238
|
+
/>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const levelColor: Record<string, string> = {
|
|
245
|
+
info: 'text-success',
|
|
246
|
+
debug: 'text-muted-foreground/60',
|
|
247
|
+
warn: 'text-yellow-500',
|
|
248
|
+
error: 'text-destructive',
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* One-line recovery hint shown in the Output tab when a finished run's
|
|
253
|
+
* Response came back 401 on an environment with login auth configured —
|
|
254
|
+
* the likeliest cause is an expired stored session. Offers an inline
|
|
255
|
+
* re-login; after success the user still needs to re-run (the shown run
|
|
256
|
+
* already happened), so we say exactly that instead of pretending.
|
|
257
|
+
*/
|
|
258
|
+
function SessionExpiredHint() {
|
|
259
|
+
const environments = useBuilderStore((s) => s.environments);
|
|
260
|
+
const selectedEnvironment = useBuilderStore((s) => s.selectedEnvironment);
|
|
261
|
+
const loginEnvironment = useBuilderStore((s) => s.loginEnvironment);
|
|
262
|
+
const [pending, setPending] = useState(false);
|
|
263
|
+
const [done, setDone] = useState(false);
|
|
264
|
+
const [error, setError] = useState<string | null>(null);
|
|
265
|
+
|
|
266
|
+
const env = environments.find((e) => e.name === selectedEnvironment);
|
|
267
|
+
if (!env?.auth?.configured) return null;
|
|
268
|
+
|
|
269
|
+
const onLogin = async () => {
|
|
270
|
+
setError(null);
|
|
271
|
+
setPending(true);
|
|
272
|
+
try {
|
|
273
|
+
await loginEnvironment(env.name);
|
|
274
|
+
setDone(true);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
setError(err instanceof Error ? err.message : 'Login failed');
|
|
277
|
+
} finally {
|
|
278
|
+
setPending(false);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
return (
|
|
283
|
+
<div className="mb-3 flex items-center gap-2 rounded-md border border-border bg-secondary/40 px-3 py-1.5 text-[11.5px] text-foreground/80">
|
|
284
|
+
<span className="size-1.5 shrink-0 rounded-full border border-muted-foreground" />
|
|
285
|
+
{done ? (
|
|
286
|
+
<span className="text-success">Logged in — run again to retry.</span>
|
|
287
|
+
) : (
|
|
288
|
+
<>
|
|
289
|
+
<span>Got a 401 — the stored session may have expired.</span>
|
|
290
|
+
<button
|
|
291
|
+
type="button"
|
|
292
|
+
onClick={() => void onLogin()}
|
|
293
|
+
disabled={pending}
|
|
294
|
+
className="flex items-center gap-1 font-medium text-highlight transition-colors hover:underline disabled:cursor-wait disabled:opacity-60"
|
|
295
|
+
>
|
|
296
|
+
{pending && <Loader2Icon className="size-3 animate-spin" />}
|
|
297
|
+
{pending ? 'Logging in…' : 'Re-log in'}
|
|
298
|
+
</button>
|
|
299
|
+
</>
|
|
300
|
+
)}
|
|
301
|
+
{error && <span className="truncate text-destructive">{error}</span>}
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Same disabled-state tooltip as the Welcome checklist's Scout row. */
|
|
307
|
+
const NO_AGENT_REASON = 'Detect a coding agent first';
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Fetch + scout wiring around the presentational InfraPanel. Loads
|
|
311
|
+
* GET /infrastructure when the Infra tab mounts, and re-fetches whenever the
|
|
312
|
+
* active agent run finishes (a completed scout writes the manifest). The scout
|
|
313
|
+
* button shares the Welcome checklist's dispatch (`beginInfrastructureScout`)
|
|
314
|
+
* and its no-agent-CLI gating (fetched once on mount, mirroring WelcomeDialog).
|
|
315
|
+
*/
|
|
316
|
+
export function InfraTab() {
|
|
317
|
+
const beginInfrastructureScout = useBuilderStore((s) => s.beginInfrastructureScout);
|
|
318
|
+
const agentRun = useBuilderStore((s) => s.agentRun);
|
|
319
|
+
const [data, setData] = useState<InfrastructureResponse | null>(null);
|
|
320
|
+
// Disabled until the fetch resolves — same caution as WelcomeDialog, which
|
|
321
|
+
// shows nothing actionable until /setup-status returns rather than
|
|
322
|
+
// optimistically enabling an action that needs an agent CLI.
|
|
323
|
+
const [hasAgent, setHasAgent] = useState(false);
|
|
324
|
+
const agentRunStatus = agentRun?.status;
|
|
325
|
+
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
// Skip refetching mid-run — only the terminal transition matters, and a
|
|
328
|
+
// running scout hasn't written the manifest yet.
|
|
329
|
+
if (agentRunStatus === 'running') return;
|
|
330
|
+
let cancelled = false;
|
|
331
|
+
void fetchInfrastructure().then((d) => {
|
|
332
|
+
if (!cancelled) setData(d);
|
|
333
|
+
});
|
|
334
|
+
return () => {
|
|
335
|
+
cancelled = true;
|
|
336
|
+
};
|
|
337
|
+
}, [agentRunStatus]);
|
|
338
|
+
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
let cancelled = false;
|
|
341
|
+
void fetchAvailableAgents().then((agents) => {
|
|
342
|
+
if (!cancelled) setHasAgent(agents.length > 0);
|
|
343
|
+
});
|
|
344
|
+
return () => {
|
|
345
|
+
cancelled = true;
|
|
346
|
+
};
|
|
347
|
+
}, []);
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<InfraPanel
|
|
351
|
+
data={data}
|
|
352
|
+
onScout={beginInfrastructureScout}
|
|
353
|
+
scouting={agentRunStatus === 'running'}
|
|
354
|
+
canScout={hasAgent}
|
|
355
|
+
canScoutReason={NO_AGENT_REASON}
|
|
356
|
+
/>
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export function Dock() {
|
|
361
|
+
const rawLogs = useBuilderStore((s) => s.logs);
|
|
362
|
+
const register = useBuilderStore((s) => s.viewRegister);
|
|
363
|
+
const logs = filterLogs(rawLogs, register);
|
|
364
|
+
const openByDefault = payloadOpenByDefault(register);
|
|
365
|
+
const run = useBuilderStore((s) => s.run);
|
|
366
|
+
const flow = useBuilderStore((s) => s.flow);
|
|
367
|
+
const selectedNodeId = useBuilderStore((s) => s.selectedNodeId);
|
|
368
|
+
const tab = useBuilderStore((s) => s.dockTab);
|
|
369
|
+
const setTab = useBuilderStore((s) => s.setDockTab);
|
|
370
|
+
const toggleDock = useBuilderStore((s) => s.toggleDock);
|
|
371
|
+
const { scrollerRef, endRef: logEndRef, detached, jumpToLatest } = useTailAnchor(logs.length);
|
|
372
|
+
|
|
373
|
+
const selectedNode = flow.nodes.find((n) => n.id === selectedNodeId);
|
|
374
|
+
const selectedState = selectedNodeId ? run?.nodeStates[selectedNodeId] : undefined;
|
|
375
|
+
// Result nodes (internal flows) AND Response nodes (HTTP operations) — the
|
|
376
|
+
// Output tab shows an operation's resulting JSON, which for an HTTP op is the
|
|
377
|
+
// Response node's { status, body }.
|
|
378
|
+
const resultNodes = flow.nodes.filter((n) => n.type === 'Result' || n.type === 'Response');
|
|
379
|
+
|
|
380
|
+
return (
|
|
381
|
+
<section className="flex h-full flex-col border-t border-border bg-background">
|
|
382
|
+
<Tabs
|
|
383
|
+
value={tab}
|
|
384
|
+
onValueChange={(v) => setTab(v as 'logs' | 'output' | 'infra')}
|
|
385
|
+
className="min-h-0 flex-1"
|
|
386
|
+
>
|
|
387
|
+
<TabsList className="shrink-0 pr-1.5">
|
|
388
|
+
<TabsTrigger value="logs">
|
|
389
|
+
Logs
|
|
390
|
+
{logs.length > 0 && (
|
|
391
|
+
<Badge variant="mono" className="text-[9px]">{logs.length}</Badge>
|
|
392
|
+
)}
|
|
393
|
+
</TabsTrigger>
|
|
394
|
+
<TabsTrigger value="output">Output</TabsTrigger>
|
|
395
|
+
<TabsTrigger value="infra">Infra</TabsTrigger>
|
|
396
|
+
<RunPicker />
|
|
397
|
+
<Button
|
|
398
|
+
variant="ghost"
|
|
399
|
+
size="icon"
|
|
400
|
+
className="size-6 shrink-0 text-muted-foreground hover:text-foreground"
|
|
401
|
+
onClick={toggleDock}
|
|
402
|
+
aria-label="Close panel"
|
|
403
|
+
title="Close panel (⌘J)"
|
|
404
|
+
>
|
|
405
|
+
<XIcon className="size-3.5" />
|
|
406
|
+
</Button>
|
|
407
|
+
</TabsList>
|
|
408
|
+
|
|
409
|
+
<TabsContent value="logs" className="relative overflow-auto px-3.5 py-2" ref={scrollerRef as unknown as React.Ref<HTMLDivElement>}>
|
|
410
|
+
{detached && (
|
|
411
|
+
<button
|
|
412
|
+
type="button"
|
|
413
|
+
onClick={jumpToLatest}
|
|
414
|
+
className="sticky top-0 left-1/2 z-10 -translate-x-1/2 rounded-full border border-highlight/40 bg-card px-3 py-0.5 text-[10.5px] text-highlight shadow-md hover:bg-secondary"
|
|
415
|
+
>
|
|
416
|
+
↓ latest
|
|
417
|
+
</button>
|
|
418
|
+
)}
|
|
419
|
+
{logs.length === 0 && <Empty>Run the flow to see logs.</Empty>}
|
|
420
|
+
{logs.map((line, i) => (
|
|
421
|
+
<div key={i} className="flex items-baseline gap-3 py-0.5 font-mono text-[11.5px]">
|
|
422
|
+
<span className="shrink-0 text-muted-foreground/50">{line.timestamp.slice(11, 19)}</span>
|
|
423
|
+
<span
|
|
424
|
+
className={`w-11 shrink-0 text-[10px] uppercase tracking-wider ${levelColor[line.level] ?? ''}`}
|
|
425
|
+
>
|
|
426
|
+
{line.level}
|
|
427
|
+
</span>
|
|
428
|
+
<span className="min-w-32 shrink-0 text-foreground/80">{line.nodeLabel ?? '—'}</span>
|
|
429
|
+
<LogMessage message={line.message} defaultOpen={openByDefault} />
|
|
430
|
+
</div>
|
|
431
|
+
))}
|
|
432
|
+
<div ref={logEndRef} />
|
|
433
|
+
</TabsContent>
|
|
434
|
+
|
|
435
|
+
<TabsContent value="output" className="overflow-auto px-3.5 py-2">
|
|
436
|
+
{selectedNode ? (
|
|
437
|
+
selectedState?.executions && selectedState.executions.length > 1 ? (
|
|
438
|
+
<ExecutionPager executions={selectedState.executions}>
|
|
439
|
+
{(record) => (
|
|
440
|
+
<NodeIoPanes
|
|
441
|
+
label={selectedNode.label}
|
|
442
|
+
input={record.input}
|
|
443
|
+
output={record.output}
|
|
444
|
+
error={record.error}
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
447
|
+
</ExecutionPager>
|
|
448
|
+
) : (
|
|
449
|
+
<NodeIoPanes
|
|
450
|
+
label={selectedNode.label}
|
|
451
|
+
input={selectedState?.input}
|
|
452
|
+
output={selectedState?.output}
|
|
453
|
+
error={selectedState?.error}
|
|
454
|
+
/>
|
|
455
|
+
)
|
|
456
|
+
) : resultNodes.length > 0 && run ? (
|
|
457
|
+
<>
|
|
458
|
+
{resultNodes.some((n) => {
|
|
459
|
+
const out = run.nodeStates[n.id]?.output as { status?: unknown } | undefined;
|
|
460
|
+
return out?.status === 401;
|
|
461
|
+
}) && <SessionExpiredHint key={run.id} />}
|
|
462
|
+
<div className="grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-3.5">
|
|
463
|
+
{resultNodes.map((n) => (
|
|
464
|
+
<div key={n.id}>
|
|
465
|
+
<OutputTitle>{n.label}</OutputTitle>
|
|
466
|
+
{run.nodeStates[n.id]?.output !== undefined ? (
|
|
467
|
+
<Json value={run.nodeStates[n.id].output} />
|
|
468
|
+
) : (
|
|
469
|
+
<Empty>No result yet.</Empty>
|
|
470
|
+
)}
|
|
471
|
+
</div>
|
|
472
|
+
))}
|
|
473
|
+
</div>
|
|
474
|
+
</>
|
|
475
|
+
) : (
|
|
476
|
+
<Empty>Run the flow to see output.</Empty>
|
|
477
|
+
)}
|
|
478
|
+
</TabsContent>
|
|
479
|
+
|
|
480
|
+
<TabsContent value="infra" className="overflow-auto px-3.5 py-2.5">
|
|
481
|
+
<InfraTab />
|
|
482
|
+
</TabsContent>
|
|
483
|
+
|
|
484
|
+
</Tabs>
|
|
485
|
+
</section>
|
|
486
|
+
);
|
|
487
|
+
}
|