diff --git a/packages/twenty-e2e-testing/tests/workflow-run.spec.ts b/packages/twenty-e2e-testing/tests/workflow-run.spec.ts
index fd7a3a323..ed5b565cd 100644
--- a/packages/twenty-e2e-testing/tests/workflow-run.spec.ts
+++ b/packages/twenty-e2e-testing/tests/workflow-run.spec.ts
@@ -57,8 +57,7 @@ test('The workflow run visualizer shows the executed draft version without the l
);
});
-// FIXME: Documented bug. See https://github.com/twentyhq/core-team-issues/issues/921
-test.fail('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
+test('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
workflowVisualizer,
page,
}) => {
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx
index 4e00fe3aa..9e53b1ed9 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx
+++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useWorkflowCommandMenu.test.tsx
@@ -4,7 +4,8 @@ import { useRecoilValue } from 'recoil';
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
-import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
+import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState';
+import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState';
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
@@ -16,10 +17,10 @@ import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { t } from '@lingui/core/macro';
import { act } from 'react';
+import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display';
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { useWorkflowCommandMenu } from '../useWorkflowCommandMenu';
-import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display';
jest.mock('uuid', () => ({
v4: jest.fn().mockReturnValue('mocked-uuid'),
@@ -95,7 +96,11 @@ const renderHooks = () => {
'mocked-uuid',
);
const workflowId = useRecoilComponentValueV2(
- workflowIdComponentState,
+ commandMenuWorkflowIdComponentState,
+ 'mocked-uuid',
+ );
+ const workflowVersionId = useRecoilComponentValueV2(
+ commandMenuWorkflowVersionIdComponentState,
'mocked-uuid',
);
const { getIcon } = useIcons();
@@ -106,6 +111,7 @@ const renderHooks = () => {
openWorkflowEditStepInCommandMenu,
openWorkflowViewStepInCommandMenu,
workflowId,
+ workflowVersionId,
viewableRecordId,
commandMenuPage,
commandMenuNavigationMorphItemByPage,
@@ -188,14 +194,16 @@ describe('useWorkflowCommandMenu', () => {
const { result } = renderHooks();
act(() => {
- result.current.openWorkflowViewStepInCommandMenu(
- 'test-workflow-id',
- 'View Step',
- IconSettingsAutomation,
- );
+ result.current.openWorkflowViewStepInCommandMenu({
+ workflowId: 'test-workflow-id',
+ workflowVersionId: 'test-workflow-version-id',
+ icon: IconSettingsAutomation,
+ title: 'View Step',
+ });
});
expect(result.current.workflowId).toBe('test-workflow-id');
+ expect(result.current.workflowVersionId).toBe('test-workflow-version-id');
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
page: CommandMenuPages.WorkflowStepView,
diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts
index 0ecedbc0e..4e0997ddf 100644
--- a/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts
+++ b/packages/twenty-front/src/modules/command-menu/hooks/useWorkflowCommandMenu.ts
@@ -1,5 +1,7 @@
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
-import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
+import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState';
+import { commandMenuWorkflowRunIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState';
+import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useSetInitialWorkflowRunRightDrawerTab } from '@/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab';
import { WorkflowDiagramRunStatus } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
@@ -23,7 +25,9 @@ export const useWorkflowCommandMenu = () => {
const pageId = v4();
set(
- workflowIdComponentState.atomFamily({ instanceId: pageId }),
+ commandMenuWorkflowIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
workflowId,
);
@@ -44,7 +48,9 @@ export const useWorkflowCommandMenu = () => {
const pageId = v4();
set(
- workflowIdComponentState.atomFamily({ instanceId: pageId }),
+ commandMenuWorkflowIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
workflowId,
);
@@ -65,7 +71,9 @@ export const useWorkflowCommandMenu = () => {
const pageId = v4();
set(
- workflowIdComponentState.atomFamily({ instanceId: pageId }),
+ commandMenuWorkflowIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
workflowId,
);
@@ -82,13 +90,31 @@ export const useWorkflowCommandMenu = () => {
const openWorkflowViewStepInCommandMenu = useRecoilCallback(
({ set }) => {
- return (workflowId: string, title: string, icon: IconComponent) => {
+ return ({
+ workflowId,
+ workflowVersionId,
+ title,
+ icon,
+ }: {
+ workflowId: string;
+ workflowVersionId: string;
+ title: string;
+ icon: IconComponent;
+ }) => {
const pageId = v4();
set(
- workflowIdComponentState.atomFamily({ instanceId: pageId }),
+ commandMenuWorkflowIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
workflowId,
);
+ set(
+ commandMenuWorkflowVersionIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
+ workflowVersionId,
+ );
navigateCommandMenu({
page: CommandMenuPages.WorkflowStepView,
@@ -105,12 +131,14 @@ export const useWorkflowCommandMenu = () => {
({ set }) => {
return ({
workflowId,
+ workflowRunId,
title,
icon,
workflowSelectedNode,
stepExecutionStatus,
}: {
workflowId: string;
+ workflowRunId: string;
title: string;
icon: IconComponent;
workflowSelectedNode: string;
@@ -119,9 +147,17 @@ export const useWorkflowCommandMenu = () => {
const pageId = v4();
set(
- workflowIdComponentState.atomFamily({ instanceId: pageId }),
+ commandMenuWorkflowIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
workflowId,
);
+ set(
+ commandMenuWorkflowRunIdComponentState.atomFamily({
+ instanceId: pageId,
+ }),
+ workflowRunId,
+ );
navigateCommandMenu({
page: CommandMenuPages.WorkflowRunStepView,
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx
index 45ca049d0..1b9613a3b 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx
@@ -1,16 +1,27 @@
import { CommandMenuWorkflowSelectActionContent } from '@/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent';
-import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
-import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { isDefined } from 'twenty-shared/utils';
export const CommandMenuWorkflowSelectAction = () => {
- const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
+ const workflowId = useCommandMenuWorkflowIdOrThrow();
const workflow = useWorkflowWithCurrentVersion(workflowId);
if (!isDefined(workflow)) {
return null;
}
- return ;
+ return (
+
+
+
+ );
};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts
new file mode 100644
index 000000000..047435f05
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow.ts
@@ -0,0 +1,16 @@
+import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { isDefined } from 'twenty-shared/utils';
+
+export const useCommandMenuWorkflowIdOrThrow = () => {
+ const workflowId = useRecoilComponentValueV2(
+ commandMenuWorkflowIdComponentState,
+ );
+ if (!isDefined(workflowId)) {
+ throw new Error(
+ 'Expected commandMenuWorkflowIdComponentState to be defined',
+ );
+ }
+
+ return workflowId;
+};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/workflowIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts
similarity index 84%
rename from packages/twenty-front/src/modules/command-menu/pages/workflow/states/workflowIdComponentState.ts
rename to packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts
index 35bb2d051..19e2b6a6a 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/workflowIdComponentState.ts
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowIdComponentState.ts
@@ -1,7 +1,7 @@
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
-export const workflowIdComponentState = createComponentStateV2<
+export const commandMenuWorkflowIdComponentState = createComponentStateV2<
string | undefined
>({
key: 'command-menu/workflow-id',
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts
new file mode 100644
index 000000000..55a39168a
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState.ts
@@ -0,0 +1,10 @@
+import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+
+export const commandMenuWorkflowRunIdComponentState = createComponentStateV2<
+ string | undefined
+>({
+ key: 'command-menu/workflow-run-id',
+ defaultValue: undefined,
+ componentInstanceContext: CommandMenuPageComponentInstanceContext,
+});
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts
new file mode 100644
index 000000000..cf0f5c15b
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState.ts
@@ -0,0 +1,9 @@
+import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+
+export const commandMenuWorkflowVersionIdComponentState =
+ createComponentStateV2({
+ key: 'command-menu/workflow-version-id',
+ defaultValue: undefined,
+ componentInstanceContext: CommandMenuPageComponentInstanceContext,
+ });
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 217e50504..27e889273 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
@@ -1,12 +1,13 @@
-import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
+import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow';
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 { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { isDefined } from 'twenty-shared/utils';
export const CommandMenuWorkflowEditStep = () => {
- const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
+ const workflowId = useCommandMenuWorkflowIdOrThrow();
const workflow = useWorkflowWithCurrentVersion(workflowId);
if (!isDefined(workflow)) {
@@ -14,10 +15,18 @@ 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 6f34c1fc1..8bac2a3e3 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
@@ -1,132 +1,20 @@
-import { getIsInputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsInputTabDisabled';
-import { getIsOutputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsOutputTabDisabled';
-import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
-import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList';
-import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
-import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
-import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
-import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
-import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
-import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
-import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
-import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
-import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail';
-import { WorkflowRunStepNodeDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepNodeDetail';
-import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail';
-import {
- WorkflowRunTabId,
- WorkflowRunTabIdType,
-} from '@/workflow/workflow-steps/types/WorkflowRunTabId';
-import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus';
-import styled from '@emotion/styled';
-import { isNull } from '@sniptt/guards';
-import { isDefined } from 'twenty-shared/utils';
-import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui/display';
-
-const StyledContainer = styled.div`
- display: flex;
- flex-direction: column;
- height: 100%;
-`;
-
-const StyledTabList = styled(TabList)`
- background-color: ${({ theme }) => theme.background.secondary};
- padding-left: ${({ theme }) => theme.spacing(2)};
-`;
-
-type TabId = WorkflowRunTabIdType;
+import { CommandMenuWorkflowRunViewStepContent } from '@/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent';
+import { useCommandMenuWorkflowRunIdOrThrow } from '@/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
export const CommandMenuWorkflowRunViewStep = () => {
- const flow = useFlowOrThrow();
- const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
- const workflowRunId = useWorkflowRunIdOrThrow();
-
- const workflowRun = useWorkflowRun({ workflowRunId });
-
- const commandMenuPageComponentInstance = useComponentInstanceStateContext(
- CommandMenuPageComponentInstanceContext,
- );
- if (isNull(commandMenuPageComponentInstance)) {
- throw new Error(
- 'CommandMenuPageComponentInstanceContext is not defined. This component should be used within CommandMenuPageComponentInstanceContext.',
- );
- }
-
- const activeTabId = useRecoilComponentValueV2(
- activeTabIdComponentState,
- commandMenuPageComponentInstance.instanceId,
- );
-
- if (!isDefined(workflowRun)) {
- return null;
- }
-
- const stepExecutionStatus = getWorkflowRunStepExecutionStatus({
- workflowRunOutput: workflowRun.output,
- stepId: workflowSelectedNode,
- });
-
- const isInputTabDisabled = getIsInputTabDisabled({
- stepExecutionStatus,
- workflowSelectedNode,
- });
- const isOutputTabDisabled = getIsOutputTabDisabled({
- stepExecutionStatus,
- });
-
- const tabs: SingleTabProps[] = [
- {
- id: WorkflowRunTabId.OUTPUT,
- title: 'Output',
- Icon: IconLogout,
- disabled: isOutputTabDisabled,
- },
- { id: WorkflowRunTabId.NODE, title: 'Node', Icon: IconStepInto },
- {
- id: WorkflowRunTabId.INPUT,
- title: 'Input',
- Icon: IconLogin2,
- disabled: isInputTabDisabled,
- },
- ];
+ const workflowRunId = useCommandMenuWorkflowRunIdOrThrow();
return (
-
-
-
-
- {activeTabId === WorkflowRunTabId.OUTPUT ? (
-
- ) : null}
-
- {activeTabId === WorkflowRunTabId.NODE ? (
-
- ) : null}
-
- {activeTabId === WorkflowRunTabId.INPUT ? (
-
- ) : null}
-
-
+
+
);
};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx
new file mode 100644
index 000000000..32e278b14
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx
@@ -0,0 +1,132 @@
+import { getIsInputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsInputTabDisabled';
+import { getIsOutputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsOutputTabDisabled';
+import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
+import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList';
+import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
+import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
+import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
+import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
+import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
+import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
+import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail';
+import { WorkflowRunStepNodeDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepNodeDetail';
+import { WorkflowRunStepOutputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepOutputDetail';
+import {
+ WorkflowRunTabId,
+ WorkflowRunTabIdType,
+} from '@/workflow/workflow-steps/types/WorkflowRunTabId';
+import { getWorkflowRunStepExecutionStatus } from '@/workflow/workflow-steps/utils/getWorkflowRunStepExecutionStatus';
+import styled from '@emotion/styled';
+import { isNull } from '@sniptt/guards';
+import { isDefined } from 'twenty-shared/utils';
+import { IconLogin2, IconLogout, IconStepInto } from 'twenty-ui/display';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+`;
+
+const StyledTabList = styled(TabList)`
+ background-color: ${({ theme }) => theme.background.secondary};
+ padding-left: ${({ theme }) => theme.spacing(2)};
+`;
+
+type TabId = WorkflowRunTabIdType;
+
+export const CommandMenuWorkflowRunViewStepContent = () => {
+ const flow = useFlowOrThrow();
+ const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
+ const workflowRunId = useWorkflowRunIdOrThrow();
+
+ const workflowRun = useWorkflowRun({ workflowRunId });
+
+ const commandMenuPageComponentInstance = useComponentInstanceStateContext(
+ CommandMenuPageComponentInstanceContext,
+ );
+ if (isNull(commandMenuPageComponentInstance)) {
+ throw new Error(
+ 'CommandMenuPageComponentInstanceContext is not defined. This component should be used within CommandMenuPageComponentInstanceContext.',
+ );
+ }
+
+ const activeTabId = useRecoilComponentValueV2(
+ activeTabIdComponentState,
+ commandMenuPageComponentInstance.instanceId,
+ );
+
+ if (!isDefined(workflowRun)) {
+ return null;
+ }
+
+ const stepExecutionStatus = getWorkflowRunStepExecutionStatus({
+ workflowRunOutput: workflowRun.output,
+ stepId: workflowSelectedNode,
+ });
+
+ const isInputTabDisabled = getIsInputTabDisabled({
+ stepExecutionStatus,
+ workflowSelectedNode,
+ });
+ const isOutputTabDisabled = getIsOutputTabDisabled({
+ stepExecutionStatus,
+ });
+
+ const tabs: SingleTabProps[] = [
+ {
+ id: WorkflowRunTabId.OUTPUT,
+ title: 'Output',
+ Icon: IconLogout,
+ disabled: isOutputTabDisabled,
+ },
+ { id: WorkflowRunTabId.NODE, title: 'Node', Icon: IconStepInto },
+ {
+ id: WorkflowRunTabId.INPUT,
+ title: 'Input',
+ Icon: IconLogin2,
+ disabled: isInputTabDisabled,
+ },
+ ];
+
+ return (
+
+
+
+
+ {activeTabId === WorkflowRunTabId.OUTPUT ? (
+
+ ) : null}
+
+ {activeTabId === WorkflowRunTabId.NODE ? (
+
+ ) : null}
+
+ {activeTabId === WorkflowRunTabId.INPUT ? (
+
+ ) : null}
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts
new file mode 100644
index 000000000..6afcf4e71
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow.ts
@@ -0,0 +1,16 @@
+import { commandMenuWorkflowRunIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { isDefined } from 'twenty-shared/utils';
+
+export const useCommandMenuWorkflowRunIdOrThrow = () => {
+ const workflowRunId = useRecoilComponentValueV2(
+ commandMenuWorkflowRunIdComponentState,
+ );
+ if (!isDefined(workflowRunId)) {
+ throw new Error(
+ 'Expected the commandMenuWorkflowRunIdComponentState to be defined.',
+ );
+ }
+
+ return workflowRunId;
+};
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 659b17808..4e644f0e6 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,31 +1,20 @@
-import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
-import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
-import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
-import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
-import styled from '@emotion/styled';
-
-const StyledContainer = styled.div`
- display: flex;
- flex-direction: column;
- height: 100%;
-`;
+import { useCommandMenuWorkflowVersionIdOrThrow } from '@/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow';
+import { CommandMenuWorkflowViewStepContent } from '@/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
export const CommandMenuWorkflowViewStep = () => {
- const flow = useFlowOrThrow();
- const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
+ const workflowVersionId = useCommandMenuWorkflowVersionIdOrThrow();
return (
-
-
-
-
-
+
+
);
};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx
new file mode 100644
index 000000000..2742cf763
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx
@@ -0,0 +1,31 @@
+import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
+import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
+import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
+import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
+import styled from '@emotion/styled';
+
+const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+`;
+
+export const CommandMenuWorkflowViewStepContent = () => {
+ const flow = useFlowOrThrow();
+ const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts
new file mode 100644
index 000000000..230c61710
--- /dev/null
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow.ts
@@ -0,0 +1,16 @@
+import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { isDefined } from 'twenty-shared/utils';
+
+export const useCommandMenuWorkflowVersionIdOrThrow = () => {
+ const workflowVersionId = useRecoilComponentValueV2(
+ commandMenuWorkflowVersionIdComponentState,
+ );
+ if (!isDefined(workflowVersionId)) {
+ throw new Error(
+ 'Expected commandMenuWorkflowVersionIdComponentState to be defined',
+ );
+ }
+
+ return workflowVersionId;
+};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerType.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerType.tsx
index 2e4bb6bc1..4877cfeaf 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerType.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerType.tsx
@@ -1,16 +1,27 @@
-import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
+import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow';
import { CommandMenuWorkflowSelectTriggerTypeContent } from '@/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent';
-import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { isDefined } from 'twenty-shared/utils';
export const CommandMenuWorkflowSelectTriggerType = () => {
- const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
+ const workflowId = useCommandMenuWorkflowIdOrThrow();
const workflow = useWorkflowWithCurrentVersion(workflowId);
if (!isDefined(workflow)) {
return null;
}
- return ;
+ return (
+
+
+
+ );
};
diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
index 92799918d..3abd377ad 100644
--- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
+++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx
@@ -1,10 +1,11 @@
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import {
WorkflowTriggerType,
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { RightDrawerStepListContainer } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer';
import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
import { DATABASE_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/DatabaseTriggerTypes';
@@ -12,9 +13,8 @@ import { OTHER_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/Other
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition';
-import { useSetRecoilState } from 'recoil';
-import { MenuItemCommand } from 'twenty-ui/navigation';
import { useIcons } from 'twenty-ui/display';
+import { MenuItemCommand } from 'twenty-ui/navigation';
export const CommandMenuWorkflowSelectTriggerTypeContent = ({
workflow,
@@ -26,7 +26,9 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
+ const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
+ workflowSelectedNodeComponentState,
+ );
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
const handleTriggerTypeClick = ({
diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx
index 62ddeba26..5fab1d8b4 100644
--- a/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-show/components/CardComponents.tsx
@@ -7,15 +7,19 @@ import { TimelineActivities } from '@/activities/timeline-activities/components/
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
import { CardType } from '@/object-record/record-show/types/CardType';
+import { ListenRecordUpdatesEffect } from '@/subscription/components/ListenUpdatesEffect';
import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizer';
import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect';
import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer';
import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect';
import { WorkflowVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVisualizer';
import { WorkflowVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVisualizerEffect';
+import { WorkflowRunVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import styled from '@emotion/styled';
-import { ListenRecordUpdatesEffect } from '@/subscription/components/ListenUpdatesEffect';
+import { useId } from 'react';
const StyledGreyBox = styled.div<{ isInRightDrawer?: boolean }>`
background: ${({ theme, isInRightDrawer }) =>
@@ -81,32 +85,63 @@ export const CardComponents: Record = {
),
- [CardType.WorkflowCard]: ({ targetableObject }) => (
- <>
-
-
- >
- ),
+ [CardType.WorkflowCard]: ({ targetableObject }) => {
+ return (
+
+
+
+
+ );
+ },
- [CardType.WorkflowVersionCard]: ({ targetableObject }) => (
- <>
-
-
- >
- ),
+ [CardType.WorkflowVersionCard]: ({ targetableObject }) => {
+ return (
+
+
+
+
+ );
+ },
- [CardType.WorkflowRunCard]: ({ targetableObject }) => (
- <>
-
-
+ [CardType.WorkflowRunCard]: ({ targetableObject }) => {
+ const componentId = useId();
-
- >
- ),
+ return (
+
+
+
+
+
+
+
+ );
+ },
};
diff --git a/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts
index f5f99a409..537781083 100644
--- a/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts
+++ b/packages/twenty-front/src/modules/workflow/hooks/useFlowOrThrow.ts
@@ -1,9 +1,10 @@
-import { flowState } from '@/workflow/states/flowState';
-import { useRecoilValue } from 'recoil';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { flowComponentState } from '@/workflow/states/flowComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useFlowOrThrow = () => {
- const flow = useRecoilValue(flowState);
+ const flow = useRecoilComponentValueV2(flowComponentState);
+
if (!isDefined(flow)) {
throw new Error('Expected the flow to be defined');
}
diff --git a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts
index 9a233a042..e34106778 100644
--- a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts
+++ b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects.ts
@@ -3,11 +3,12 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
-import { flowState } from '@/workflow/states/flowState';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
+import { flowComponentState } from '@/workflow/states/flowComponentState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
import { WorkflowRun } from '@/workflow/types/Workflow';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { useApolloClient } from '@apollo/client';
@@ -58,17 +59,46 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
return;
}
- set(workflowRunIdState, workflowRunRecord.id);
- set(workflowIdState, workflowRunRecord.workflowId);
- set(flowState, {
- workflowVersionId: workflowRunRecord.workflowVersionId,
- trigger: workflowRunRecord.output.flow.trigger,
- steps: workflowRunRecord.output.flow.steps,
- });
- set(workflowSelectedNodeState, stepToOpenByDefault.id);
+ set(
+ workflowVisualizerWorkflowRunIdComponentState.atomFamily({
+ instanceId: getWorkflowVisualizerComponentInstanceId({
+ recordId,
+ }),
+ }),
+ workflowRunRecord.id,
+ );
+ set(
+ workflowVisualizerWorkflowIdComponentState.atomFamily({
+ instanceId: getWorkflowVisualizerComponentInstanceId({
+ recordId,
+ }),
+ }),
+ workflowRunRecord.workflowId,
+ );
+ set(
+ flowComponentState.atomFamily({
+ instanceId: getWorkflowVisualizerComponentInstanceId({
+ recordId,
+ }),
+ }),
+ {
+ workflowVersionId: workflowRunRecord.workflowVersionId,
+ trigger: workflowRunRecord.output.flow.trigger,
+ steps: workflowRunRecord.output.flow.steps,
+ },
+ );
+ set(
+ workflowSelectedNodeComponentState.atomFamily({
+ instanceId: getWorkflowVisualizerComponentInstanceId({
+ recordId,
+ }),
+ }),
+ stepToOpenByDefault.id,
+ );
openWorkflowRunViewStepInCommandMenu({
workflowId: workflowRunRecord.workflowId,
+ workflowRunId: workflowRunRecord.id,
title: stepToOpenByDefault.data.name,
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
workflowSelectedNode: stepToOpenByDefault.id,
diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts
index d76132dcc..98f383790 100644
--- a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts
+++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowRunIdOrThrow.ts
@@ -1,9 +1,12 @@
-import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
-import { useRecoilValue } from 'recoil';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useWorkflowRunIdOrThrow = () => {
- const workflowRunId = useRecoilValue(workflowRunIdState);
+ const workflowRunId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowRunIdComponentState,
+ );
+
if (!isDefined(workflowRunId)) {
throw new Error('Expected the workflow run ID to be defined');
}
diff --git a/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts b/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts
new file mode 100644
index 000000000..1b5b9ddb6
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/states/flowComponentState.ts
@@ -0,0 +1,16 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowAction, WorkflowTrigger } from '@/workflow/types/Workflow';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const flowComponentState = createComponentStateV2<
+ | {
+ workflowVersionId: string;
+ trigger: WorkflowTrigger | null;
+ steps: WorkflowAction[] | null;
+ }
+ | undefined
+>({
+ key: 'flowComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+});
diff --git a/packages/twenty-front/src/modules/workflow/states/flowState.ts b/packages/twenty-front/src/modules/workflow/states/flowState.ts
deleted file mode 100644
index 9cdd51b00..000000000
--- a/packages/twenty-front/src/modules/workflow/states/flowState.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { WorkflowAction, WorkflowTrigger } from '@/workflow/types/Workflow';
-import { createState } from 'twenty-ui/utilities';
-
-export const flowState = createState<
- | {
- workflowVersionId: string;
- trigger: WorkflowTrigger | null;
- steps: WorkflowAction[] | null;
- }
- | undefined
->({
- key: 'flowState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowIdState.ts b/packages/twenty-front/src/modules/workflow/states/workflowIdState.ts
deleted file mode 100644
index 0851b1044..000000000
--- a/packages/twenty-front/src/modules/workflow/states/workflowIdState.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-export const workflowIdState = createState({
- key: 'workflowIdState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts
new file mode 100644
index 000000000..20b09c41e
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdComponentState.ts
@@ -0,0 +1,10 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowLastCreatedStepIdComponentState = createComponentStateV2<
+ string | undefined
+>({
+ key: 'workflowLastCreatedStepIdComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+});
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdState.ts b/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdState.ts
deleted file mode 100644
index 14252388f..000000000
--- a/packages/twenty-front/src/modules/workflow/states/workflowLastCreatedStepIdState.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-export const workflowLastCreatedStepIdState = createState({
- key: 'workflowLastCreatedStepIdState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowRunIdState.ts b/packages/twenty-front/src/modules/workflow/states/workflowRunIdState.ts
deleted file mode 100644
index f1460ff00..000000000
--- a/packages/twenty-front/src/modules/workflow/states/workflowRunIdState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowRunIdState = createState({
- key: 'workflowRunIdState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts
new file mode 100644
index 000000000..cbd75d932
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowIdComponentState.ts
@@ -0,0 +1,9 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowVisualizerWorkflowIdComponentState =
+ createComponentStateV2({
+ key: 'workflowVisualizerWorkflowIdComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts
new file mode 100644
index 000000000..905c9fec5
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowRunIdComponentState.ts
@@ -0,0 +1,9 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowVisualizerWorkflowRunIdComponentState =
+ createComponentStateV2({
+ key: 'workflowVisualizerWorkflowRunIdComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts
new file mode 100644
index 000000000..e60141130
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/states/workflowVisualizerWorkflowVersionIdComponentState.ts
@@ -0,0 +1,9 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowVisualizerWorkflowVersionIdComponentState =
+ createComponentStateV2({
+ key: 'workflowVisualizerWorkflowVersionIdComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/utils/getWorkflowVisualizerComponentInstanceId.ts b/packages/twenty-front/src/modules/workflow/utils/getWorkflowVisualizerComponentInstanceId.ts
new file mode 100644
index 000000000..b8a930e0e
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/utils/getWorkflowVisualizerComponentInstanceId.ts
@@ -0,0 +1,7 @@
+export const getWorkflowVisualizerComponentInstanceId = ({
+ recordId,
+}: {
+ recordId: string;
+}) => {
+ return recordId;
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx
index 5d517e832..ba69cea7c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase.tsx
@@ -1,8 +1,9 @@
import { useListenRightDrawerClose } from '@/ui/layout/right-drawer/hooks/useListenRightDrawerClose';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/components/WorkflowDiagramCustomMarkers';
import { useRightDrawerState } from '@/workflow/workflow-diagram/hooks/useRightDrawerState';
-import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
-import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
import {
WorkflowDiagramEdge,
WorkflowDiagramEdgeType,
@@ -26,7 +27,6 @@ import {
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import React, { useEffect, useMemo, useRef } from 'react';
-import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { Tag, TagColor } from 'twenty-ui/components';
import { THEME_COMMON } from 'twenty-ui/theme';
@@ -121,7 +121,9 @@ export const WorkflowDiagramCanvasBase = ({
const reactflow = useReactFlow();
- const workflowDiagram = useRecoilValue(workflowDiagramState);
+ const workflowDiagram = useRecoilComponentValueV2(
+ workflowDiagramComponentState,
+ );
const { nodes, edges } = useMemo(
() =>
@@ -137,14 +139,8 @@ export const WorkflowDiagramCanvasBase = ({
THEME_COMMON.rightDrawerWidth.replace('px', ''),
);
- const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
-
- const setWorkflowReactFlowRef = useRecoilCallback(
- ({ set }) =>
- (node: HTMLDivElement | null) => {
- set(workflowReactFlowRefState, { current: node });
- },
- [],
+ const setWorkflowDiagram = useSetRecoilComponentStateV2(
+ workflowDiagramComponentState,
);
const handleEdgesChange = (
@@ -199,24 +195,18 @@ export const WorkflowDiagramCanvasBase = ({
);
}, [reactflow, rightDrawerState, rightDrawerWidth]);
- const handleNodesChanges = useRecoilCallback(
- ({ set }) =>
- (changes: NodeChange[]) => {
- set(workflowDiagramState, (diagram) => {
- if (!isDefined(diagram)) {
- throw new Error(
- 'It must be impossible for the nodes to be updated if the diagram is not defined yet. Be sure the diagram is rendered only when defined.',
- );
- }
+ const handleNodesChanges = (changes: NodeChange[]) => {
+ setWorkflowDiagram((diagram) => {
+ if (!isDefined(diagram)) {
+ return diagram;
+ }
- return {
- ...diagram,
- nodes: applyNodeChanges(changes, diagram.nodes),
- };
- });
- },
- [],
- );
+ return {
+ ...diagram,
+ nodes: applyNodeChanges(changes, diagram.nodes),
+ };
+ });
+ };
const handleInit = () => {
if (!isDefined(containerRef.current)) {
@@ -239,7 +229,6 @@ export const WorkflowDiagramCanvasBase = ({
{
openWorkflowEditStepInCommandMenu,
} = useWorkflowCommandMenu();
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
+ const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
+ workflowSelectedNodeComponentState,
+ );
const setCommandMenuNavigationStack = useSetRecoilState(
commandMenuNavigationStackState,
@@ -37,7 +41,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
const { isInRightDrawer } = useContext(ActionMenuContext);
- const workflowId = useRecoilValue(workflowIdState);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
const handleSelectionChange = useCallback(
({ nodes }: OnSelectionChangeParams) => {
@@ -53,8 +59,8 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID;
if (isEmptyTriggerNode) {
- if (isDefined(workflowId)) {
- openWorkflowTriggerTypeInCommandMenu(workflowId);
+ if (isDefined(workflowVisualizerWorkflowId)) {
+ openWorkflowTriggerTypeInCommandMenu(workflowVisualizerWorkflowId);
return;
}
@@ -71,9 +77,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
setWorkflowSelectedNode(selectedNode.id);
- if (isDefined(workflowId)) {
+ if (isDefined(workflowVisualizerWorkflowId)) {
openWorkflowEditStepInCommandMenu(
- workflowId,
+ workflowVisualizerWorkflowId,
selectedNodeData.name,
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
);
@@ -84,7 +90,7 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
[
isInRightDrawer,
setCommandMenuNavigationStack,
- workflowId,
+ workflowVisualizerWorkflowId,
openWorkflowTriggerTypeInCommandMenu,
startNodeCreation,
openWorkflowEditStepInCommandMenu,
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect.tsx
index 023f1a78a..9f1252cd3 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect.tsx
@@ -1,7 +1,10 @@
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import {
WorkflowDiagramNode,
WorkflowDiagramStepNodeData,
@@ -9,19 +12,34 @@ import {
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
import { useCallback } from 'react';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useIcons } from 'twenty-ui/display';
export const WorkflowDiagramCanvasReadonlyEffect = () => {
const { getIcon } = useIcons();
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
+ const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
+ workflowSelectedNodeComponentState,
+ );
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
- const workflowId = useRecoilValue(workflowIdState);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const workflowVisualizerWorkflowVersionId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowVersionIdComponentState,
+ );
const handleSelectionChange = useCallback(
({ nodes }: OnSelectionChangeParams) => {
+ if (
+ !(
+ isDefined(workflowVisualizerWorkflowId) &&
+ isDefined(workflowVisualizerWorkflowVersionId)
+ )
+ ) {
+ return;
+ }
+
const selectedNode = nodes[0] as WorkflowDiagramNode | undefined;
if (!isDefined(selectedNode)) {
@@ -32,18 +50,18 @@ export const WorkflowDiagramCanvasReadonlyEffect = () => {
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
- if (isDefined(workflowId)) {
- openWorkflowViewStepInCommandMenu(
- workflowId,
- selectedNodeData.name,
- getIcon(getWorkflowNodeIconKey(selectedNodeData)),
- );
- }
+ openWorkflowViewStepInCommandMenu({
+ workflowId: workflowVisualizerWorkflowId,
+ workflowVersionId: workflowVisualizerWorkflowVersionId,
+ title: selectedNodeData.name,
+ icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
+ });
},
[
setWorkflowSelectedNode,
openWorkflowViewStepInCommandMenu,
- workflowId,
+ workflowVisualizerWorkflowId,
+ workflowVisualizerWorkflowVersionId,
getIcon,
],
);
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 ec652bbad..16c6a2da4 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,18 +1,20 @@
+import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
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 { flowComponentState } from '@/workflow/states/flowComponentState';
+import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState';
import {
WorkflowVersion,
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
-import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
import { addCreateStepNodes } from '@/workflow/workflow-diagram/utils/addCreateStepNodes';
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
import { mergeWorkflowDiagrams } from '@/workflow/workflow-diagram/utils/mergeWorkflowDiagrams';
import { useEffect } from 'react';
-import { useRecoilCallback, useSetRecoilState } from 'recoil';
+import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const WorkflowDiagramEffect = ({
@@ -20,10 +22,19 @@ export const WorkflowDiagramEffect = ({
}: {
workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined;
}) => {
- const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
- const setFlow = useSetRecoilState(flowState);
+ const workflowDiagramState = useRecoilComponentCallbackStateV2(
+ workflowDiagramComponentState,
+ );
+ const setWorkflowDiagram = useSetRecoilComponentStateV2(
+ workflowDiagramComponentState,
+ );
+ const setFlow = useSetRecoilComponentStateV2(flowComponentState);
const { populateStepsOutputSchema } = useStepsOutputSchema();
+ const workflowLastCreatedStepIdState = useRecoilComponentCallbackStateV2(
+ workflowLastCreatedStepIdComponentState,
+ );
+
const computeAndMergeNewWorkflowDiagram = useRecoilCallback(
({ snapshot, set }) => {
return (currentVersion: WorkflowVersion) => {
@@ -64,7 +75,7 @@ export const WorkflowDiagramEffect = ({
set(workflowDiagramState, mergedWorkflowDiagram);
};
},
- [],
+ [workflowLastCreatedStepIdState, workflowDiagramState],
);
const currentVersion = workflowWithCurrentVersion?.currentVersion;
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
index d5f9bd18f..08c188a80 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
@@ -1,10 +1,10 @@
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined';
import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent';
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
-import { useRecoilValue } from 'recoil';
export const WorkflowDiagramStepNodeEditable = ({
id,
@@ -15,9 +15,13 @@ export const WorkflowDiagramStepNodeEditable = ({
data: WorkflowDiagramStepNodeData;
selected?: boolean;
}) => {
- const workflowId = useRecoilValue(workflowIdState);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
- const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
+ const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(
+ workflowVisualizerWorkflowId,
+ );
assertWorkflowWithCurrentVersionIsDefined(workflowWithCurrentVersion);
const { deleteStep } = useDeleteStep({
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunDiagramCanvasEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunDiagramCanvasEffect.tsx
index c524fa985..22042b0e3 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunDiagramCanvasEffect.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowRunDiagramCanvasEffect.tsx
@@ -1,8 +1,10 @@
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
+import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { WorkflowRunDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
@@ -15,10 +17,25 @@ export const WorkflowRunDiagramCanvasEffect = () => {
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
+ const workflowRunId = useWorkflowRunIdOrThrow();
+
+ const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackStateV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const workflowDiagramStatusState = useRecoilComponentCallbackStateV2(
+ workflowDiagramStatusComponentState,
+ );
+ const workflowSelectedNodeState = useRecoilComponentCallbackStateV2(
+ workflowSelectedNodeComponentState,
+ );
+
const handleSelectionChange = useRecoilCallback(
({ snapshot, set }) =>
({ nodes }: OnSelectionChangeParams) => {
- const workflowId = getSnapshotValue(snapshot, workflowIdState);
+ const workflowId = getSnapshotValue(
+ snapshot,
+ workflowVisualizerWorkflowIdState,
+ );
if (!isDefined(workflowId)) {
throw new Error('Expected the workflowId to be defined.');
@@ -49,13 +66,21 @@ export const WorkflowRunDiagramCanvasEffect = () => {
openWorkflowRunViewStepInCommandMenu({
workflowId,
+ workflowRunId,
title: selectedNodeData.name,
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
workflowSelectedNode: selectedNode.id,
stepExecutionStatus: selectedNodeData.runStatus,
});
},
- [getIcon, openWorkflowRunViewStepInCommandMenu],
+ [
+ workflowVisualizerWorkflowIdState,
+ workflowDiagramStatusState,
+ workflowSelectedNodeState,
+ openWorkflowRunViewStepInCommandMenu,
+ workflowRunId,
+ getIcon,
+ ],
);
useOnSelectionChange({
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 a46d913c7..c5a66d597 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,8 +1,8 @@
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
import { WorkflowRunDiagramCanvas } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvas';
-import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
+import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
import styled from '@emotion/styled';
-import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
const StyledContainer = styled.div`
@@ -15,7 +15,9 @@ export const WorkflowRunVisualizer = ({
workflowRunId: string;
}) => {
const workflowRun = useWorkflowRun({ workflowRunId });
- const workflowDiagramStatus = useRecoilValue(workflowDiagramStatusState);
+ const workflowDiagramStatus = useRecoilComponentValueV2(
+ workflowDiagramStatusComponentState,
+ );
if (
!isDefined(workflowRun) ||
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 c49777bc9..a404d8bae 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,18 +1,21 @@
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
+import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
+import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
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 { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
+import { flowComponentState } from '@/workflow/states/flowComponentState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
import { WorkflowRunOutput } from '@/workflow/types/Workflow';
-import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
-import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
-import { workflowRunStepToOpenByDefaultState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
+import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
+import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode';
import { useContext, useEffect } from 'react';
-import { useRecoilCallback, useSetRecoilState } from 'recoil';
+import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const WorkflowRunVisualizerEffect = ({
@@ -23,8 +26,24 @@ export const WorkflowRunVisualizerEffect = ({
const workflowRun = useWorkflowRun({ workflowRunId });
const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId);
- const setWorkflowRunId = useSetRecoilState(workflowRunIdState);
- const setWorkflowId = useSetRecoilState(workflowIdState);
+ const setWorkflowRunId = useSetRecoilComponentStateV2(
+ workflowVisualizerWorkflowRunIdComponentState,
+ );
+ const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+
+ const flowState = useRecoilComponentCallbackStateV2(flowComponentState);
+ const workflowDiagramState = useRecoilComponentCallbackStateV2(
+ workflowDiagramComponentState,
+ );
+ const workflowDiagramStatusState = useRecoilComponentCallbackStateV2(
+ workflowDiagramStatusComponentState,
+ );
+ const workflowRunStepToOpenByDefaultState = useRecoilComponentCallbackStateV2(
+ workflowRunStepToOpenByDefaultComponentState,
+ );
+
const { populateStepsOutputSchema } = useStepsOutputSchema();
const { isInRightDrawer } = useContext(ActionMenuContext);
@@ -38,11 +57,11 @@ export const WorkflowRunVisualizerEffect = ({
return;
}
- setWorkflowId(workflowRun.workflowId);
- }, [setWorkflowId, workflowRun]);
+ setWorkflowVisualizerWorkflowId(workflowRun.workflowId);
+ }, [setWorkflowVisualizerWorkflowId, workflowRun]);
const handleWorkflowRunDiagramGeneration = useRecoilCallback(
- ({ set }) =>
+ ({ snapshot, set }) =>
({
workflowRunOutput,
workflowVersionId,
@@ -59,7 +78,14 @@ export const WorkflowRunVisualizerEffect = ({
return;
}
- set(workflowDiagramStatusState, 'computing-diagram');
+ const workflowDiagramStatus = getSnapshotValue(
+ snapshot,
+ workflowDiagramStatusState,
+ );
+
+ if (workflowDiagramStatus !== 'done') {
+ set(workflowDiagramStatusState, 'computing-diagram');
+ }
set(flowState, {
workflowVersionId,
@@ -89,9 +115,16 @@ export const WorkflowRunVisualizerEffect = ({
set(workflowDiagramState, baseWorkflowRunDiagram);
}
- set(workflowDiagramStatusState, 'computing-dimensions');
+ if (workflowDiagramStatus !== 'done') {
+ set(workflowDiagramStatusState, 'computing-dimensions');
+ }
},
- [],
+ [
+ flowState,
+ workflowDiagramState,
+ workflowDiagramStatusState,
+ workflowRunStepToOpenByDefaultState,
+ ],
);
useEffect(() => {
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 7f73f34f1..084fc5037 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,11 +1,12 @@
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
-import { flowState } from '@/workflow/states/flowState';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
+import { flowComponentState } from '@/workflow/states/flowComponentState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
+import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
import { useEffect } from 'react';
-import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const WorkflowVersionVisualizerEffect = ({
@@ -15,10 +16,19 @@ export const WorkflowVersionVisualizerEffect = ({
}) => {
const workflowVersion = useWorkflowVersion(workflowVersionId);
- const setFlow = useSetRecoilState(flowState);
- const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
- const setWorkflowId = useSetRecoilState(workflowIdState);
+ const setFlow = useSetRecoilComponentStateV2(flowComponentState);
+ const setWorkflowDiagram = useSetRecoilComponentStateV2(
+ workflowDiagramComponentState,
+ );
+ const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentStateV2(
+ workflowVisualizerWorkflowVersionIdComponentState,
+ );
+
const { populateStepsOutputSchema } = useStepsOutputSchema();
+
useEffect(() => {
if (!isDefined(workflowVersion)) {
setFlow(undefined);
@@ -32,8 +42,14 @@ export const WorkflowVersionVisualizerEffect = ({
steps: workflowVersion.steps,
});
- setWorkflowId(workflowVersion.workflowId);
- }, [setFlow, setWorkflowId, workflowVersion]);
+ setWorkflowVisualizerWorkflowId(workflowVersion.workflowId);
+ setWorkflowVisualizerWorkflowVersionId(workflowVersion.id);
+ }, [
+ setFlow,
+ setWorkflowVisualizerWorkflowId,
+ setWorkflowVisualizerWorkflowVersionId,
+ workflowVersion,
+ ]);
useEffect(() => {
if (!isDefined(workflowVersion)) {
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx
index f3f7ed097..3d5fa311f 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx
@@ -1,17 +1,19 @@
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { useEffect } from 'react';
-import { useSetRecoilState } from 'recoil';
export const WorkflowVisualizerEffect = ({
workflowId,
}: {
workflowId: string;
}) => {
- const setWorkflowId = useSetRecoilState(workflowIdState);
+ const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
useEffect(() => {
- setWorkflowId(workflowId);
- }, [setWorkflowId, workflowId]);
+ setWorkflowVisualizerWorkflowId(workflowId);
+ }, [setWorkflowVisualizerWorkflowId, workflowId]);
return null;
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCustomMarkers.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCustomMarkers.stories.tsx
index 8bb3f74b9..8a5eec03c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCustomMarkers.stories.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCustomMarkers.stories.tsx
@@ -9,11 +9,12 @@ import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/com
import { WorkflowDiagramSuccessEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramSuccessEdge';
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeDefaultConfiguration';
import { WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeSuccessConfiguration';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
-import { workflowDiagramState } from '../../states/workflowDiagramState';
+import { workflowDiagramComponentState } from '../../states/workflowDiagramComponentState';
import { WorkflowDiagramCanvasBase } from '../WorkflowDiagramCanvasBase';
const StyledContainer = styled.div`
@@ -51,63 +52,79 @@ export const DefaultEdge: Story = {
},
},
decorators: [
- (Story) => (
- {
- set(workflowDiagramState, {
- nodes: [
+ (Story) => {
+ const workflowVisualizerComponentInstanceId =
+ 'workflow-visualizer-test-id';
+
+ return (
+ {
+ set(
+ workflowDiagramComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
{
- id: 'trigger-1',
- type: 'default',
- position: { x: 100, y: 100 },
- data: {
- nodeType: 'trigger',
- triggerType: 'DATABASE_EVENT',
- name: 'When record is created',
- },
+ nodes: [
+ {
+ id: 'trigger-1',
+ type: 'default',
+ position: { x: 100, y: 100 },
+ data: {
+ nodeType: 'trigger',
+ triggerType: 'DATABASE_EVENT',
+ name: 'When record is created',
+ },
+ },
+ {
+ id: 'action-1',
+ type: 'default',
+ position: { x: 300, y: 100 },
+ data: {
+ nodeType: 'action',
+ actionType: 'CREATE_RECORD',
+ name: 'Create record',
+ },
+ },
+ {
+ id: 'create-step-1',
+ type: 'create-step',
+ position: { x: 500, y: 100 },
+ data: {
+ nodeType: 'create-step',
+ parentNodeId: 'action-1',
+ },
+ },
+ ],
+ edges: [
+ {
+ ...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
+ id: 'edge-1',
+ source: 'trigger-1',
+ target: 'action-1',
+ },
+ {
+ ...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
+ id: 'edge-2',
+ source: 'action-1',
+ target: 'create-step-1',
+ },
+ ],
},
- {
- id: 'action-1',
- type: 'default',
- position: { x: 300, y: 100 },
- data: {
- nodeType: 'action',
- actionType: 'CREATE_RECORD',
- name: 'Create record',
- },
- },
- {
- id: 'create-step-1',
- type: 'create-step',
- position: { x: 500, y: 100 },
- data: {
- nodeType: 'create-step',
- parentNodeId: 'action-1',
- },
- },
- ],
- edges: [
- {
- ...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
- id: 'edge-1',
- source: 'trigger-1',
- target: 'action-1',
- },
- {
- ...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
- id: 'edge-2',
- source: 'action-1',
- target: 'create-step-1',
- },
- ],
- });
- }}
- >
-
-
-
-
- ),
+ );
+ }}
+ >
+
+
+
+
+
+
+ );
+ },
],
};
@@ -124,49 +141,65 @@ export const SuccessEdge: Story = {
},
},
decorators: [
- (Story) => (
- {
- set(workflowDiagramState, {
- nodes: [
+ (Story) => {
+ const workflowVisualizerComponentInstanceId =
+ 'workflow-visualizer-test-id';
+
+ return (
+ {
+ set(
+ workflowDiagramComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
{
- id: 'trigger-1',
- type: 'default',
- position: { x: 100, y: 100 },
- data: {
- nodeType: 'trigger',
- triggerType: 'DATABASE_EVENT',
- name: 'When record is created',
- },
+ nodes: [
+ {
+ id: 'trigger-1',
+ type: 'default',
+ position: { x: 100, y: 100 },
+ data: {
+ nodeType: 'trigger',
+ triggerType: 'DATABASE_EVENT',
+ name: 'When record is created',
+ },
+ },
+ {
+ id: 'action-1',
+ type: 'default',
+ position: { x: 300, y: 100 },
+ data: {
+ nodeType: 'action',
+ actionType: 'CREATE_RECORD',
+ name: 'Create record',
+ },
+ },
+ ],
+ edges: [
+ {
+ ...WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION,
+ id: 'edge-1',
+ source: 'trigger-1',
+ target: 'action-1',
+ type: 'success',
+ label: '1 item',
+ },
+ ],
},
- {
- id: 'action-1',
- type: 'default',
- position: { x: 300, y: 100 },
- data: {
- nodeType: 'action',
- actionType: 'CREATE_RECORD',
- name: 'Create record',
- },
- },
- ],
- edges: [
- {
- ...WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION,
- id: 'edge-1',
- source: 'trigger-1',
- target: 'action-1',
- type: 'success',
- label: '1 item',
- },
- ],
- });
- }}
- >
-
-
-
-
- ),
+ );
+ }}
+ >
+
+
+
+
+
+
+ );
+ },
],
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/__tests__/useTriggerNodeSelection.test.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/__tests__/useTriggerNodeSelection.test.tsx
index d28c33ba5..bade0f15d 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/__tests__/useTriggerNodeSelection.test.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/__tests__/useTriggerNodeSelection.test.tsx
@@ -1,15 +1,25 @@
+import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
-import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
import { act, renderHook } from '@testing-library/react';
import { useReactFlow } from '@xyflow/react';
-import { RecoilRoot, useRecoilState } from 'recoil';
+import { RecoilRoot } from 'recoil';
jest.mock('@xyflow/react', () => ({
useReactFlow: jest.fn(),
}));
const wrapper = ({ children }: { children: React.ReactNode }) => (
- {children}
+
+
+ {children}
+
+
);
describe('useTriggerNodeSelection', () => {
@@ -31,7 +41,9 @@ describe('useTriggerNodeSelection', () => {
const [
workflowDiagramTriggerNodeSelection,
setWorkflowDiagramTriggerNodeSelection,
- ] = useRecoilState(workflowDiagramTriggerNodeSelectionState);
+ ] = useRecoilComponentStateV2(
+ workflowDiagramTriggerNodeSelectionComponentState,
+ );
useTriggerNodeSelection();
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useHandleWorkflowRunDiagramCanvasInit.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useHandleWorkflowRunDiagramCanvasInit.ts
index ab8849c84..4b52dd43c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useHandleWorkflowRunDiagramCanvasInit.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useHandleWorkflowRunDiagramCanvasInit.ts
@@ -1,10 +1,12 @@
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
-import { workflowRunStepToOpenByDefaultState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
+import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
+import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { useContext } from 'react';
import { useRecoilCallback } from 'recoil';
@@ -17,6 +19,21 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
const { isInRightDrawer } = useContext(ActionMenuContext);
+ const workflowRunId = useWorkflowRunIdOrThrow();
+
+ const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackStateV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const workflowDiagramStatusState = useRecoilComponentCallbackStateV2(
+ workflowDiagramStatusComponentState,
+ );
+ const workflowRunStepToOpenByDefaultState = useRecoilComponentCallbackStateV2(
+ workflowRunStepToOpenByDefaultComponentState,
+ );
+ const workflowSelectedNodeState = useRecoilComponentCallbackStateV2(
+ workflowSelectedNodeComponentState,
+ );
+
const handleWorkflowRunDiagramCanvasInit = useRecoilCallback(
({ snapshot, set }) =>
() => {
@@ -43,8 +60,11 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
);
if (isDefined(workflowStepToOpenByDefault)) {
- const workflowId = getSnapshotValue(snapshot, workflowIdState);
- if (!isDefined(workflowId)) {
+ const workflowVisualizerWorkflowId = getSnapshotValue(
+ snapshot,
+ workflowVisualizerWorkflowIdState,
+ );
+ if (!isDefined(workflowVisualizerWorkflowId)) {
throw new Error(
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
);
@@ -53,7 +73,8 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
set(workflowSelectedNodeState, workflowStepToOpenByDefault.id);
openWorkflowRunViewStepInCommandMenu({
- workflowId,
+ workflowId: workflowVisualizerWorkflowId,
+ workflowRunId,
title: workflowStepToOpenByDefault.data.name,
icon: getIcon(
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
@@ -65,7 +86,16 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
set(workflowRunStepToOpenByDefaultState, undefined);
}
},
- [getIcon, isInRightDrawer, openWorkflowRunViewStepInCommandMenu],
+ [
+ workflowDiagramStatusState,
+ isInRightDrawer,
+ workflowRunStepToOpenByDefaultState,
+ workflowVisualizerWorkflowIdState,
+ workflowSelectedNodeState,
+ openWorkflowRunViewStepInCommandMenu,
+ workflowRunId,
+ getIcon,
+ ],
);
return {
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts
index 218205f5b..1487c835a 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts
@@ -1,18 +1,21 @@
import { useCallback } from 'react';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
+import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useStartNodeCreation = () => {
- const setWorkflowCreateStepFromParentStepId = useSetRecoilState(
- workflowCreateStepFromParentStepIdState,
+ const setWorkflowCreateStepFromParentStepId = useSetRecoilComponentStateV2(
+ workflowCreateStepFromParentStepIdComponentState,
);
const { openStepSelectInCommandMenu } = useWorkflowCommandMenu();
- const workflowId = useRecoilValue(workflowIdState);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
/**
* This function is used in a context where dependencies shouldn't change much.
@@ -22,14 +25,14 @@ export const useStartNodeCreation = () => {
(parentNodeId: string) => {
setWorkflowCreateStepFromParentStepId(parentNodeId);
- if (isDefined(workflowId)) {
- openStepSelectInCommandMenu(workflowId);
+ if (isDefined(workflowVisualizerWorkflowId)) {
+ openStepSelectInCommandMenu(workflowVisualizerWorkflowId);
return;
}
},
[
setWorkflowCreateStepFromParentStepId,
- workflowId,
+ workflowVisualizerWorkflowId,
openStepSelectInCommandMenu,
],
);
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useTriggerNodeSelection.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useTriggerNodeSelection.ts
index fe8a87c3f..bddbaaf12 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useTriggerNodeSelection.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useTriggerNodeSelection.ts
@@ -1,11 +1,11 @@
-import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState';
+import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
+import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
import {
WorkflowDiagramEdge,
WorkflowDiagramNode,
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { useReactFlow } from '@xyflow/react';
import { useEffect } from 'react';
-import { useRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const useTriggerNodeSelection = () => {
@@ -14,7 +14,9 @@ export const useTriggerNodeSelection = () => {
const [
workflowDiagramTriggerNodeSelection,
setWorkflowDiagramTriggerNodeSelection,
- ] = useRecoilState(workflowDiagramTriggerNodeSelectionState);
+ ] = useRecoilComponentStateV2(
+ workflowDiagramTriggerNodeSelectionComponentState,
+ );
useEffect(() => {
if (!isDefined(workflowDiagramTriggerNodeSelection)) {
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow.ts
index 10a62c6c1..b36fb2985 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow.ts
@@ -1,9 +1,11 @@
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
-import { useRecoilValue } from 'recoil';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useWorkflowSelectedNodeOrThrow = () => {
- const workflowSelectedNode = useRecoilValue(workflowSelectedNodeState);
+ const workflowSelectedNode = useRecoilComponentValueV2(
+ workflowSelectedNodeComponentState,
+ );
if (!isDefined(workflowSelectedNode)) {
throw new Error(
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext.tsx
new file mode 100644
index 000000000..e9787f3ab
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext.tsx
@@ -0,0 +1,6 @@
+import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
+
+export const WorkflowRunVisualizerComponentInstanceContext =
+ createComponentInstanceContext({
+ instanceId: '',
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext.tsx
new file mode 100644
index 000000000..64493b8e2
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext.tsx
@@ -0,0 +1,6 @@
+import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
+
+export const WorkflowVisualizerComponentInstanceContext =
+ createComponentInstanceContext({
+ instanceId: '',
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts
new file mode 100644
index 000000000..f861397f4
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramComponentState.ts
@@ -0,0 +1,11 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+import { WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
+
+export const workflowDiagramComponentState = createComponentStateV2<
+ WorkflowDiagram | undefined
+>({
+ key: 'workflowDiagramComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramState.ts
deleted file mode 100644
index fc535453b..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramState.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowDiagramState = createState({
- key: 'workflowDiagramState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts
new file mode 100644
index 000000000..f63685f25
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusComponentState.ts
@@ -0,0 +1,12 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowRunVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext';
+import { WorkflowDiagramStatus } from '@/workflow/workflow-diagram/types/WorkflowDiagramStatus';
+
+// This state must be fresh every time the Reactflow component is mounted.
+// We use another instance context whose instanceId is an id unique to the component hierarchy.
+export const workflowDiagramStatusComponentState =
+ createComponentStateV2({
+ key: 'workflowDiagramStatusComponentState',
+ defaultValue: 'computing-diagram',
+ componentInstanceContext: WorkflowRunVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusState.ts
deleted file mode 100644
index 6a43fac9f..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramStatusState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowDiagramStatusState = createState<
- 'computing-diagram' | 'computing-dimensions' | 'done'
->({
- key: 'workflowDiagramStatusState',
- defaultValue: 'computing-diagram',
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState.ts
new file mode 100644
index 000000000..341dba6d7
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState.ts
@@ -0,0 +1,9 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowDiagramTriggerNodeSelectionComponentState =
+ createComponentStateV2({
+ key: 'workflowDiagramTriggerNodeSelectionComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState.ts
deleted file mode 100644
index a1df2bab9..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-export const workflowDiagramTriggerNodeSelectionState = createState<
- string | undefined
->({
- key: 'workflowDiagramTriggerNodeSelectionState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowReactFlowRefState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowReactFlowRefState.ts
deleted file mode 100644
index 3f16972b7..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowReactFlowRefState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { RefObject } from 'react';
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowReactFlowRefState =
- createState | null>({
- key: 'workflowReactFlowRefState',
- defaultValue: null,
- });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState.ts
new file mode 100644
index 000000000..f0830b445
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState.ts
@@ -0,0 +1,16 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+import { WorkflowRunDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
+
+export const workflowRunStepToOpenByDefaultComponentState =
+ createComponentStateV2<
+ | {
+ id: string;
+ data: WorkflowRunDiagramStepNodeData;
+ }
+ | undefined
+ >({
+ key: 'workflowRunStepToOpenByDefaultComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState.ts
deleted file mode 100644
index d17465faf..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { WorkflowRunDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowRunStepToOpenByDefaultState = createState<
- | {
- id: string;
- data: WorkflowRunDiagramStepNodeData;
- }
- | undefined
->({
- key: 'workflowStepIdToOpenByDefaultState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts
new file mode 100644
index 000000000..0ffad0a3b
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeComponentState.ts
@@ -0,0 +1,10 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowSelectedNodeComponentState = createComponentStateV2<
+ string | undefined
+>({
+ key: 'workflowSelectedNodeComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeState.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeState.ts
deleted file mode 100644
index 6046be903..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/states/workflowSelectedNodeState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-
-export const workflowSelectedNodeState = createState({
- key: 'workflowSelectedNodeState',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramStatus.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramStatus.ts
new file mode 100644
index 000000000..5b5d7aede
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/types/WorkflowDiagramStatus.ts
@@ -0,0 +1,4 @@
+export type WorkflowDiagramStatus =
+ | 'computing-diagram'
+ | 'computing-dimensions'
+ | 'done';
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts
deleted file mode 100644
index 3d9694c2c..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
-import { renderHook } from '@testing-library/react';
-import { useCreateStep } from '../useCreateStep';
-
-const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
-const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
- data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
-});
-
-jest.mock('recoil', () => ({
- useRecoilValue: () => 'parent-step-id',
- useSetRecoilState: () => jest.fn(),
- atom: (params: any) => params,
-}));
-
-jest.mock(
- '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep',
- () => ({
- useCreateWorkflowVersionStep: () => ({
- createWorkflowVersionStep: mockCreateWorkflowVersionStep,
- }),
- }),
-);
-
-jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({
- useCreateDraftFromWorkflowVersion: () => ({
- createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion,
- }),
-}));
-
-describe('useCreateStep', () => {
- const mockWorkflow = {
- id: '123',
- currentVersion: {
- id: '456',
- status: 'DRAFT',
- steps: [],
- trigger: { type: 'manual' },
- },
- versions: [],
- };
-
- it('should create step in draft version', async () => {
- const { result } = renderHook(() =>
- useCreateStep({
- workflow: mockWorkflow as unknown as WorkflowWithCurrentVersion,
- }),
- );
- await result.current.createStep('CODE');
-
- expect(mockCreateWorkflowVersionStep).toHaveBeenCalled();
- });
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx
new file mode 100644
index 000000000..c00e8c934
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.tsx
@@ -0,0 +1,80 @@
+import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
+import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
+import { renderHook } from '@testing-library/react';
+import { RecoilRoot } from 'recoil';
+import { WorkflowVisualizerComponentInstanceContext } from '../../../workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+import { useCreateStep } from '../useCreateStep';
+
+const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
+const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
+ data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
+});
+
+jest.mock(
+ '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep',
+ () => ({
+ useCreateWorkflowVersionStep: () => ({
+ createWorkflowVersionStep: mockCreateWorkflowVersionStep,
+ }),
+ }),
+);
+
+jest.mock('@/workflow/hooks/useCreateDraftFromWorkflowVersion', () => ({
+ useCreateDraftFromWorkflowVersion: () => ({
+ createDraftFromWorkflowVersion: mockCreateDraftFromWorkflowVersion,
+ }),
+}));
+
+const wrapper = ({ children }: { children: React.ReactNode }) => {
+ const workflowVisualizerComponentInstanceId =
+ 'workflow-visualizer-instance-id';
+
+ return (
+ {
+ set(
+ workflowCreateStepFromParentStepIdComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
+ 'parent-step-id',
+ );
+ }}
+ >
+
+ {children}
+
+
+ );
+};
+
+describe('useCreateStep', () => {
+ const mockWorkflow = {
+ id: '123',
+ currentVersion: {
+ id: '456',
+ status: 'DRAFT',
+ steps: [],
+ trigger: { type: 'manual' },
+ },
+ versions: [],
+ };
+
+ it('should create step in draft version', async () => {
+ const { result } = renderHook(
+ () =>
+ useCreateStep({
+ workflow: mockWorkflow as unknown as WorkflowWithCurrentVersion,
+ }),
+ {
+ wrapper,
+ },
+ );
+ await result.current.createStep('CODE');
+
+ expect(mockCreateWorkflowVersionStep).toHaveBeenCalled();
+ });
+});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts
index 674ca3a0f..d41459a1e 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts
@@ -1,13 +1,14 @@
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
-import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
+import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState';
import {
WorkflowStepType,
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
-import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
+import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
import { isDefined } from 'twenty-shared/utils';
export const useCreateStep = ({
@@ -16,13 +17,15 @@ export const useCreateStep = ({
workflow: WorkflowWithCurrentVersion;
}) => {
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
- const setWorkflowLastCreatedStepId = useSetRecoilState(
- workflowLastCreatedStepIdState,
+ const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
+ workflowSelectedNodeComponentState,
+ );
+ const setWorkflowLastCreatedStepId = useSetRecoilComponentStateV2(
+ workflowLastCreatedStepIdComponentState,
);
- const workflowCreateStepFromParentStepId = useRecoilValue(
- workflowCreateStepFromParentStepIdState,
+ const workflowCreateStepFromParentStepId = useRecoilComponentValueV2(
+ workflowCreateStepFromParentStepIdComponentState,
);
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState.ts
new file mode 100644
index 000000000..98153b858
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState.ts
@@ -0,0 +1,9 @@
+import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+
+export const workflowCreateStepFromParentStepIdComponentState =
+ createComponentStateV2({
+ key: 'workflowCreateStepFromParentStepIdComponentState',
+ defaultValue: undefined,
+ componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
+ });
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState.ts
deleted file mode 100644
index e8f52d0a6..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createState } from 'twenty-ui/utilities';
-export const workflowCreateStepFromParentStepIdState = createState<
- string | undefined
->({
- key: 'workflowCreateStepFromParentStepId',
- defaultValue: undefined,
-});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx
index 8de526e9a..2b43b89cd 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction.tsx
@@ -3,7 +3,7 @@ import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-func
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { WorkflowCodeAction } from '@/workflow/types/Workflow';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/setNestedValue';
@@ -36,11 +36,11 @@ import { Monaco } from '@monaco-editor/react';
import { editor } from 'monaco-editor';
import { AutoTypings } from 'monaco-editor-auto-typings';
import { useEffect, useState } from 'react';
-import { useRecoilState, useRecoilValue } from 'recoil';
-import { useDebouncedCallback } from 'use-debounce';
+import { useRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
-import { CodeEditor } from 'twenty-ui/input';
import { IconCode, IconPlayerPlay, useIcons } from 'twenty-ui/display';
+import { CodeEditor } from 'twenty-ui/input';
+import { useDebouncedCallback } from 'use-debounce';
const StyledCodeEditorContainer = styled.div`
display: flex;
@@ -82,8 +82,10 @@ export const WorkflowEditActionServerlessFunction = ({
useUpdateOneServerlessFunction(serverlessFunctionId);
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
- const workflowId = useRecoilValue(workflowIdState);
- const workflow = useWorkflowWithCurrentVersion(workflowId);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
const { availablePackages } = useGetAvailablePackages({
id: serverlessFunctionId,
});
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx
index 0869263f8..bfb6efd0e 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx
@@ -8,7 +8,8 @@ import { FormTextFieldInput } from '@/object-record/record-field/form-types/comp
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
import { SettingsPath } from '@/types/SettingsPath';
import { Select } from '@/ui/input/components/Select';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { WorkflowSendEmailAction } from '@/workflow/types/Workflow';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
@@ -20,11 +21,11 @@ import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
+import { IconPlus, useIcons } from 'twenty-ui/display';
+import { SelectOption } from 'twenty-ui/input';
import { JsonValue } from 'type-fest';
import { useDebouncedCallback } from 'use-debounce';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
-import { IconPlus, useIcons } from 'twenty-ui/display';
-import { SelectOption } from 'twenty-ui/input';
type WorkflowEditActionSendEmailProps = {
action: WorkflowSendEmailAction;
@@ -53,8 +54,10 @@ export const WorkflowEditActionSendEmail = ({
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { triggerApisOAuth } = useTriggerApisOAuth();
- const workflowId = useRecoilValue(workflowIdState);
- const redirectUrl = `/object/workflow/${workflowId}`;
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
+ const redirectUrl = `/object/workflow/${workflowVisualizerWorkflowId}`;
const [formData, setFormData] = useState({
connectedAccountId: action.settings.input.connectedAccountId,
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerType.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerType.tsx
deleted file mode 100644
index c41a8f3fd..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerType.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
-import { RightDrawerWorkflowSelectTriggerTypeContent } from '@/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerTypeContent';
-import { useRecoilValue } from 'recoil';
-import { isDefined } from 'twenty-shared/utils';
-
-export const RightDrawerWorkflowSelectTriggerType = () => {
- const workflowId = useRecoilValue(workflowIdState);
- const workflow = useWorkflowWithCurrentVersion(workflowId);
-
- if (!isDefined(workflow)) {
- return null;
- }
-
- return ;
-};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx
deleted file mode 100644
index 20ea25d13..000000000
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
-import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
-import {
- WorkflowTriggerType,
- WorkflowWithCurrentVersion,
-} from '@/workflow/types/Workflow';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
-import { RightDrawerStepListContainer } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer';
-import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
-import { DATABASE_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/DatabaseTriggerTypes';
-import { OTHER_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/OtherTriggerTypes';
-import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
-import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
-import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition';
-import { useSetRecoilState } from 'recoil';
-import { MenuItemCommand } from 'twenty-ui/navigation';
-import { useIcons } from 'twenty-ui/display';
-
-export const RightDrawerWorkflowSelectTriggerTypeContent = ({
- workflow,
-}: {
- workflow: WorkflowWithCurrentVersion;
-}) => {
- const { getIcon } = useIcons();
- const { updateTrigger } = useUpdateWorkflowVersionTrigger({ workflow });
-
- const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
-
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
- const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
-
- const handleTriggerTypeClick = ({
- type,
- defaultLabel,
- icon,
- }: {
- type: WorkflowTriggerType;
- defaultLabel: string;
- icon: string;
- }) => {
- return async () => {
- await updateTrigger(
- getTriggerDefaultDefinition({
- defaultLabel,
- type,
- activeObjectMetadataItems,
- }),
- );
-
- setWorkflowSelectedNode(TRIGGER_STEP_ID);
-
- openWorkflowEditStepInCommandMenu(
- workflow.id,
- defaultLabel,
- getIcon(icon),
- );
- };
- };
-
- return (
-
-
- Data
-
- {DATABASE_TRIGGER_TYPES.map((action) => (
-
- ))}
-
- Others
-
- {OTHER_TRIGGER_TYPES.map((action) => (
-
- ))}
-
- );
-};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
index 0b39d9d53..159be6634 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm.tsx
@@ -5,7 +5,8 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Select } from '@/ui/input/components/Select';
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { WorkflowWebhookTrigger } from '@/workflow/types/Workflow';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
@@ -54,7 +55,9 @@ export const WorkflowEditTriggerWebhookForm = ({
const [errorMessages, setErrorMessages] = useState({});
const [errorMessagesVisible, setErrorMessagesVisible] = useState(false);
const { getIcon } = useIcons();
- const workflowId = useRecoilValue(workflowIdState);
+ const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
+ workflowVisualizerWorkflowIdComponentState,
+ );
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const onBlur = () => {
@@ -66,7 +69,7 @@ export const WorkflowEditTriggerWebhookForm = ({
const headerIcon = getTriggerIcon(trigger);
const headerType = getTriggerHeaderType(trigger);
- const webhookUrl = `${REACT_APP_SERVER_BASE_URL}/webhooks/workflows/${currentWorkspace?.id}/${workflowId}`;
+ const webhookUrl = `${REACT_APP_SERVER_BASE_URL}/webhooks/workflows/${currentWorkspace?.id}/${workflowVisualizerWorkflowId}`;
const displayWebhookUrl = webhookUrl.replace(/^(https?:\/\/)?(www\.)?/, '');
const copyToClipboard = async () => {
diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
index 5fa9e0a3f..d25d2a057 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-variables/components/WorkflowVariablesDropdownFieldItems.tsx
@@ -13,13 +13,12 @@ import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isReco
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
-import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
import { useState } from 'react';
-import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import {
IconChevronLeft,
@@ -42,13 +41,15 @@ export const WorkflowVariablesDropdownFieldItems = ({
const [currentPath, setCurrentPath] = useState([]);
const [searchInputValue, setSearchInputValue] = useState('');
const { getIcon } = useIcons();
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
+ const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
+ workflowSelectedNodeComponentState,
+ );
const setActiveTabId = useSetRecoilComponentStateV2(
activeTabIdComponentState,
'workflow-serverless-function-tab-list-component-id',
);
- const setWorkflowDiagramTriggerNodeSelection = useSetRecoilState(
- workflowDiagramTriggerNodeSelectionState,
+ const setWorkflowDiagramTriggerNodeSelection = useSetRecoilComponentStateV2(
+ workflowDiagramTriggerNodeSelectionComponentState,
);
const getDisplayedSubStepFields = () => {
diff --git a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx
index 943e8bfd4..71c639bcd 100644
--- a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx
@@ -1,52 +1,75 @@
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
-import { flowState } from '@/workflow/states/flowState';
-import { workflowIdState } from '@/workflow/states/workflowIdState';
+import { flowComponentState } from '@/workflow/states/flowComponentState';
+import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
import { WorkflowVersion } from '@/workflow/types/Workflow';
-import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
+import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
+import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
import { Decorator } from '@storybook/react';
import { useEffect, useState } from 'react';
-import { useSetRecoilState } from 'recoil';
+import { useRecoilCallback } from 'recoil';
import {
getWorkflowMock,
getWorkflowNodeIdMock,
} from '~/testing/mock-data/workflow';
export const WorkflowStepDecorator: Decorator = (Story) => {
- const setWorkflowId = useSetRecoilState(workflowIdState);
- const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
- const setFlow = useSetRecoilState(flowState);
+ const workflowVisualizerComponentInstanceId = 'workflow-visualizer-test-id';
+
const workflowVersion = getWorkflowMock().versions.edges[0]
.node as WorkflowVersion;
const { populateStepsOutputSchema } = useStepsOutputSchema();
const [ready, setReady] = useState(false);
+ const handleMount = useRecoilCallback(
+ ({ set }) =>
+ () => {
+ set(
+ workflowVisualizerWorkflowIdComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
+ getWorkflowMock().id,
+ );
+ set(
+ workflowSelectedNodeComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
+ getWorkflowNodeIdMock(),
+ );
+ set(
+ flowComponentState.atomFamily({
+ instanceId: workflowVisualizerComponentInstanceId,
+ }),
+ {
+ workflowVersionId: workflowVersion.id,
+ trigger: workflowVersion.trigger,
+ steps: workflowVersion.steps,
+ },
+ );
+ populateStepsOutputSchema(workflowVersion);
+ setReady(true);
+ },
+ [populateStepsOutputSchema, workflowVersion],
+ );
+
useEffect(() => {
- setWorkflowId(getWorkflowMock().id);
- setWorkflowSelectedNode(getWorkflowNodeIdMock());
- setFlow({
- workflowVersionId: workflowVersion.id,
- trigger: workflowVersion.trigger,
- steps: workflowVersion.steps,
- });
- populateStepsOutputSchema(workflowVersion);
- setReady(true);
- }, [
- setWorkflowId,
- setWorkflowSelectedNode,
- populateStepsOutputSchema,
- workflowVersion,
- setFlow,
- ]);
+ handleMount();
+ }, [handleMount]);
return (
-
- {ready && }
-
+
+ {ready && }
+
+
);
};