From d6c2e5043b2b3d277af5848f5babcfa59ec23007 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 17 Sep 2026 10:15:22 +0200 Subject: [PATCH 1/2] feat(webapp): run a workflow from the editor and watch it node by node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting a run navigated away to the inspector, so the graph you had just built disappeared at the moment it became interesting to watch. It now stays: the dialog closes, the run starts, and the editor colours itself. Each connector carries the status of its own step — amber while running, green once succeeded, red on failure. A connector with no step, or one still pending, is left alone rather than dressed in a colour that would claim more than the engine has said. The run id is not threaded between the two sibling features. The canvas already fetched the workflow's latest run to feed the available-data tree, so it simply polls that one instead, through `useRunPolling`, which stops of its own accord at a terminal status. Starting a run invalidates the run list, so the newly created run becomes the latest and the canvas picks it up with nothing to wire between components. This is polling rather than push because the run engine emits no realtime event: none of its `#[transactional]` methods lists `events`. Making the engine publish per-step progress is a backend change of its own, and worth doing before this feature is asked to scale past one editor tab. `Historique d'exécution` still navigates — only the post-start jump is gone. --- .../feature/run-now-feature.test.tsx | 9 +-- .../automation/feature/run-now-feature.tsx | 12 +--- .../feature/workflow-canvas-feature.tsx | 13 +++- .../automation/lib/workflow-runs.test.ts | 25 +++++++ .../src/pages/automation/lib/workflow-runs.ts | 14 ++++ .../pages/automation/ui/connector-node.tsx | 4 ++ .../automation/ui/workflow-canvas.test.tsx | 72 +++++++++++++++++++ .../pages/automation/ui/workflow-canvas.tsx | 20 ++++-- 8 files changed, 146 insertions(+), 23 deletions(-) diff --git a/apps/webapp/src/pages/automation/feature/run-now-feature.test.tsx b/apps/webapp/src/pages/automation/feature/run-now-feature.test.tsx index 9a03001d..417a9222 100644 --- a/apps/webapp/src/pages/automation/feature/run-now-feature.test.tsx +++ b/apps/webapp/src/pages/automation/feature/run-now-feature.test.tsx @@ -166,7 +166,7 @@ describe('RunNowFeature — opening the dialog', () => { }) describe('RunNowFeature — confirming a run', () => { - it('starts the run through the real mutation and navigates to its inspector', async () => { + it('starts the run through the real mutation without leaving the editor', async () => { const user = userEvent.setup() renderFeature((api) => { api.mockMutation('post', WORKFLOW_RUNS_PATH, () => ({ @@ -184,12 +184,9 @@ describe('RunNowFeature — confirming a run', () => { ) await waitFor(() => { - expect(navigateSpy).toHaveBeenCalledWith( - expect.objectContaining({ - params: { workflowId: 'workflow-1', runId: 'run-42' }, - }), - ) + expect(screen.queryByRole('dialog')).toBeNull() }) + expect(navigateSpy).not.toHaveBeenCalled() }) it('shows the failure and keeps the dialog open when the start is refused', async () => { diff --git a/apps/webapp/src/pages/automation/feature/run-now-feature.tsx b/apps/webapp/src/pages/automation/feature/run-now-feature.tsx index 8988f69c..e8a66fa0 100644 --- a/apps/webapp/src/pages/automation/feature/run-now-feature.tsx +++ b/apps/webapp/src/pages/automation/feature/run-now-feature.tsx @@ -61,21 +61,11 @@ function RunNowWorkspace({ async function handleConfirm(payload: unknown) { setStartError(null) try { - const result = await startRun.mutateAsync({ + await startRun.mutateAsync({ path: { organization_id: organizationId, workflow_id: workflowId }, body: { trigger_payload: payload }, }) setOpen(false) - await navigate({ - to: buildOrgPath( - organizationSlug, - '/automatisation/$workflowId/executions/$runId', - ), - params: { - workflowId, - runId: (result.data as { run_id: string }).run_id, - }, - }) } catch (error) { setStartError( error instanceof Error && error.message diff --git a/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.tsx b/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.tsx index 5b8d2685..5a5c79af 100644 --- a/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.tsx +++ b/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.tsx @@ -10,7 +10,7 @@ import { useConnectorCatalogue, useCreateCredential, useEvaluateExpression, - useRun, + useRunPolling, useSaveWorkflowVersion, useWorkflow, type WorkflowDetail, @@ -23,6 +23,7 @@ import { projectGraphErrors, } from '#/pages/automation/lib/validation' import { + aggregateConnectorStatuses, connectorOutputsFromSteps, latestRunId, } from '#/pages/automation/lib/workflow-runs' @@ -85,7 +86,7 @@ function WorkflowCanvasWorkspace({ const eventsQuery = useAutomationEvents(organizationId) const runsQuery = useAutomationRuns(organizationId) const latestId = latestRunId(runsQuery.data?.data ?? [], workflowId) - const runDetailQuery = useRun(organizationId, latestId) + const runDetailQuery = useRunPolling(organizationId, latestId) if ( workflowQuery.isLoading || @@ -128,6 +129,10 @@ function WorkflowCanvasWorkspace({ } : null + const runStatuses = runDetail + ? aggregateConnectorStatuses(runDetail.steps) + : new Map() + return ( ) } @@ -153,6 +159,7 @@ function WorkflowCanvasLoaded({ credentials, events, lastRun, + runStatuses, }: { organizationId: string workflowId: string @@ -162,6 +169,7 @@ function WorkflowCanvasLoaded({ credentials: Schemas.CredentialResponse[] events: Schemas.EventDescriptorResponse[] lastRun: LastRunData | null + runStatuses: Map }) { const saveVersion = useSaveWorkflowVersion() const createCredential = useCreateCredential(organizationId) @@ -260,6 +268,7 @@ function WorkflowCanvasLoaded({ connectorErrors={validation.connectorErrors} events={events} lastRun={lastRun} + runStatuses={runStatuses} onEvaluateExpression={handleEvaluateExpression} credentials={credentials} authSchemes={authSchemes} diff --git a/apps/webapp/src/pages/automation/lib/workflow-runs.test.ts b/apps/webapp/src/pages/automation/lib/workflow-runs.test.ts index 01e3d4ab..261c875b 100644 --- a/apps/webapp/src/pages/automation/lib/workflow-runs.test.ts +++ b/apps/webapp/src/pages/automation/lib/workflow-runs.test.ts @@ -11,6 +11,7 @@ import { latestRunByWorkflow, latestRunId, runDurationMs, + runStatusBorderClass, runTriggerLabel, } from '#/pages/automation/lib/workflow-runs' @@ -361,3 +362,27 @@ describe('canReplay', () => { expect(canReplay('running')).toBe(false) }) }) + +describe('runStatusBorderClass', () => { + it('marks a step in progress amber', () => { + expect(runStatusBorderClass('running')).toBe('border-amber-500') + }) + + it('marks a succeeded step green', () => { + expect(runStatusBorderClass('succeeded')).toBe('border-emerald-500') + }) + + it('marks a failed step red', () => { + expect(runStatusBorderClass('failed')).toBe('border-destructive') + }) + + it('leaves a pending or cancelled step unmarked', () => { + expect(runStatusBorderClass('pending')).toBeNull() + expect(runStatusBorderClass('cancelled')).toBeNull() + }) + + it('leaves a connector with no step at all unmarked', () => { + expect(runStatusBorderClass(null)).toBeNull() + expect(runStatusBorderClass(undefined)).toBeNull() + }) +}) diff --git a/apps/webapp/src/pages/automation/lib/workflow-runs.ts b/apps/webapp/src/pages/automation/lib/workflow-runs.ts index 93f4d843..529837d1 100644 --- a/apps/webapp/src/pages/automation/lib/workflow-runs.ts +++ b/apps/webapp/src/pages/automation/lib/workflow-runs.ts @@ -92,6 +92,20 @@ const STATUS_PRIORITY: Record = { succeeded: 0, } +const RUN_STATUS_BORDER: Record = { + running: 'border-amber-500', + succeeded: 'border-emerald-500', + failed: 'border-destructive', +} + +export function runStatusBorderClass( + status: string | null | undefined, +): string | null { + if (!status) return null + + return RUN_STATUS_BORDER[status] ?? null +} + export function aggregateConnectorStatuses( steps: Schemas.RunStepResponse[], ): Map { diff --git a/apps/webapp/src/pages/automation/ui/connector-node.tsx b/apps/webapp/src/pages/automation/ui/connector-node.tsx index 2304740e..e681a7d9 100644 --- a/apps/webapp/src/pages/automation/ui/connector-node.tsx +++ b/apps/webapp/src/pages/automation/ui/connector-node.tsx @@ -4,6 +4,7 @@ import type { Schemas } from '#/api/api.client' import { Badge } from '#/components/ui/badge' import { cn } from '#/lib/utils' import type { ConnectorValidationError } from '#/pages/automation/lib/validation' +import { runStatusBorderClass } from '#/pages/automation/lib/workflow-runs' import { AddNodeButton } from '#/pages/automation/ui/add-node-button' import { useWorkflowCanvasActions } from '#/pages/automation/ui/workflow-canvas-context' @@ -11,6 +12,7 @@ export interface ConnectorNodeData extends Record { label: string branches: Schemas.BranchDto[] errors: ConnectorValidationError[] + runStatus: string | null connector: Schemas.PlacedConnectorDto } @@ -21,6 +23,7 @@ export function ConnectorNode({ }: NodeProps & { data: ConnectorNodeData }) { const actions = useWorkflowCanvasActions() const hasError = data.errors.length > 0 + const runBorder = runStatusBorderClass(data.runStatus) return (
diff --git a/apps/webapp/src/pages/automation/ui/workflow-canvas.test.tsx b/apps/webapp/src/pages/automation/ui/workflow-canvas.test.tsx index 54807562..d665e341 100644 --- a/apps/webapp/src/pages/automation/ui/workflow-canvas.test.tsx +++ b/apps/webapp/src/pages/automation/ui/workflow-canvas.test.tsx @@ -108,6 +108,7 @@ function Harness({ layout, descriptors, connectorErrors = new Map(), + runStatuses = new Map(), events = [], lastRun = null, onEvaluateExpression = () => Promise.resolve(null), @@ -120,6 +121,7 @@ function Harness({ layout: Map descriptors: Map connectorErrors?: Map + runStatuses?: Map events?: Schemas.EventDescriptorResponse[] lastRun?: LastRunData | null onEvaluateExpression?: WorkflowCanvasProps['onEvaluateExpression'] @@ -140,6 +142,7 @@ function Harness({ layout, descriptors, connectorErrors, + runStatuses, events, lastRun, onEvaluateExpression, @@ -1691,3 +1694,72 @@ describe('WorkflowCanvas — the pane context menu', () => { expect(screen.getByTestId('connector-config-panel')).toBeDefined() }) }) + +describe('WorkflowCanvas — a run in progress', () => { + function borderOf(nodeId: string): string { + const node = screen.getByTestId(`rf__node-${nodeId}`) + return (node.firstElementChild as HTMLElement).className + } + + it('borders each connector by the status of its step', async () => { + const graph: Schemas.GraphDto = { + connectors: [ + connector('c1', SIMPLE_KIND), + connector('c2', SIMPLE_KIND), + connector('c3', SIMPLE_KIND), + ], + edges: [ + { from: 't1', to: 'c1', branch: null }, + { from: 'c1', to: 'c2', branch: null }, + { from: 'c2', to: 'c3', branch: null }, + ], + triggers: [trigger('t1', 'Manual')], + } + + renderHarness({ + graph, + layout: new Map([ + ['t1', { x: -220, y: 0 }], + ['c1', { x: 0, y: 0 }], + ['c2', { x: 200, y: 0 }], + ['c3', { x: 400, y: 0 }], + ]), + descriptors: descriptorMap(SIMPLE_DESCRIPTOR), + runStatuses: new Map([ + ['c1', 'succeeded'], + ['c2', 'running'], + ['c3', 'failed'], + ]), + }) + + await screen.findByTestId('rf__node-c1') + + expect(borderOf('c1')).toContain('border-emerald-500') + expect(borderOf('c2')).toContain('border-amber-500') + expect(borderOf('c3')).toContain('border-destructive') + }) + + it('leaves a connector with no step of its own unmarked', async () => { + const graph: Schemas.GraphDto = { + connectors: [connector('c1', SIMPLE_KIND)], + edges: [{ from: 't1', to: 'c1', branch: null }], + triggers: [trigger('t1', 'Manual')], + } + + renderHarness({ + graph, + layout: new Map([ + ['t1', { x: -220, y: 0 }], + ['c1', { x: 0, y: 0 }], + ]), + descriptors: descriptorMap(SIMPLE_DESCRIPTOR), + runStatuses: new Map([['c1', 'pending']]), + }) + + await screen.findByTestId('rf__node-c1') + + expect(borderOf('c1')).not.toContain('border-amber-500') + expect(borderOf('c1')).not.toContain('border-emerald-500') + expect(borderOf('c1')).not.toContain('border-destructive') + }) +}) diff --git a/apps/webapp/src/pages/automation/ui/workflow-canvas.tsx b/apps/webapp/src/pages/automation/ui/workflow-canvas.tsx index d074530e..4c1ab8d9 100644 --- a/apps/webapp/src/pages/automation/ui/workflow-canvas.tsx +++ b/apps/webapp/src/pages/automation/ui/workflow-canvas.tsx @@ -104,6 +104,7 @@ export interface WorkflowCanvasProps { connectorErrors: Map events: Schemas.EventDescriptorResponse[] lastRun: LastRunData | null + runStatuses: Map onEvaluateExpression: ( template: unknown, context: Schemas.EvaluateContextBody, @@ -134,6 +135,7 @@ function buildInitialNodes( layout: Map, descriptors: Map, connectorErrors: Map, + runStatuses: Map, ): Node[] { const triggerNodes: Node[] = graph.triggers.map((trigger, index) => ({ id: trigger.id, @@ -154,6 +156,7 @@ function buildInitialNodes( label: descriptor?.label ?? connector.id, branches: descriptor?.branches ?? [], errors: connectorErrors.get(connector.id) ?? [], + runStatus: runStatuses.get(connector.id) ?? null, connector, } @@ -240,6 +243,7 @@ export function WorkflowCanvas({ connectorErrors, events, lastRun, + runStatuses, onEvaluateExpression, credentials = [], authSchemes = [], @@ -250,7 +254,7 @@ export function WorkflowCanvas({ onSave, }: WorkflowCanvasProps) { const [nodes, setNodes, onNodesChangeInternal] = useNodesState( - buildInitialNodes(graph, layout, descriptors, connectorErrors), + buildInitialNodes(graph, layout, descriptors, connectorErrors, runStatuses), ) const [edges, setEdges] = useEdgesState(buildInitialEdges(graph)) const [pendingDeleteId, setPendingDeleteId] = useState(null) @@ -276,11 +280,17 @@ export function WorkflowCanvas({ current.map((node) => { const data = node.data as ConnectorNodeData | TriggerNodeData const errors = connectorErrors.get(node.id) ?? [] - if (data.errors === errors) return node - return { ...node, data: { ...data, errors } } + const runStatus = runStatuses.get(node.id) ?? null + if ( + data.errors === errors && + (data as ConnectorNodeData).runStatus === runStatus + ) { + return node + } + return { ...node, data: { ...data, errors, runStatus } } }), ) - }, [connectorErrors, setNodes]) + }, [connectorErrors, runStatuses, setNodes]) const handleNodesChange = useCallback( (changes: NodeChange[]) => { @@ -374,6 +384,7 @@ export function WorkflowCanvas({ label: descriptor.label, branches: descriptor.branches, errors: [], + runStatus: null, connector: newConnector, } const nextNodes = [ @@ -510,6 +521,7 @@ export function WorkflowCanvas({ label: descriptor.label, branches: descriptor.branches, errors: [], + runStatus: null, connector: newConnector, } const nextNodes = [ From c07f5330a675c7e8ee2a00c47c3d36837f2d5877 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Thu, 17 Sep 2026 10:34:48 +0200 Subject: [PATCH 2/2] fix(webapp): drop the example/last-run switch from the data panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The available-data tree made you pick between the example payload and the last run's real values before it would show you anything. Two of the three states that toggle could be in were useless: the example once a run exists, and a disabled last-run button before one does. It now shows the last run's values when there is a run, and the example until then. Nothing to choose, and the panel stops carrying a control whose only job was to be in the wrong position. The three tests covering the toggle are deleted — their subject is gone. The one whose intent survived is rewritten rather than dropped: the tree does still show real values once a run exists, just without a button, and a companion now pins the fallback to the example while no run has happened. --- .../feature/workflow-canvas-feature.test.tsx | 5 +- .../ui/available-data-tree.test.tsx | 36 +------------ .../automation/ui/available-data-tree.tsx | 50 ------------------- .../ui/connector-config-panel.test.tsx | 40 +++++++-------- .../automation/ui/connector-config-panel.tsx | 12 +---- .../automation/ui/workflow-canvas.test.tsx | 8 +-- 6 files changed, 23 insertions(+), 128 deletions(-) diff --git a/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.test.tsx b/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.test.tsx index 9c33527d..6f88d0b3 100644 --- a/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.test.tsx +++ b/apps/webapp/src/pages/automation/feature/workflow-canvas-feature.test.tsx @@ -955,11 +955,8 @@ describe('WorkflowCanvasFeature — the last run', () => { const node = await screen.findByTestId('rf__node-c1') node.click() - const lastRunButton = (await screen.findByRole('button', { - name: 'Dernière exécution', - })) as HTMLButtonElement await waitFor(() => { - expect(lastRunButton.disabled).toBe(false) + expect(screen.getByRole('button', { name: 'trigger' })).toBeDefined() }) }) }) diff --git a/apps/webapp/src/pages/automation/ui/available-data-tree.test.tsx b/apps/webapp/src/pages/automation/ui/available-data-tree.test.tsx index 7879436f..57ba155f 100644 --- a/apps/webapp/src/pages/automation/ui/available-data-tree.test.tsx +++ b/apps/webapp/src/pages/automation/ui/available-data-tree.test.tsx @@ -48,18 +48,14 @@ function renderTree( overrides: Partial[0]> = {}, ) { const onInsert = vi.fn() - const onSourceChange = vi.fn() render( , ) - return { onInsert, onSourceChange } + return { onInsert } } describe('AvailableDataTree — structure', () => { @@ -131,33 +127,3 @@ describe('AvailableDataTree — insertion', () => { ) }) }) - -describe('AvailableDataTree — source toggle', () => { - it('disables the last-run option until a run exists', () => { - renderTree({ hasLastRun: false }) - - const button = screen.getByRole('button', { - name: 'Dernière exécution', - }) as HTMLButtonElement - expect(button.disabled).toBe(true) - }) - - it('reports the requested source once a run exists', async () => { - const user = userEvent.setup() - const { onSourceChange } = renderTree({ hasLastRun: true }) - - await user.click(screen.getByRole('button', { name: 'Dernière exécution' })) - - expect(onSourceChange).toHaveBeenCalledWith('last_run') - }) - - it('marks the active source', () => { - renderTree({ source: 'example' }) - - expect( - screen - .getByRole('button', { name: 'Exemple' }) - .getAttribute('aria-pressed'), - ).toBe('true') - }) -}) diff --git a/apps/webapp/src/pages/automation/ui/available-data-tree.tsx b/apps/webapp/src/pages/automation/ui/available-data-tree.tsx index dc35fd39..52e2299c 100644 --- a/apps/webapp/src/pages/automation/ui/available-data-tree.tsx +++ b/apps/webapp/src/pages/automation/ui/available-data-tree.tsx @@ -1,40 +1,18 @@ import { ChevronDown, ChevronRight } from 'lucide-react' import { useState } from 'react' -import { cn } from '#/lib/utils' import type { DataTreeNode } from '#/pages/automation/lib/data-tree' -export type DataTreeSource = 'example' | 'last_run' - export interface AvailableDataTreeProps { branches: DataTreeNode[] - source: DataTreeSource - hasLastRun: boolean - onSourceChange: (source: DataTreeSource) => void onInsert: (path: string) => void } export function AvailableDataTree({ branches, - source, - hasLastRun, - onSourceChange, onInsert, }: AvailableDataTreeProps) { return (
-
- onSourceChange('example')} - /> - onSourceChange('last_run')} - /> -
{branches.length === 0 ? (

Aucune donnée disponible. @@ -50,34 +28,6 @@ export function AvailableDataTree({ ) } -function SourceButton({ - label, - active, - disabled = false, - onClick, -}: { - label: string - active: boolean - disabled?: boolean - onClick: () => void -}) { - return ( - - ) -} - function TreeNodeItem({ node, onInsert, diff --git a/apps/webapp/src/pages/automation/ui/connector-config-panel.test.tsx b/apps/webapp/src/pages/automation/ui/connector-config-panel.test.tsx index d10da52a..7c471cdc 100644 --- a/apps/webapp/src/pages/automation/ui/connector-config-panel.test.tsx +++ b/apps/webapp/src/pages/automation/ui/connector-config-panel.test.tsx @@ -445,26 +445,34 @@ describe('ConnectorConfigPanel — the available-data tree', () => { expect(screen.getByRole('button', { name: /trigger/ })).toBeDefined() }) - it('disables the last-run toggle until a run exists', () => { + it('shows the real values rather than the example once a run exists', async () => { + const user = userEvent.setup() render( , ) - const button = screen.getByRole('button', { - name: 'Dernière exécution', - }) as HTMLButtonElement - expect(button.disabled).toBe(true) + await user.click(screen.getByRole('button', { name: 'trigger' })) + + expect(screen.getByText('confirmed_name')).toBeDefined() + expect(screen.queryByText('name')).toBeNull() }) - it('switches the same tree to the real values once a run exists', async () => { + it('falls back to the example while no run has happened', async () => { const user = userEvent.setup() render( { tree: [TRIGGER_BRANCH], context: { trigger: { name: 'Julie' }, connectors: {}, loop: null }, }, - lastRunData: { - tree: [LAST_RUN_TRIGGER_BRANCH], - context: { - trigger: { name: 'Real customer' }, - connectors: {}, - loop: null, - }, - }, + lastRunData: null, })} />, ) await user.click(screen.getByRole('button', { name: 'trigger' })) - expect(screen.getByText('name')).toBeDefined() - expect(screen.queryByText('confirmed_name')).toBeNull() - - await user.click(screen.getByRole('button', { name: 'Dernière exécution' })) - expect(screen.getByText('confirmed_name')).toBeDefined() - expect(screen.queryByText('name')).toBeNull() + expect(screen.getByText('name')).toBeDefined() }) }) diff --git a/apps/webapp/src/pages/automation/ui/connector-config-panel.tsx b/apps/webapp/src/pages/automation/ui/connector-config-panel.tsx index 2f0688ae..414a4315 100644 --- a/apps/webapp/src/pages/automation/ui/connector-config-panel.tsx +++ b/apps/webapp/src/pages/automation/ui/connector-config-panel.tsx @@ -19,10 +19,7 @@ import { type ConnectorValidationError, connectorLevelErrors, } from '#/pages/automation/lib/validation' -import { - AvailableDataTree, - type DataTreeSource, -} from '#/pages/automation/ui/available-data-tree' +import { AvailableDataTree } from '#/pages/automation/ui/available-data-tree' import { ConnectorConfigForm, type CredentialCreationPurpose, @@ -102,7 +99,6 @@ export function ConnectorConfigPanel({ const [createState, setCreateState] = useState(null) const [createPending, setCreatePending] = useState(false) const [createError, setCreateError] = useState(null) - const [dataSource, setDataSource] = useState('example') const [activeField, setActiveField] = useState( null, ) @@ -118,8 +114,7 @@ export function ConnectorConfigPanel({ fieldRefs.current.clear() } - const activeSource = - dataSource === 'last_run' && lastRunData ? lastRunData : exampleData + const activeSource = lastRunData ?? exampleData useEffect(() => { if (!activeField) { @@ -297,9 +292,6 @@ export function ConnectorConfigPanel({ { expect(screen.getByText('quote_id')).toBeDefined() }) - it('switches to the real values once a last run is supplied', async () => { + it('shows the real values once a last run is supplied', async () => { renderHarness({ graph: { connectors: [connector('c1', SIMPLE_KIND)], @@ -1444,12 +1444,6 @@ describe('WorkflowCanvas — the available-data tree', () => { fireEvent.click(node) await screen.findByText('Paramètres') - const lastRunButton = screen.getByRole('button', { - name: 'Dernière exécution', - }) as HTMLButtonElement - expect(lastRunButton.disabled).toBe(false) - - fireEvent.click(lastRunButton) fireEvent.click(screen.getByRole('button', { name: 'trigger' })) expect(screen.getByText('quote_id')).toBeDefined()