From abe6b7828b2aa2529739b60fa29f33256a23f4ec Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Mon, 18 Aug 2025 17:00:52 +0200 Subject: [PATCH] Fix run input tab for filters (#13961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous step id was still calculated the old way for step following triggers: if first step in the array, means it follows the trigger. It was not working for steps inserted between trigger and first step. Removing that code for good. Before Capture d’écran 2025-08-18 à 16 34
50 After Capture d’écran 2025-08-18 à 16 34
18 --- .../components/WorkflowRunStepInputDetail.tsx | 15 +- .../getWorkflowPreviousStepId.test.ts | 239 ------------------ .../utils/getWorkflowPreviousStepId.ts | 22 -- 3 files changed, 4 insertions(+), 272 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/utils/__tests__/getWorkflowPreviousStepId.test.ts delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-steps/utils/getWorkflowPreviousStepId.ts diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx index 9ea77abadb..398edf8df8 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepInputDetail.tsx @@ -3,7 +3,6 @@ import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThro import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow'; import { WorkflowRunStepJsonContainer } from '@/workflow/workflow-steps/components/WorkflowRunStepJsonContainer'; import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader'; -import { getWorkflowPreviousStepId } from '@/workflow/workflow-steps/utils/getWorkflowPreviousStepId'; import { getWorkflowRunStepContext } from '@/workflow/workflow-steps/utils/getWorkflowRunStepContext'; import { getWorkflowVariablesUsedInStep } from '@/workflow/workflow-steps/utils/getWorkflowVariablesUsedInStep'; import { getActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/utils/getActionHeaderTypeOrThrow'; @@ -19,8 +18,8 @@ import { JsonTreeContextProvider, type ShouldExpandNodeInitiallyProps, } from 'twenty-ui/json-visualizer'; -import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; import { type JsonValue } from 'type-fest'; +import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { const { t, i18n } = useLingui(); @@ -45,20 +44,12 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { return null; } - const previousStepId = getWorkflowPreviousStepId({ - stepId, - steps: workflowRun.state.flow.steps, - }); - - if (previousStepId === undefined) { - return null; - } - const stepDefinition = getStepDefinitionOrThrow({ stepId, trigger: workflowRun.state.flow.trigger, steps: workflowRun.state.flow.steps, }); + if (stepDefinition?.type !== 'action') { throw new Error('The input tab must be rendered with an action step.'); } @@ -86,6 +77,8 @@ export const WorkflowRunStepInputDetail = ({ stepId }: { stepId: string }) => { throw new Error('The input tab must be rendered with a non-empty context.'); } + const previousStepId = stepContext[stepContext.length - 1].id; + const getNodeHighlighting: GetJsonNodeHighlighting = (keyPath: string) => { if (variablesUsedInStep.has(keyPath)) { return 'blue'; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/utils/__tests__/getWorkflowPreviousStepId.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/utils/__tests__/getWorkflowPreviousStepId.test.ts deleted file mode 100644 index 2975603193..0000000000 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/utils/__tests__/getWorkflowPreviousStepId.test.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { type WorkflowStep } from '@/workflow/types/Workflow'; -import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; -import { getWorkflowPreviousStepId } from '../getWorkflowPreviousStepId'; - -describe('getWorkflowPreviousStepId', () => { - const mockSteps: WorkflowStep[] = [ - { - id: 'step-1', - name: 'First Step', - type: 'CREATE_RECORD', - valid: true, - nextStepIds: ['step-2'], - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - }, - outputSchema: {}, - }, - } as WorkflowStep, - { - id: 'step-2', - name: 'Second Step', - type: 'UPDATE_RECORD', - valid: true, - nextStepIds: ['step-3'], - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - objectRecordId: 'test-id', - fieldsToUpdate: ['name'], - }, - outputSchema: {}, - }, - } as WorkflowStep, - { - id: 'step-3', - name: 'Third Step', - type: 'SEND_EMAIL', - valid: true, - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - connectedAccountId: 'account-id', - email: 'test@example.com', - }, - outputSchema: {}, - }, - } as WorkflowStep, - ]; - - it('should return undefined for TRIGGER_STEP_ID', () => { - const result = getWorkflowPreviousStepId({ - stepId: TRIGGER_STEP_ID, - steps: mockSteps, - }); - - expect(result).toBeUndefined(); - }); - - it('should return TRIGGER_STEP_ID for first step', () => { - const result = getWorkflowPreviousStepId({ - stepId: 'step-1', - steps: mockSteps, - }); - - expect(result).toBe(TRIGGER_STEP_ID); - }); - - it('should return previous step ID for middle step', () => { - const result = getWorkflowPreviousStepId({ - stepId: 'step-2', - steps: mockSteps, - }); - - expect(result).toBe('step-1'); - }); - - it('should return previous step ID for last step', () => { - const result = getWorkflowPreviousStepId({ - stepId: 'step-3', - steps: mockSteps, - }); - - expect(result).toBe('step-2'); - }); - - it('should return undefined for non-existent step', () => { - const result = getWorkflowPreviousStepId({ - stepId: 'non-existent-step', - steps: mockSteps, - }); - - expect(result).toBeUndefined(); - }); - - it('should work with single step', () => { - const singleStep = [mockSteps[0]]; - - const result = getWorkflowPreviousStepId({ - stepId: 'step-1', - steps: singleStep, - }); - - expect(result).toBe(TRIGGER_STEP_ID); - }); - - it('should handle branching workflow with multiple next steps', () => { - const branchingSteps: WorkflowStep[] = [ - { - id: 'step-1', - name: 'First Step', - type: 'CREATE_RECORD', - valid: true, - nextStepIds: ['step-2a', 'step-2b'], - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - }, - outputSchema: {}, - }, - } as WorkflowStep, - { - id: 'step-2a', - name: 'Second Step A', - type: 'UPDATE_RECORD', - valid: true, - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - objectRecordId: 'test-id', - fieldsToUpdate: ['name'], - }, - outputSchema: {}, - }, - } as WorkflowStep, - { - id: 'step-2b', - name: 'Second Step B', - type: 'SEND_EMAIL', - valid: true, - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - connectedAccountId: 'account-id', - email: 'test@example.com', - }, - outputSchema: {}, - }, - } as WorkflowStep, - ]; - - const resultA = getWorkflowPreviousStepId({ - stepId: 'step-2a', - steps: branchingSteps, - }); - - const resultB = getWorkflowPreviousStepId({ - stepId: 'step-2b', - steps: branchingSteps, - }); - - expect(resultA).toBe('step-1'); - expect(resultB).toBe('step-1'); - }); - - it('should handle workflow where step is not connected to previous steps', () => { - const disconnectedSteps: WorkflowStep[] = [ - { - id: 'step-1', - name: 'First Step', - type: 'CREATE_RECORD', - valid: true, - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - }, - outputSchema: {}, - }, - } as WorkflowStep, - { - id: 'step-2', - name: 'Disconnected Step', - type: 'UPDATE_RECORD', - valid: true, - settings: { - errorHandlingOptions: { - continueOnFailure: { value: false }, - retryOnFailure: { value: false }, - }, - input: { - objectName: 'Company', - objectRecord: {}, - objectRecordId: 'test-id', - fieldsToUpdate: ['name'], - }, - outputSchema: {}, - }, - } as WorkflowStep, - ]; - - const result = getWorkflowPreviousStepId({ - stepId: 'step-2', - steps: disconnectedSteps, - }); - - expect(result).toBeUndefined(); - }); -}); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/utils/getWorkflowPreviousStepId.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/utils/getWorkflowPreviousStepId.ts deleted file mode 100644 index f3f344b14a..0000000000 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/utils/getWorkflowPreviousStepId.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { type WorkflowStep } from '@/workflow/types/Workflow'; -import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; - -export const getWorkflowPreviousStepId = ({ - stepId, - steps, -}: { - stepId: string; - steps: Array; -}) => { - if (stepId === TRIGGER_STEP_ID) { - return undefined; - } - - if (stepId === steps[0].id) { - return TRIGGER_STEP_ID; - } - - const previousStep = steps.find((step) => step.nextStepIds?.includes(stepId)); - - return previousStep?.id; -};