From ddeba39a2ca8e26817eda4b43a6aee6eaeccfebd Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Tue, 11 Mar 2025 17:38:47 +0100 Subject: [PATCH] Reset step output schema when step is removed (#10762) When a step is deleted in a draft version, its variable are still available in the following steps. This is because step output schema was not reset. We needed either to refresh or to change version so output schema gets updated. This PR: - migrates to a family state global + context not linked to a component - add a reset step output schema function - reset when a step is removed --- .../CommandMenuWorkflowEditStep.tsx | 8 +- .../CommandMenuWorkflowRunViewStep.tsx | 8 +- .../CommandMenuWorkflowViewStep.tsx | 8 +- .../form-types/components/VariableChip.tsx | 17 ++- .../hooks/usePopulateStepsOutputSchema.ts | 76 ------------ .../workflow/hooks/useStepsOutputSchema.ts | 117 +++++++++++++----- .../states/context/WorkflowStepContext.ts | 8 ++ ...WorkflowVersionComponentInstanceContext.ts | 4 - .../stepsOutputSchemaFamilySelector.ts | 26 ++++ .../states/stepsOutputSchemaFamilyState.ts | 16 +-- .../getStepOutputSchemaFamilyStateKey.ts | 4 + .../components/WorkflowDiagramEffect.tsx | 14 ++- .../components/WorkflowRunVisualizer.tsx | 6 +- .../WorkflowRunVisualizerEffect.tsx | 12 ++ .../WorkflowVersionOutputSchemaEffect.tsx | 19 --- .../components/WorkflowVersionVisualizer.tsx | 14 +-- .../WorkflowVersionVisualizerEffect.tsx | 11 +- .../components/WorkflowVisualizer.tsx | 18 ++- .../RightDrawerWorkflowEditStep.tsx | 8 +- .../RightDrawerWorkflowRunViewStep.tsx | 8 +- .../RightDrawerWorkflowViewStep.tsx | 8 +- .../workflow-steps/hooks/useDeleteStep.ts | 12 +- .../useAvailableVariablesInWorkflowStep.ts | 21 ++-- .../decorators/WorkflowStepDecorator.tsx | 14 +-- 24 files changed, 242 insertions(+), 215 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workflow/hooks/usePopulateStepsOutputSchema.ts create mode 100644 packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts delete mode 100644 packages/twenty-front/src/modules/workflow/states/context/WorkflowVersionComponentInstanceContext.ts create mode 100644 packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts create mode 100644 packages/twenty-front/src/modules/workflow/utils/getStepOutputSchemaFamilyStateKey.ts delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect.tsx diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx index 3022c0a5c0..4aeb0a9cdd 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx @@ -2,7 +2,7 @@ import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/w import { CommandMenuWorkflowEditStepContent } from '@/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { isDefined } from 'twenty-shared'; export const CommandMenuWorkflowEditStep = () => { @@ -14,10 +14,10 @@ export const CommandMenuWorkflowEditStep = () => { } return ( - - + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx index 1adff9df21..1ff2c7c74c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStep.tsx @@ -4,7 +4,7 @@ import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail'; import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail'; @@ -66,8 +66,8 @@ export const CommandMenuWorkflowRunViewStep = () => { } return ( - { {activeTabId === 'output' ? ( ) : null} - + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx index 554579f96e..97825c9c1c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStep.tsx @@ -1,5 +1,5 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -7,8 +7,8 @@ export const CommandMenuWorkflowViewStep = () => { const flow = useFlowOrThrow(); const workflowSelectedNode = useWorkflowSelectedNodeOrThrow(); return ( - { steps={flow.steps} readonly /> - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx index e286ff6f2e..1fc18c8b4e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/VariableChip.tsx @@ -1,9 +1,11 @@ -import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; +import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext'; +import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { extractRawVariableNamePart } from '@/workflow/workflow-variables/utils/extractRawVariableNamePart'; import { searchVariableThroughOutputSchema } from '@/workflow/workflow-variables/utils/searchVariableThroughOutputSchema'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; +import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared'; import { IconAlertTriangle, IconX } from 'twenty-ui'; @@ -76,21 +78,26 @@ export const VariableChip = ({ }: VariableChipProps) => { const theme = useTheme(); const { t } = useLingui(); - const { getStepsOutputSchema } = useStepsOutputSchema({}); + const { workflowVersionId } = useWorkflowStepContextOrThrow(); + const stepId = extractRawVariableNamePart({ rawVariableName, part: 'stepId', }); + const stepsOutputSchema = useRecoilValue( + stepsOutputSchemaFamilySelector({ + workflowVersionId, + stepIds: [stepId], + }), + ); if (!isDefined(stepId)) { return null; } - const stepOutputSchema = getStepsOutputSchema([stepId])?.[0]; - const { variableLabel, variablePathLabel } = searchVariableThroughOutputSchema({ - stepOutputSchema, + stepOutputSchema: stepsOutputSchema?.[0], rawVariableName, isFullRecord, }); diff --git a/packages/twenty-front/src/modules/workflow/hooks/usePopulateStepsOutputSchema.ts b/packages/twenty-front/src/modules/workflow/hooks/usePopulateStepsOutputSchema.ts deleted file mode 100644 index 590735ebb2..0000000000 --- a/packages/twenty-front/src/modules/workflow/hooks/usePopulateStepsOutputSchema.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; -import { stepsOutputSchemaComponentFamilyState } from '@/workflow/states/stepsOutputSchemaFamilyState'; -import { WorkflowVersion } from '@/workflow/types/Workflow'; -import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName'; -import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; -import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId'; -import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon'; -import { - OutputSchema, - StepOutputSchema, -} from '@/workflow/workflow-variables/types/StepOutputSchema'; -import { getTriggerStepName } from '@/workflow/workflow-variables/utils/getTriggerStepName'; -import { useRecoilCallback } from 'recoil'; -import { isDefined } from 'twenty-shared'; - -export const usePopulateStepsOutputSchema = ({ - workflowVersionId, -}: { - workflowVersionId: string; -}) => { - const stepsOutputSchemaFamilyState = useRecoilComponentCallbackStateV2( - stepsOutputSchemaComponentFamilyState, - workflowVersionId, - ); - - const populateStepsOutputSchema = useRecoilCallback( - ({ set }) => - (workflowVersion: WorkflowVersion) => { - workflowVersion?.steps?.forEach((step) => { - const stepOutputSchema: StepOutputSchema = { - id: step.id, - name: step.name, - icon: getActionIcon(step.type), - outputSchema: step.settings.outputSchema as OutputSchema, - }; - - set(stepsOutputSchemaFamilyState(step.id), stepOutputSchema); - }); - - const trigger = workflowVersion.trigger; - - if (isDefined(trigger)) { - const triggerIconKey = - trigger.type === 'DATABASE_EVENT' - ? getTriggerIcon({ - type: trigger.type, - eventName: splitWorkflowTriggerEventName( - trigger.settings?.eventName, - ).event, - }) - : getTriggerIcon({ - type: trigger.type, - }); - - const triggerOutputSchema: StepOutputSchema = { - id: TRIGGER_STEP_ID, - name: isDefined(trigger.name) - ? trigger.name - : getTriggerStepName(trigger), - icon: triggerIconKey, - outputSchema: trigger.settings.outputSchema as OutputSchema, - }; - - set( - stepsOutputSchemaFamilyState(TRIGGER_STEP_ID), - triggerOutputSchema, - ); - } - }, - [stepsOutputSchemaFamilyState], - ); - - return { - populateStepsOutputSchema, - }; -}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts b/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts index f7a7e0dd4e..063ab14339 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts @@ -1,40 +1,97 @@ -import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; -import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; -import { stepsOutputSchemaComponentFamilyState } from '@/workflow/states/stepsOutputSchemaFamilyState'; +import { stepsOutputSchemaFamilyState } from '@/workflow/states/stepsOutputSchemaFamilyState'; +import { WorkflowVersion } from '@/workflow/types/Workflow'; +import { getStepOutputSchemaFamilyStateKey } from '@/workflow/utils/getStepOutputSchemaFamilyStateKey'; +import { splitWorkflowTriggerEventName } from '@/workflow/utils/splitWorkflowTriggerEventName'; +import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; +import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId'; +import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon'; +import { + OutputSchema, + StepOutputSchema, +} from '@/workflow/workflow-variables/types/StepOutputSchema'; +import { getTriggerStepName } from '@/workflow/workflow-variables/utils/getTriggerStepName'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared'; -export const useStepsOutputSchema = ({ - instanceIdFromProps, -}: { - instanceIdFromProps?: string; -}) => { - const instanceId = useAvailableComponentInstanceIdOrThrow( - WorkflowVersionComponentInstanceContext, - instanceIdFromProps, - ); +export const useStepsOutputSchema = () => { + const populateStepsOutputSchema = useRecoilCallback( + ({ set }) => + (workflowVersion: WorkflowVersion) => { + workflowVersion.steps?.forEach((step) => { + const stepOutputSchema: StepOutputSchema = { + id: step.id, + name: step.name, + icon: getActionIcon(step.type), + outputSchema: step.settings?.outputSchema as OutputSchema, + }; - const stepsOutputSchemaFamilyState = useRecoilComponentCallbackStateV2( - stepsOutputSchemaComponentFamilyState, - instanceId, - ); + set( + stepsOutputSchemaFamilyState( + getStepOutputSchemaFamilyStateKey(workflowVersion.id, step.id), + ), + stepOutputSchema, + ); + }); - const getStepsOutputSchema = useRecoilCallback( - ({ snapshot }) => - (stepIds: string[]) => { - const stepsOutputSchema = stepIds - .map((stepId) => - snapshot - .getLoadable(stepsOutputSchemaFamilyState(stepId)) - .getValue(), - ) - .filter(isDefined); + const trigger = workflowVersion.trigger; - return stepsOutputSchema; + if (isDefined(trigger)) { + const triggerIconKey = + trigger.type === 'DATABASE_EVENT' + ? getTriggerIcon({ + type: trigger.type, + eventName: splitWorkflowTriggerEventName( + trigger.settings?.eventName, + ).event, + }) + : getTriggerIcon({ + type: trigger.type, + }); + + const triggerOutputSchema: StepOutputSchema = { + id: TRIGGER_STEP_ID, + name: isDefined(trigger.name) + ? trigger.name + : getTriggerStepName(trigger), + icon: triggerIconKey, + outputSchema: trigger.settings?.outputSchema as OutputSchema, + }; + + set( + stepsOutputSchemaFamilyState( + getStepOutputSchemaFamilyStateKey( + workflowVersion.id, + TRIGGER_STEP_ID, + ), + ), + triggerOutputSchema, + ); + } }, - [stepsOutputSchemaFamilyState], + [], ); - return { getStepsOutputSchema }; + const deleteStepOutputSchema = useRecoilCallback( + ({ set }) => + ({ + stepId, + workflowVersionId, + }: { + stepId: string; + workflowVersionId: string; + }) => { + set( + stepsOutputSchemaFamilyState( + getStepOutputSchemaFamilyStateKey(workflowVersionId, stepId), + ), + null, + ); + }, + [], + ); + + return { + populateStepsOutputSchema, + deleteStepOutputSchema, + }; }; diff --git a/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts b/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts new file mode 100644 index 0000000000..3f1962eab9 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts @@ -0,0 +1,8 @@ +import { createRequiredContext } from '~/utils/createRequiredContext'; + +type WorkflowStepContextType = { + workflowVersionId: string; +}; + +export const [WorkflowStepContextProvider, useWorkflowStepContextOrThrow] = + createRequiredContext('WorkflowStepContext'); diff --git a/packages/twenty-front/src/modules/workflow/states/context/WorkflowVersionComponentInstanceContext.ts b/packages/twenty-front/src/modules/workflow/states/context/WorkflowVersionComponentInstanceContext.ts deleted file mode 100644 index dfa548cc91..0000000000 --- a/packages/twenty-front/src/modules/workflow/states/context/WorkflowVersionComponentInstanceContext.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; - -export const WorkflowVersionComponentInstanceContext = - createComponentInstanceContext(); diff --git a/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts b/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts new file mode 100644 index 0000000000..6e4367ed26 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/states/selectors/stepsOutputSchemaFamilySelector.ts @@ -0,0 +1,26 @@ +import { stepsOutputSchemaFamilyState } from '@/workflow/states/stepsOutputSchemaFamilyState'; +import { getStepOutputSchemaFamilyStateKey } from '@/workflow/utils/getStepOutputSchemaFamilyStateKey'; +import { StepOutputSchema } from '@/workflow/workflow-variables/types/StepOutputSchema'; +import { selectorFamily } from 'recoil'; +import { isDefined } from 'twenty-shared'; + +export const stepsOutputSchemaFamilySelector = selectorFamily< + StepOutputSchema[], + { workflowVersionId: string; stepIds: string[] } +>({ + key: 'stepsOutputSchemaFamilySelector', + get: + ({ workflowVersionId, stepIds }) => + ({ get }) => { + const stepsOutputSchema = stepIds + .map((stepId) => + getStepOutputSchemaFamilyStateKey(workflowVersionId, stepId), + ) + .map((stepOutputSchemaKey) => + get(stepsOutputSchemaFamilyState(stepOutputSchemaKey)), + ) + .filter(isDefined); + + return stepsOutputSchema; + }, +}); diff --git a/packages/twenty-front/src/modules/workflow/states/stepsOutputSchemaFamilyState.ts b/packages/twenty-front/src/modules/workflow/states/stepsOutputSchemaFamilyState.ts index 2713dc7089..0e86ad56d9 100644 --- a/packages/twenty-front/src/modules/workflow/states/stepsOutputSchemaFamilyState.ts +++ b/packages/twenty-front/src/modules/workflow/states/stepsOutputSchemaFamilyState.ts @@ -1,10 +1,10 @@ -import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; import { StepOutputSchema } from '@/workflow/workflow-variables/types/StepOutputSchema'; -export const stepsOutputSchemaComponentFamilyState = - createComponentFamilyStateV2({ - key: 'stepsOutputSchemaComponentFamilyState', - defaultValue: null, - componentInstanceContext: WorkflowVersionComponentInstanceContext, - }); +export const stepsOutputSchemaFamilyState = createFamilyState< + StepOutputSchema | null, + string | undefined +>({ + key: 'stepsOutputSchemaFamilyState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/workflow/utils/getStepOutputSchemaFamilyStateKey.ts b/packages/twenty-front/src/modules/workflow/utils/getStepOutputSchemaFamilyStateKey.ts new file mode 100644 index 0000000000..e4fbc84279 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/utils/getStepOutputSchemaFamilyStateKey.ts @@ -0,0 +1,4 @@ +export const getStepOutputSchemaFamilyStateKey = ( + workflowVersionId: string, + stepId: string, +) => `${workflowVersionId}-${stepId}`; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx index 3735632b4f..dbc6de7154 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEffect.tsx @@ -1,4 +1,5 @@ import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; import { flowState } from '@/workflow/states/flowState'; import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState'; import { @@ -22,6 +23,7 @@ export const WorkflowDiagramEffect = ({ }) => { const setWorkflowDiagram = useSetRecoilState(workflowDiagramState); const setFlow = useSetRecoilState(flowState); + const { populateStepsOutputSchema } = useStepsOutputSchema(); const computeAndMergeNewWorkflowDiagram = useRecoilCallback( ({ snapshot, set }) => { @@ -66,8 +68,8 @@ export const WorkflowDiagramEffect = ({ [], ); + const currentVersion = workflowWithCurrentVersion?.currentVersion; useEffect(() => { - const currentVersion = workflowWithCurrentVersion?.currentVersion; if (!isDefined(currentVersion)) { setFlow(undefined); setWorkflowDiagram(undefined); @@ -86,8 +88,16 @@ export const WorkflowDiagramEffect = ({ computeAndMergeNewWorkflowDiagram, setFlow, setWorkflowDiagram, - workflowWithCurrentVersion?.currentVersion, + currentVersion, ]); + useEffect(() => { + if (!isDefined(currentVersion)) { + return; + } + + populateStepsOutputSchema(currentVersion); + }, [currentVersion, populateStepsOutputSchema]); + return null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx index b4890ede33..3b7b9e69b7 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizer.tsx @@ -1,7 +1,5 @@ import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; -import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { WorkflowRunDiagramCanvas } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvas'; -import { WorkflowVersionOutputSchemaEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared'; @@ -15,15 +13,13 @@ export const WorkflowRunVisualizer = ({ workflowRunId: string; }) => { const workflowRun = useWorkflowRun({ workflowRunId }); - const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId); - if (!isDefined(workflowRun) || !isDefined(workflowVersion)) { + if (!isDefined(workflowRun)) { return null; } return ( - ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx index 7db1186b15..293d7452d7 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect.tsx @@ -1,4 +1,6 @@ +import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; +import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { flowState } from '@/workflow/states/flowState'; import { workflowRunIdState } from '@/workflow/states/workflowRunIdState'; import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState'; @@ -13,10 +15,12 @@ export const WorkflowRunVisualizerEffect = ({ workflowRunId: string; }) => { const workflowRun = useWorkflowRun({ workflowRunId }); + const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId); const setWorkflowRunId = useSetRecoilState(workflowRunIdState); const setFlow = useSetRecoilState(flowState); const setWorkflowDiagram = useSetRecoilState(workflowDiagramState); + const { populateStepsOutputSchema } = useStepsOutputSchema(); useEffect(() => { setWorkflowRunId(workflowRunId); @@ -50,5 +54,13 @@ export const WorkflowRunVisualizerEffect = ({ workflowRun?.workflowVersionId, ]); + useEffect(() => { + if (!isDefined(workflowVersion)) { + return; + } + + populateStepsOutputSchema(workflowVersion); + }, [populateStepsOutputSchema, workflowVersion]); + return null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect.tsx deleted file mode 100644 index 53e86178c2..0000000000 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { usePopulateStepsOutputSchema } from '@/workflow/hooks/usePopulateStepsOutputSchema'; -import { WorkflowVersion } from '@/workflow/types/Workflow'; -import { useEffect } from 'react'; - -export const WorkflowVersionOutputSchemaEffect = ({ - workflowVersion, -}: { - workflowVersion: WorkflowVersion; -}) => { - const { populateStepsOutputSchema } = usePopulateStepsOutputSchema({ - workflowVersionId: workflowVersion.id, - }); - - useEffect(() => { - populateStepsOutputSchema(workflowVersion); - }, [populateStepsOutputSchema, workflowVersion]); - - return null; -}; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx index 349812afaa..c4946ecb49 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizer.tsx @@ -1,6 +1,5 @@ import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { WorkflowDiagramCanvasReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonly'; -import { WorkflowVersionOutputSchemaEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect'; import '@xyflow/react/dist/style.css'; import { isDefined } from 'twenty-shared'; @@ -11,10 +10,11 @@ export const WorkflowVersionVisualizer = ({ }) => { const workflowVersion = useWorkflowVersion(workflowVersionId); - return isDefined(workflowVersion) ? ( - <> - - - - ) : null; + if (!isDefined(workflowVersion)) { + return null; + } + + return ( + + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx index e73cafc95d..b1b6733046 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect.tsx @@ -1,3 +1,4 @@ +import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion'; import { flowState } from '@/workflow/states/flowState'; import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState'; @@ -16,7 +17,7 @@ export const WorkflowVersionVisualizerEffect = ({ const setFlow = useSetRecoilState(flowState); const setWorkflowDiagram = useSetRecoilState(workflowDiagramState); - + const { populateStepsOutputSchema } = useStepsOutputSchema(); useEffect(() => { if (!isDefined(workflowVersion)) { setFlow(undefined); @@ -45,5 +46,13 @@ export const WorkflowVersionVisualizerEffect = ({ setWorkflowDiagram(nextWorkflowDiagram); }, [setWorkflowDiagram, workflowVersion]); + useEffect(() => { + if (!isDefined(workflowVersion)) { + return; + } + + populateStepsOutputSchema(workflowVersion); + }, [populateStepsOutputSchema, workflowVersion]); + return null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx index 8bbb4032f2..94d3b69935 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizer.tsx @@ -1,28 +1,24 @@ import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { WorkflowDiagramCanvasEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable'; import { WorkflowDiagramEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramEffect'; -import { WorkflowVersionOutputSchemaEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionOutputSchemaEffect'; import '@xyflow/react/dist/style.css'; import { isDefined } from 'twenty-shared'; export const WorkflowVisualizer = ({ workflowId }: { workflowId: string }) => { const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId); - const workflowVersion = workflowWithCurrentVersion?.currentVersion; + + if (!isDefined(workflowWithCurrentVersion)) { + return null; + } return ( <> - {isDefined(workflowVersion) && ( - - )} - - {isDefined(workflowWithCurrentVersion) ? ( - - ) : null} + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowEditStep.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowEditStep.tsx index a9a2f6cb79..acd9c20f87 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowEditStep.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowEditStep.tsx @@ -1,5 +1,5 @@ import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { workflowIdState } from '@/workflow/states/workflowIdState'; import { RightDrawerWorkflowEditStepContent } from '@/workflow/workflow-steps/components/RightDrawerWorkflowEditStepContent'; import { useRecoilValue } from 'recoil'; @@ -14,10 +14,10 @@ export const RightDrawerWorkflowEditStep = () => { } return ( - - + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx index bb628304f4..b9ffcc93c6 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep.tsx @@ -4,7 +4,7 @@ import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail'; import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail'; @@ -66,8 +66,8 @@ export const RightDrawerWorkflowRunViewStep = () => { } return ( - { {activeTabId === 'output' ? ( ) : null} - + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx index 727ddc656c..95a1dfc70d 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/RightDrawerWorkflowViewStep.tsx @@ -1,5 +1,5 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; @@ -8,8 +8,8 @@ export const RightDrawerWorkflowViewStep = () => { const workflowSelectedNode = useWorkflowSelectedNodeOrThrow(); return ( - { steps={flow.steps} readonly /> - + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts index bb5008497b..4fa6adaeae 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDeleteStep.ts @@ -4,6 +4,7 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; import { useDeleteWorkflowVersionStep } from '@/workflow/hooks/useDeleteWorkflowVersionStep'; import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion'; +import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; import { WorkflowVersion, WorkflowWithCurrentVersion, @@ -20,6 +21,7 @@ export const useDeleteStep = ({ useUpdateOneRecord({ objectNameSingular: CoreObjectNameSingular.WorkflowVersion, }); + const { deleteStepOutputSchema } = useStepsOutputSchema(); const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion(); const { closeRightDrawer } = useRightDrawer(); @@ -36,11 +38,15 @@ export const useDeleteStep = ({ trigger: null, }, }); - return; + } else { + await deleteWorkflowVersionStep({ + workflowVersionId, + stepId, + }); } - await deleteWorkflowVersionStep({ - workflowVersionId, + deleteStepOutputSchema({ stepId, + workflowVersionId, }); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts index 30544f0c5c..2ed6365501 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/hooks/useAvailableVariablesInWorkflowStep.ts @@ -1,5 +1,5 @@ import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; -import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; +import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow'; import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId'; import { @@ -8,6 +8,7 @@ import { } from '@/workflow/workflow-variables/types/StepOutputSchema'; import { filterOutputSchema } from '@/workflow/workflow-variables/utils/filterOutputSchema'; import { isEmptyObject } from '@tiptap/core'; +import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared'; export const useAvailableVariablesInWorkflowStep = ({ @@ -17,7 +18,6 @@ export const useAvailableVariablesInWorkflowStep = ({ }): StepOutputSchema[] => { const workflowSelectedNode = useWorkflowSelectedNodeOrThrow(); const flow = useFlowOrThrow(); - const { getStepsOutputSchema } = useStepsOutputSchema({}); const steps = flow.steps ?? []; @@ -30,17 +30,14 @@ export const useAvailableVariablesInWorkflowStep = ({ previousStepIds.push(step.id); } - const availableStepsOutputSchema: StepOutputSchema[] = - getStepsOutputSchema(previousStepIds).filter(isDefined); + const availableStepsOutputSchema: StepOutputSchema[] = useRecoilValue( + stepsOutputSchemaFamilySelector({ + workflowVersionId: flow.workflowVersionId, + stepIds: [TRIGGER_STEP_ID, ...previousStepIds], + }), + ); - const triggersOutputSchema: StepOutputSchema[] = isDefined(flow.trigger) - ? getStepsOutputSchema([TRIGGER_STEP_ID]).filter(isDefined) - : []; - - const availableVariablesInWorkflowStep = [ - ...availableStepsOutputSchema, - ...triggersOutputSchema, - ] + const availableVariablesInWorkflowStep = availableStepsOutputSchema .map((stepOutputSchema) => { const outputSchema = filterOutputSchema( stepOutputSchema.outputSchema, diff --git a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx index f0f0458ae5..56c71bf333 100644 --- a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx @@ -1,5 +1,5 @@ -import { usePopulateStepsOutputSchema } from '@/workflow/hooks/usePopulateStepsOutputSchema'; -import { WorkflowVersionComponentInstanceContext } from '@/workflow/states/context/WorkflowVersionComponentInstanceContext'; +import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; +import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { workflowIdState } from '@/workflow/states/workflowIdState'; import { WorkflowVersion } from '@/workflow/types/Workflow'; import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState'; @@ -16,9 +16,7 @@ export const WorkflowStepDecorator: Decorator = (Story) => { const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState); const workflowVersion = getWorkflowMock().versions.edges[0] .node as WorkflowVersion; - const { populateStepsOutputSchema } = usePopulateStepsOutputSchema({ - workflowVersionId: workflowVersion.id, - }); + const { populateStepsOutputSchema } = useStepsOutputSchema(); const [ready, setReady] = useState(false); useEffect(() => { @@ -34,10 +32,10 @@ export const WorkflowStepDecorator: Decorator = (Story) => { ]); return ( - {ready && } - + ); };