Migrate workflow states to component states (#11773)
- Migrated all workflow Recoil states to component states to isolate each workflow visualizer instance. The use case of having two workflow visualizers displayed at the same time appeared recently and will grow in the near future. - We chose to use the `recordId` as the value for the `instanceId` of the component states. Currently, there are a few cases where two workflows or two workflow runs are rendered at the same time. As a consequence, relying on the `recordId` is enough for the moment. - However, there is one case where it's necessary to have a component state scoped to a workflow visualizer instance: the `workflowVisualizerStatusState`. This component is tightly coupled to the `<Reactflow />` component instance rendered in the workflow visualizer, and it must be set to its default value when the component first renders. I achieved that by using another component instance context whose instanceId is an identifier returned by the `useId()` hook in the Workflow Run Card component.
This commit is contained in:
committed by
GitHub
parent
8b68dce795
commit
1543c900ae
@ -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('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
|
||||||
test.fail('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
|
|
||||||
workflowVisualizer,
|
workflowVisualizer,
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
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 { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
|
import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
import { useWorkflowCommandMenu } from '../useWorkflowCommandMenu';
|
import { useWorkflowCommandMenu } from '../useWorkflowCommandMenu';
|
||||||
import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui/display';
|
|
||||||
|
|
||||||
jest.mock('uuid', () => ({
|
jest.mock('uuid', () => ({
|
||||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||||
@ -95,7 +96,11 @@ const renderHooks = () => {
|
|||||||
'mocked-uuid',
|
'mocked-uuid',
|
||||||
);
|
);
|
||||||
const workflowId = useRecoilComponentValueV2(
|
const workflowId = useRecoilComponentValueV2(
|
||||||
workflowIdComponentState,
|
commandMenuWorkflowIdComponentState,
|
||||||
|
'mocked-uuid',
|
||||||
|
);
|
||||||
|
const workflowVersionId = useRecoilComponentValueV2(
|
||||||
|
commandMenuWorkflowVersionIdComponentState,
|
||||||
'mocked-uuid',
|
'mocked-uuid',
|
||||||
);
|
);
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
@ -106,6 +111,7 @@ const renderHooks = () => {
|
|||||||
openWorkflowEditStepInCommandMenu,
|
openWorkflowEditStepInCommandMenu,
|
||||||
openWorkflowViewStepInCommandMenu,
|
openWorkflowViewStepInCommandMenu,
|
||||||
workflowId,
|
workflowId,
|
||||||
|
workflowVersionId,
|
||||||
viewableRecordId,
|
viewableRecordId,
|
||||||
commandMenuPage,
|
commandMenuPage,
|
||||||
commandMenuNavigationMorphItemByPage,
|
commandMenuNavigationMorphItemByPage,
|
||||||
@ -188,14 +194,16 @@ describe('useWorkflowCommandMenu', () => {
|
|||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.openWorkflowViewStepInCommandMenu(
|
result.current.openWorkflowViewStepInCommandMenu({
|
||||||
'test-workflow-id',
|
workflowId: 'test-workflow-id',
|
||||||
'View Step',
|
workflowVersionId: 'test-workflow-version-id',
|
||||||
IconSettingsAutomation,
|
icon: IconSettingsAutomation,
|
||||||
);
|
title: 'View Step',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.workflowId).toBe('test-workflow-id');
|
expect(result.current.workflowId).toBe('test-workflow-id');
|
||||||
|
expect(result.current.workflowVersionId).toBe('test-workflow-version-id');
|
||||||
|
|
||||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||||
page: CommandMenuPages.WorkflowStepView,
|
page: CommandMenuPages.WorkflowStepView,
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
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 { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||||
import { useSetInitialWorkflowRunRightDrawerTab } from '@/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab';
|
import { useSetInitialWorkflowRunRightDrawerTab } from '@/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab';
|
||||||
import { WorkflowDiagramRunStatus } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramRunStatus } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
@ -23,7 +25,9 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
const pageId = v4();
|
const pageId = v4();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
commandMenuWorkflowIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
workflowId,
|
workflowId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -44,7 +48,9 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
const pageId = v4();
|
const pageId = v4();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
commandMenuWorkflowIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
workflowId,
|
workflowId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -65,7 +71,9 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
const pageId = v4();
|
const pageId = v4();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
commandMenuWorkflowIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
workflowId,
|
workflowId,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -82,13 +90,31 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
|
|
||||||
const openWorkflowViewStepInCommandMenu = useRecoilCallback(
|
const openWorkflowViewStepInCommandMenu = useRecoilCallback(
|
||||||
({ set }) => {
|
({ set }) => {
|
||||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
return ({
|
||||||
|
workflowId,
|
||||||
|
workflowVersionId,
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
}: {
|
||||||
|
workflowId: string;
|
||||||
|
workflowVersionId: string;
|
||||||
|
title: string;
|
||||||
|
icon: IconComponent;
|
||||||
|
}) => {
|
||||||
const pageId = v4();
|
const pageId = v4();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
commandMenuWorkflowIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
workflowId,
|
workflowId,
|
||||||
);
|
);
|
||||||
|
set(
|
||||||
|
commandMenuWorkflowVersionIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
|
workflowVersionId,
|
||||||
|
);
|
||||||
|
|
||||||
navigateCommandMenu({
|
navigateCommandMenu({
|
||||||
page: CommandMenuPages.WorkflowStepView,
|
page: CommandMenuPages.WorkflowStepView,
|
||||||
@ -105,12 +131,14 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
({ set }) => {
|
({ set }) => {
|
||||||
return ({
|
return ({
|
||||||
workflowId,
|
workflowId,
|
||||||
|
workflowRunId,
|
||||||
title,
|
title,
|
||||||
icon,
|
icon,
|
||||||
workflowSelectedNode,
|
workflowSelectedNode,
|
||||||
stepExecutionStatus,
|
stepExecutionStatus,
|
||||||
}: {
|
}: {
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
|
workflowRunId: string;
|
||||||
title: string;
|
title: string;
|
||||||
icon: IconComponent;
|
icon: IconComponent;
|
||||||
workflowSelectedNode: string;
|
workflowSelectedNode: string;
|
||||||
@ -119,9 +147,17 @@ export const useWorkflowCommandMenu = () => {
|
|||||||
const pageId = v4();
|
const pageId = v4();
|
||||||
|
|
||||||
set(
|
set(
|
||||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
commandMenuWorkflowIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
workflowId,
|
workflowId,
|
||||||
);
|
);
|
||||||
|
set(
|
||||||
|
commandMenuWorkflowRunIdComponentState.atomFamily({
|
||||||
|
instanceId: pageId,
|
||||||
|
}),
|
||||||
|
workflowRunId,
|
||||||
|
);
|
||||||
|
|
||||||
navigateCommandMenu({
|
navigateCommandMenu({
|
||||||
page: CommandMenuPages.WorkflowRunStepView,
|
page: CommandMenuPages.WorkflowRunStepView,
|
||||||
|
|||||||
@ -1,16 +1,27 @@
|
|||||||
import { CommandMenuWorkflowSelectActionContent } from '@/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent';
|
import { CommandMenuWorkflowSelectActionContent } from '@/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectActionContent';
|
||||||
import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
|
import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
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';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const CommandMenuWorkflowSelectAction = () => {
|
export const CommandMenuWorkflowSelectAction = () => {
|
||||||
const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
|
const workflowId = useCommandMenuWorkflowIdOrThrow();
|
||||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
if (!isDefined(workflow)) {
|
if (!isDefined(workflow)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <CommandMenuWorkflowSelectActionContent workflow={workflow} />;
|
return (
|
||||||
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
|
recordId: workflowId,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CommandMenuWorkflowSelectActionContent workflow={workflow} />
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
||||||
|
};
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const workflowIdComponentState = createComponentStateV2<
|
export const commandMenuWorkflowIdComponentState = createComponentStateV2<
|
||||||
string | undefined
|
string | undefined
|
||||||
>({
|
>({
|
||||||
key: 'command-menu/workflow-id',
|
key: 'command-menu/workflow-id',
|
||||||
@ -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,
|
||||||
|
});
|
||||||
@ -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<string | undefined>({
|
||||||
|
key: 'command-menu/workflow-version-id',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: CommandMenuPageComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -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 { 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 { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
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';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const CommandMenuWorkflowEditStep = () => {
|
export const CommandMenuWorkflowEditStep = () => {
|
||||||
const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
|
const workflowId = useCommandMenuWorkflowIdOrThrow();
|
||||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
if (!isDefined(workflow)) {
|
if (!isDefined(workflow)) {
|
||||||
@ -14,10 +15,18 @@ export const CommandMenuWorkflowEditStep = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowStepContextProvider
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
value={{ workflowVersionId: workflow.currentVersion.id }}
|
value={{
|
||||||
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
|
recordId: workflowId,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<CommandMenuWorkflowEditStepContent workflow={workflow} />
|
<WorkflowStepContextProvider
|
||||||
</WorkflowStepContextProvider>
|
value={{ workflowVersionId: workflow.currentVersion.id }}
|
||||||
|
>
|
||||||
|
<CommandMenuWorkflowEditStepContent workflow={workflow} />
|
||||||
|
</WorkflowStepContextProvider>
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,132 +1,20 @@
|
|||||||
import { getIsInputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsInputTabDisabled';
|
import { CommandMenuWorkflowRunViewStepContent } from '@/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent';
|
||||||
import { getIsOutputTabDisabled } from '@/command-menu/pages/workflow/step/view-run/utils/getIsOutputTabDisabled';
|
import { useCommandMenuWorkflowRunIdOrThrow } from '@/command-menu/pages/workflow/step/view-run/hooks/useCommandMenuWorkflowRunIdOrThrow';
|
||||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||||
import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList';
|
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||||
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 CommandMenuWorkflowRunViewStep = () => {
|
export const CommandMenuWorkflowRunViewStep = () => {
|
||||||
const flow = useFlowOrThrow();
|
const workflowRunId = useCommandMenuWorkflowRunIdOrThrow();
|
||||||
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<TabId>[] = [
|
|
||||||
{
|
|
||||||
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 (
|
return (
|
||||||
<WorkflowStepContextProvider
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
workflowVersionId: workflowRun.workflowVersionId,
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
workflowRunId: workflowRun.id,
|
recordId: workflowRunId,
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledContainer>
|
<CommandMenuWorkflowRunViewStepContent />
|
||||||
<StyledTabList
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
tabs={tabs}
|
|
||||||
behaveAsLinks={false}
|
|
||||||
componentInstanceId={commandMenuPageComponentInstance.instanceId}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{activeTabId === WorkflowRunTabId.OUTPUT ? (
|
|
||||||
<WorkflowRunStepOutputDetail
|
|
||||||
key={workflowSelectedNode}
|
|
||||||
stepId={workflowSelectedNode}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{activeTabId === WorkflowRunTabId.NODE ? (
|
|
||||||
<WorkflowRunStepNodeDetail
|
|
||||||
stepId={workflowSelectedNode}
|
|
||||||
trigger={flow.trigger}
|
|
||||||
steps={flow.steps}
|
|
||||||
stepExecutionStatus={stepExecutionStatus}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{activeTabId === WorkflowRunTabId.INPUT ? (
|
|
||||||
<WorkflowRunStepInputDetail
|
|
||||||
key={workflowSelectedNode}
|
|
||||||
stepId={workflowSelectedNode}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</StyledContainer>
|
|
||||||
</WorkflowStepContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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<TabId>[] = [
|
||||||
|
{
|
||||||
|
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 (
|
||||||
|
<WorkflowStepContextProvider
|
||||||
|
value={{
|
||||||
|
workflowVersionId: workflowRun.workflowVersionId,
|
||||||
|
workflowRunId: workflowRun.id,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StyledContainer>
|
||||||
|
<StyledTabList
|
||||||
|
tabs={tabs}
|
||||||
|
behaveAsLinks={false}
|
||||||
|
componentInstanceId={commandMenuPageComponentInstance.instanceId}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{activeTabId === WorkflowRunTabId.OUTPUT ? (
|
||||||
|
<WorkflowRunStepOutputDetail
|
||||||
|
key={workflowSelectedNode}
|
||||||
|
stepId={workflowSelectedNode}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeTabId === WorkflowRunTabId.NODE ? (
|
||||||
|
<WorkflowRunStepNodeDetail
|
||||||
|
stepId={workflowSelectedNode}
|
||||||
|
trigger={flow.trigger}
|
||||||
|
steps={flow.steps}
|
||||||
|
stepExecutionStatus={stepExecutionStatus}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeTabId === WorkflowRunTabId.INPUT ? (
|
||||||
|
<WorkflowRunStepInputDetail
|
||||||
|
key={workflowSelectedNode}
|
||||||
|
stepId={workflowSelectedNode}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</StyledContainer>
|
||||||
|
</WorkflowStepContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -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;
|
||||||
|
};
|
||||||
@ -1,31 +1,20 @@
|
|||||||
import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow';
|
import { useCommandMenuWorkflowVersionIdOrThrow } from '@/command-menu/pages/workflow/step/view/hooks/useCommandMenuWorkflowVersionIdOrThrow';
|
||||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
import { CommandMenuWorkflowViewStepContent } from '@/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent';
|
||||||
import { useWorkflowSelectedNodeOrThrow } from '@/workflow/workflow-diagram/hooks/useWorkflowSelectedNodeOrThrow';
|
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||||
import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail';
|
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CommandMenuWorkflowViewStep = () => {
|
export const CommandMenuWorkflowViewStep = () => {
|
||||||
const flow = useFlowOrThrow();
|
const workflowVersionId = useCommandMenuWorkflowVersionIdOrThrow();
|
||||||
const workflowSelectedNode = useWorkflowSelectedNodeOrThrow();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowStepContextProvider
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
value={{ workflowVersionId: flow.workflowVersionId }}
|
value={{
|
||||||
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
|
recordId: workflowVersionId,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<StyledContainer>
|
<CommandMenuWorkflowViewStepContent />
|
||||||
<WorkflowStepDetail
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
stepId={workflowSelectedNode}
|
|
||||||
trigger={flow.trigger}
|
|
||||||
steps={flow.steps}
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
</StyledContainer>
|
|
||||||
</WorkflowStepContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 (
|
||||||
|
<WorkflowStepContextProvider
|
||||||
|
value={{ workflowVersionId: flow.workflowVersionId }}
|
||||||
|
>
|
||||||
|
<StyledContainer>
|
||||||
|
<WorkflowStepDetail
|
||||||
|
stepId={workflowSelectedNode}
|
||||||
|
trigger={flow.trigger}
|
||||||
|
steps={flow.steps}
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
|
</WorkflowStepContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -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;
|
||||||
|
};
|
||||||
@ -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 { 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 { 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';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const CommandMenuWorkflowSelectTriggerType = () => {
|
export const CommandMenuWorkflowSelectTriggerType = () => {
|
||||||
const workflowId = useRecoilComponentValueV2(workflowIdComponentState);
|
const workflowId = useCommandMenuWorkflowIdOrThrow();
|
||||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
if (!isDefined(workflow)) {
|
if (!isDefined(workflow)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <CommandMenuWorkflowSelectTriggerTypeContent workflow={workflow} />;
|
return (
|
||||||
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
|
recordId: workflowId,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CommandMenuWorkflowSelectTriggerTypeContent workflow={workflow} />
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import {
|
import {
|
||||||
WorkflowTriggerType,
|
WorkflowTriggerType,
|
||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
} from '@/workflow/types/Workflow';
|
} 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 { RightDrawerStepListContainer } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepContainer';
|
||||||
import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
|
import { RightDrawerWorkflowSelectStepTitle } from '@/workflow/workflow-steps/components/RightDrawerWorkflowSelectStepTitle';
|
||||||
import { DATABASE_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/DatabaseTriggerTypes';
|
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 { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
|
||||||
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
||||||
import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition';
|
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 { useIcons } from 'twenty-ui/display';
|
||||||
|
import { MenuItemCommand } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
export const CommandMenuWorkflowSelectTriggerTypeContent = ({
|
export const CommandMenuWorkflowSelectTriggerTypeContent = ({
|
||||||
workflow,
|
workflow,
|
||||||
@ -26,7 +26,9 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({
|
|||||||
|
|
||||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||||
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
const handleTriggerTypeClick = ({
|
const handleTriggerTypeClick = ({
|
||||||
|
|||||||
@ -7,15 +7,19 @@ import { TimelineActivities } from '@/activities/timeline-activities/components/
|
|||||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||||
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
||||||
import { CardType } from '@/object-record/record-show/types/CardType';
|
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 { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer';
|
||||||
|
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||||
import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizer';
|
import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizer';
|
||||||
import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect';
|
import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect';
|
||||||
import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer';
|
import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer';
|
||||||
import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect';
|
import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect';
|
||||||
import { WorkflowVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVisualizer';
|
import { WorkflowVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVisualizer';
|
||||||
import { WorkflowVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVisualizerEffect';
|
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 styled from '@emotion/styled';
|
||||||
import { ListenRecordUpdatesEffect } from '@/subscription/components/ListenUpdatesEffect';
|
import { useId } from 'react';
|
||||||
|
|
||||||
const StyledGreyBox = styled.div<{ isInRightDrawer?: boolean }>`
|
const StyledGreyBox = styled.div<{ isInRightDrawer?: boolean }>`
|
||||||
background: ${({ theme, isInRightDrawer }) =>
|
background: ${({ theme, isInRightDrawer }) =>
|
||||||
@ -81,32 +85,63 @@ export const CardComponents: Record<CardType, CardComponentType> = {
|
|||||||
<Calendar targetableObject={targetableObject} />
|
<Calendar targetableObject={targetableObject} />
|
||||||
),
|
),
|
||||||
|
|
||||||
[CardType.WorkflowCard]: ({ targetableObject }) => (
|
[CardType.WorkflowCard]: ({ targetableObject }) => {
|
||||||
<>
|
return (
|
||||||
<WorkflowVisualizerEffect workflowId={targetableObject.id} />
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
<WorkflowVisualizer workflowId={targetableObject.id} />
|
value={{
|
||||||
</>
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
),
|
recordId: targetableObject.id,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<WorkflowVisualizerEffect workflowId={targetableObject.id} />
|
||||||
|
<WorkflowVisualizer workflowId={targetableObject.id} />
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
[CardType.WorkflowVersionCard]: ({ targetableObject }) => (
|
[CardType.WorkflowVersionCard]: ({ targetableObject }) => {
|
||||||
<>
|
return (
|
||||||
<WorkflowVersionVisualizerEffect
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
workflowVersionId={targetableObject.id}
|
value={{
|
||||||
/>
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
<WorkflowVersionVisualizer workflowVersionId={targetableObject.id} />
|
recordId: targetableObject.id,
|
||||||
</>
|
}),
|
||||||
),
|
}}
|
||||||
|
>
|
||||||
|
<WorkflowVersionVisualizerEffect
|
||||||
|
workflowVersionId={targetableObject.id}
|
||||||
|
/>
|
||||||
|
<WorkflowVersionVisualizer workflowVersionId={targetableObject.id} />
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
[CardType.WorkflowRunCard]: ({ targetableObject }) => (
|
[CardType.WorkflowRunCard]: ({ targetableObject }) => {
|
||||||
<>
|
const componentId = useId();
|
||||||
<WorkflowRunVisualizerEffect workflowRunId={targetableObject.id} />
|
|
||||||
<ListenRecordUpdatesEffect
|
|
||||||
objectNameSingular={targetableObject.targetObjectNameSingular}
|
|
||||||
recordId={targetableObject.id}
|
|
||||||
listenedFields={['status', 'output']}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<WorkflowRunVisualizer workflowRunId={targetableObject.id} />
|
return (
|
||||||
</>
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
),
|
value={{
|
||||||
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
|
recordId: targetableObject.id,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<WorkflowRunVisualizerComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: componentId,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<WorkflowRunVisualizerEffect workflowRunId={targetableObject.id} />
|
||||||
|
<ListenRecordUpdatesEffect
|
||||||
|
objectNameSingular={targetableObject.targetObjectNameSingular}
|
||||||
|
recordId={targetableObject.id}
|
||||||
|
listenedFields={['status', 'output']}
|
||||||
|
/>
|
||||||
|
<WorkflowRunVisualizer workflowRunId={targetableObject.id} />
|
||||||
|
</WorkflowRunVisualizerComponentInstanceContext.Provider>
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { flowState } from '@/workflow/states/flowState';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useFlowOrThrow = () => {
|
export const useFlowOrThrow = () => {
|
||||||
const flow = useRecoilValue(flowState);
|
const flow = useRecoilComponentValueV2(flowComponentState);
|
||||||
|
|
||||||
if (!isDefined(flow)) {
|
if (!isDefined(flow)) {
|
||||||
throw new Error('Expected the flow to be defined');
|
throw new Error('Expected the flow to be defined');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,11 +3,12 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
|
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
import { flowState } from '@/workflow/states/flowState';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
|
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
|
||||||
import { WorkflowRun } from '@/workflow/types/Workflow';
|
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 { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
@ -58,17 +59,46 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set(workflowRunIdState, workflowRunRecord.id);
|
set(
|
||||||
set(workflowIdState, workflowRunRecord.workflowId);
|
workflowVisualizerWorkflowRunIdComponentState.atomFamily({
|
||||||
set(flowState, {
|
instanceId: getWorkflowVisualizerComponentInstanceId({
|
||||||
workflowVersionId: workflowRunRecord.workflowVersionId,
|
recordId,
|
||||||
trigger: workflowRunRecord.output.flow.trigger,
|
}),
|
||||||
steps: workflowRunRecord.output.flow.steps,
|
}),
|
||||||
});
|
workflowRunRecord.id,
|
||||||
set(workflowSelectedNodeState, stepToOpenByDefault.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({
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
workflowId: workflowRunRecord.workflowId,
|
workflowId: workflowRunRecord.workflowId,
|
||||||
|
workflowRunId: workflowRunRecord.id,
|
||||||
title: stepToOpenByDefault.data.name,
|
title: stepToOpenByDefault.data.name,
|
||||||
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
|
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
|
||||||
workflowSelectedNode: stepToOpenByDefault.id,
|
workflowSelectedNode: stepToOpenByDefault.id,
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useWorkflowRunIdOrThrow = () => {
|
export const useWorkflowRunIdOrThrow = () => {
|
||||||
const workflowRunId = useRecoilValue(workflowRunIdState);
|
const workflowRunId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowRunIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
if (!isDefined(workflowRunId)) {
|
if (!isDefined(workflowRunId)) {
|
||||||
throw new Error('Expected the workflow run ID to be defined');
|
throw new Error('Expected the workflow run ID to be defined');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
});
|
||||||
@ -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,
|
|
||||||
});
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
export const workflowIdState = createState<string | undefined>({
|
|
||||||
key: 'workflowIdState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -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,
|
||||||
|
});
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
export const workflowLastCreatedStepIdState = createState<string | undefined>({
|
|
||||||
key: 'workflowLastCreatedStepIdState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
|
|
||||||
export const workflowRunIdState = createState<string | undefined>({
|
|
||||||
key: 'workflowRunIdState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -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<string | undefined>({
|
||||||
|
key: 'workflowVisualizerWorkflowIdComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -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<string | undefined>({
|
||||||
|
key: 'workflowVisualizerWorkflowRunIdComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -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<string | undefined>({
|
||||||
|
key: 'workflowVisualizerWorkflowVersionIdComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export const getWorkflowVisualizerComponentInstanceId = ({
|
||||||
|
recordId,
|
||||||
|
}: {
|
||||||
|
recordId: string;
|
||||||
|
}) => {
|
||||||
|
return recordId;
|
||||||
|
};
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import { useListenRightDrawerClose } from '@/ui/layout/right-drawer/hooks/useListenRightDrawerClose';
|
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 { WorkflowDiagramCustomMarkers } from '@/workflow/workflow-diagram/components/WorkflowDiagramCustomMarkers';
|
||||||
import { useRightDrawerState } from '@/workflow/workflow-diagram/hooks/useRightDrawerState';
|
import { useRightDrawerState } from '@/workflow/workflow-diagram/hooks/useRightDrawerState';
|
||||||
import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
|
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||||
import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState';
|
|
||||||
import {
|
import {
|
||||||
WorkflowDiagramEdge,
|
WorkflowDiagramEdge,
|
||||||
WorkflowDiagramEdgeType,
|
WorkflowDiagramEdgeType,
|
||||||
@ -26,7 +27,6 @@ import {
|
|||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
import React, { useEffect, useMemo, useRef } from 'react';
|
import React, { useEffect, useMemo, useRef } from 'react';
|
||||||
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { Tag, TagColor } from 'twenty-ui/components';
|
import { Tag, TagColor } from 'twenty-ui/components';
|
||||||
import { THEME_COMMON } from 'twenty-ui/theme';
|
import { THEME_COMMON } from 'twenty-ui/theme';
|
||||||
@ -121,7 +121,9 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
|
|
||||||
const reactflow = useReactFlow();
|
const reactflow = useReactFlow();
|
||||||
|
|
||||||
const workflowDiagram = useRecoilValue(workflowDiagramState);
|
const workflowDiagram = useRecoilComponentValueV2(
|
||||||
|
workflowDiagramComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const { nodes, edges } = useMemo(
|
const { nodes, edges } = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -137,14 +139,8 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
THEME_COMMON.rightDrawerWidth.replace('px', ''),
|
THEME_COMMON.rightDrawerWidth.replace('px', ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
|
const setWorkflowDiagram = useSetRecoilComponentStateV2(
|
||||||
|
workflowDiagramComponentState,
|
||||||
const setWorkflowReactFlowRef = useRecoilCallback(
|
|
||||||
({ set }) =>
|
|
||||||
(node: HTMLDivElement | null) => {
|
|
||||||
set(workflowReactFlowRefState, { current: node });
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleEdgesChange = (
|
const handleEdgesChange = (
|
||||||
@ -199,24 +195,18 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
);
|
);
|
||||||
}, [reactflow, rightDrawerState, rightDrawerWidth]);
|
}, [reactflow, rightDrawerState, rightDrawerWidth]);
|
||||||
|
|
||||||
const handleNodesChanges = useRecoilCallback(
|
const handleNodesChanges = (changes: NodeChange<WorkflowDiagramNode>[]) => {
|
||||||
({ set }) =>
|
setWorkflowDiagram((diagram) => {
|
||||||
(changes: NodeChange<WorkflowDiagramNode>[]) => {
|
if (!isDefined(diagram)) {
|
||||||
set(workflowDiagramState, (diagram) => {
|
return 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.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...diagram,
|
...diagram,
|
||||||
nodes: applyNodeChanges(changes, diagram.nodes),
|
nodes: applyNodeChanges(changes, diagram.nodes),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleInit = () => {
|
const handleInit = () => {
|
||||||
if (!isDefined(containerRef.current)) {
|
if (!isDefined(containerRef.current)) {
|
||||||
@ -239,7 +229,6 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
<WorkflowDiagramCustomMarkers />
|
<WorkflowDiagramCustomMarkers />
|
||||||
|
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
ref={setWorkflowReactFlowRef}
|
|
||||||
onInit={handleInit}
|
onInit={handleInit}
|
||||||
minZoom={defaultFitViewOptions.minZoom}
|
minZoom={defaultFitViewOptions.minZoom}
|
||||||
maxZoom={defaultFitViewOptions.maxZoom}
|
maxZoom={defaultFitViewOptions.maxZoom}
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
import { useCallback, useContext } from 'react';
|
import { useCallback, useContext } from 'react';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
|
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
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 { EMPTY_TRIGGER_STEP_ID } from '@/workflow/workflow-diagram/constants/EmptyTriggerStepId';
|
import { EMPTY_TRIGGER_STEP_ID } from '@/workflow/workflow-diagram/constants/EmptyTriggerStepId';
|
||||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
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 {
|
import {
|
||||||
WorkflowDiagramNode,
|
WorkflowDiagramNode,
|
||||||
WorkflowDiagramStepNodeData,
|
WorkflowDiagramStepNodeData,
|
||||||
@ -29,7 +31,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
openWorkflowEditStepInCommandMenu,
|
openWorkflowEditStepInCommandMenu,
|
||||||
} = useWorkflowCommandMenu();
|
} = useWorkflowCommandMenu();
|
||||||
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
commandMenuNavigationStackState,
|
commandMenuNavigationStackState,
|
||||||
@ -37,7 +41,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
|
|
||||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleSelectionChange = useCallback(
|
const handleSelectionChange = useCallback(
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
({ nodes }: OnSelectionChangeParams) => {
|
||||||
@ -53,8 +59,8 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
|
|
||||||
const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID;
|
const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID;
|
||||||
if (isEmptyTriggerNode) {
|
if (isEmptyTriggerNode) {
|
||||||
if (isDefined(workflowId)) {
|
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||||
openWorkflowTriggerTypeInCommandMenu(workflowId);
|
openWorkflowTriggerTypeInCommandMenu(workflowVisualizerWorkflowId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,9 +77,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
|
|
||||||
setWorkflowSelectedNode(selectedNode.id);
|
setWorkflowSelectedNode(selectedNode.id);
|
||||||
|
|
||||||
if (isDefined(workflowId)) {
|
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||||
openWorkflowEditStepInCommandMenu(
|
openWorkflowEditStepInCommandMenu(
|
||||||
workflowId,
|
workflowVisualizerWorkflowId,
|
||||||
selectedNodeData.name,
|
selectedNodeData.name,
|
||||||
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
||||||
);
|
);
|
||||||
@ -84,7 +90,7 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
[
|
[
|
||||||
isInRightDrawer,
|
isInRightDrawer,
|
||||||
setCommandMenuNavigationStack,
|
setCommandMenuNavigationStack,
|
||||||
workflowId,
|
workflowVisualizerWorkflowId,
|
||||||
openWorkflowTriggerTypeInCommandMenu,
|
openWorkflowTriggerTypeInCommandMenu,
|
||||||
startNodeCreation,
|
startNodeCreation,
|
||||||
openWorkflowEditStepInCommandMenu,
|
openWorkflowEditStepInCommandMenu,
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
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 { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import {
|
import {
|
||||||
WorkflowDiagramNode,
|
WorkflowDiagramNode,
|
||||||
WorkflowDiagramStepNodeData,
|
WorkflowDiagramStepNodeData,
|
||||||
@ -9,19 +12,34 @@ import {
|
|||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const WorkflowDiagramCanvasReadonlyEffect = () => {
|
export const WorkflowDiagramCanvasReadonlyEffect = () => {
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflowVisualizerWorkflowVersionId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowVersionIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleSelectionChange = useCallback(
|
const handleSelectionChange = useCallback(
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
({ nodes }: OnSelectionChangeParams) => {
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
isDefined(workflowVisualizerWorkflowId) &&
|
||||||
|
isDefined(workflowVisualizerWorkflowVersionId)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const selectedNode = nodes[0] as WorkflowDiagramNode | undefined;
|
const selectedNode = nodes[0] as WorkflowDiagramNode | undefined;
|
||||||
|
|
||||||
if (!isDefined(selectedNode)) {
|
if (!isDefined(selectedNode)) {
|
||||||
@ -32,18 +50,18 @@ export const WorkflowDiagramCanvasReadonlyEffect = () => {
|
|||||||
|
|
||||||
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
|
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
|
||||||
|
|
||||||
if (isDefined(workflowId)) {
|
openWorkflowViewStepInCommandMenu({
|
||||||
openWorkflowViewStepInCommandMenu(
|
workflowId: workflowVisualizerWorkflowId,
|
||||||
workflowId,
|
workflowVersionId: workflowVisualizerWorkflowVersionId,
|
||||||
selectedNodeData.name,
|
title: selectedNodeData.name,
|
||||||
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
||||||
);
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
setWorkflowSelectedNode,
|
setWorkflowSelectedNode,
|
||||||
openWorkflowViewStepInCommandMenu,
|
openWorkflowViewStepInCommandMenu,
|
||||||
workflowId,
|
workflowVisualizerWorkflowId,
|
||||||
|
workflowVisualizerWorkflowVersionId,
|
||||||
getIcon,
|
getIcon,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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 { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
||||||
import { flowState } from '@/workflow/states/flowState';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
|
import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState';
|
||||||
import {
|
import {
|
||||||
WorkflowVersion,
|
WorkflowVersion,
|
||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
} from '@/workflow/types/Workflow';
|
} 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 { addCreateStepNodes } from '@/workflow/workflow-diagram/utils/addCreateStepNodes';
|
||||||
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
|
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
|
||||||
import { mergeWorkflowDiagrams } from '@/workflow/workflow-diagram/utils/mergeWorkflowDiagrams';
|
import { mergeWorkflowDiagrams } from '@/workflow/workflow-diagram/utils/mergeWorkflowDiagrams';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const WorkflowDiagramEffect = ({
|
export const WorkflowDiagramEffect = ({
|
||||||
@ -20,10 +22,19 @@ export const WorkflowDiagramEffect = ({
|
|||||||
}: {
|
}: {
|
||||||
workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined;
|
workflowWithCurrentVersion: WorkflowWithCurrentVersion | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
|
const workflowDiagramState = useRecoilComponentCallbackStateV2(
|
||||||
const setFlow = useSetRecoilState(flowState);
|
workflowDiagramComponentState,
|
||||||
|
);
|
||||||
|
const setWorkflowDiagram = useSetRecoilComponentStateV2(
|
||||||
|
workflowDiagramComponentState,
|
||||||
|
);
|
||||||
|
const setFlow = useSetRecoilComponentStateV2(flowComponentState);
|
||||||
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
||||||
|
|
||||||
|
const workflowLastCreatedStepIdState = useRecoilComponentCallbackStateV2(
|
||||||
|
workflowLastCreatedStepIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const computeAndMergeNewWorkflowDiagram = useRecoilCallback(
|
const computeAndMergeNewWorkflowDiagram = useRecoilCallback(
|
||||||
({ snapshot, set }) => {
|
({ snapshot, set }) => {
|
||||||
return (currentVersion: WorkflowVersion) => {
|
return (currentVersion: WorkflowVersion) => {
|
||||||
@ -64,7 +75,7 @@ export const WorkflowDiagramEffect = ({
|
|||||||
set(workflowDiagramState, mergedWorkflowDiagram);
|
set(workflowDiagramState, mergedWorkflowDiagram);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[],
|
[workflowLastCreatedStepIdState, workflowDiagramState],
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentVersion = workflowWithCurrentVersion?.currentVersion;
|
const currentVersion = workflowWithCurrentVersion?.currentVersion;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
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 { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined';
|
||||||
import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent';
|
import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent';
|
||||||
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
export const WorkflowDiagramStepNodeEditable = ({
|
export const WorkflowDiagramStepNodeEditable = ({
|
||||||
id,
|
id,
|
||||||
@ -15,9 +15,13 @@ export const WorkflowDiagramStepNodeEditable = ({
|
|||||||
data: WorkflowDiagramStepNodeData;
|
data: WorkflowDiagramStepNodeData;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(
|
||||||
|
workflowVisualizerWorkflowId,
|
||||||
|
);
|
||||||
assertWorkflowWithCurrentVersionIsDefined(workflowWithCurrentVersion);
|
assertWorkflowWithCurrentVersionIsDefined(workflowWithCurrentVersion);
|
||||||
|
|
||||||
const { deleteStep } = useDeleteStep({
|
const { deleteStep } = useDeleteStep({
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
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 { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||||
import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
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 { WorkflowRunDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
||||||
@ -15,10 +17,25 @@ export const WorkflowRunDiagramCanvasEffect = () => {
|
|||||||
|
|
||||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackStateV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflowDiagramStatusState = useRecoilComponentCallbackStateV2(
|
||||||
|
workflowDiagramStatusComponentState,
|
||||||
|
);
|
||||||
|
const workflowSelectedNodeState = useRecoilComponentCallbackStateV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleSelectionChange = useRecoilCallback(
|
const handleSelectionChange = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
({ nodes }: OnSelectionChangeParams) => {
|
||||||
const workflowId = getSnapshotValue(snapshot, workflowIdState);
|
const workflowId = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
workflowVisualizerWorkflowIdState,
|
||||||
|
);
|
||||||
|
|
||||||
if (!isDefined(workflowId)) {
|
if (!isDefined(workflowId)) {
|
||||||
throw new Error('Expected the workflowId to be defined.');
|
throw new Error('Expected the workflowId to be defined.');
|
||||||
@ -49,13 +66,21 @@ export const WorkflowRunDiagramCanvasEffect = () => {
|
|||||||
|
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
workflowId,
|
workflowId,
|
||||||
|
workflowRunId,
|
||||||
title: selectedNodeData.name,
|
title: selectedNodeData.name,
|
||||||
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
||||||
workflowSelectedNode: selectedNode.id,
|
workflowSelectedNode: selectedNode.id,
|
||||||
stepExecutionStatus: selectedNodeData.runStatus,
|
stepExecutionStatus: selectedNodeData.runStatus,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[getIcon, openWorkflowRunViewStepInCommandMenu],
|
[
|
||||||
|
workflowVisualizerWorkflowIdState,
|
||||||
|
workflowDiagramStatusState,
|
||||||
|
workflowSelectedNodeState,
|
||||||
|
openWorkflowRunViewStepInCommandMenu,
|
||||||
|
workflowRunId,
|
||||||
|
getIcon,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
useOnSelectionChange({
|
useOnSelectionChange({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||||
import { WorkflowRunDiagramCanvas } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvas';
|
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 styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -15,7 +15,9 @@ export const WorkflowRunVisualizer = ({
|
|||||||
workflowRunId: string;
|
workflowRunId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||||
const workflowDiagramStatus = useRecoilValue(workflowDiagramStatusState);
|
const workflowDiagramStatus = useRecoilComponentValueV2(
|
||||||
|
workflowDiagramStatusComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isDefined(workflowRun) ||
|
!isDefined(workflowRun) ||
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
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 { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
||||||
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun';
|
||||||
import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
|
import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
|
||||||
import { flowState } from '@/workflow/states/flowState';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowRunIdState } from '@/workflow/states/workflowRunIdState';
|
import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState';
|
||||||
import { WorkflowRunOutput } from '@/workflow/types/Workflow';
|
import { WorkflowRunOutput } from '@/workflow/types/Workflow';
|
||||||
import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
|
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||||
import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
|
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
||||||
import { workflowRunStepToOpenByDefaultState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState';
|
import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
|
||||||
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
import { generateWorkflowRunDiagram } from '@/workflow/workflow-diagram/utils/generateWorkflowRunDiagram';
|
||||||
import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode';
|
import { selectWorkflowDiagramNode } from '@/workflow/workflow-diagram/utils/selectWorkflowDiagramNode';
|
||||||
import { useContext, useEffect } from 'react';
|
import { useContext, useEffect } from 'react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const WorkflowRunVisualizerEffect = ({
|
export const WorkflowRunVisualizerEffect = ({
|
||||||
@ -23,8 +26,24 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
const workflowRun = useWorkflowRun({ workflowRunId });
|
const workflowRun = useWorkflowRun({ workflowRunId });
|
||||||
const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId);
|
const workflowVersion = useWorkflowVersion(workflowRun?.workflowVersionId);
|
||||||
|
|
||||||
const setWorkflowRunId = useSetRecoilState(workflowRunIdState);
|
const setWorkflowRunId = useSetRecoilComponentStateV2(
|
||||||
const setWorkflowId = useSetRecoilState(workflowIdState);
|
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 { populateStepsOutputSchema } = useStepsOutputSchema();
|
||||||
|
|
||||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
@ -38,11 +57,11 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setWorkflowId(workflowRun.workflowId);
|
setWorkflowVisualizerWorkflowId(workflowRun.workflowId);
|
||||||
}, [setWorkflowId, workflowRun]);
|
}, [setWorkflowVisualizerWorkflowId, workflowRun]);
|
||||||
|
|
||||||
const handleWorkflowRunDiagramGeneration = useRecoilCallback(
|
const handleWorkflowRunDiagramGeneration = useRecoilCallback(
|
||||||
({ set }) =>
|
({ snapshot, set }) =>
|
||||||
({
|
({
|
||||||
workflowRunOutput,
|
workflowRunOutput,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
@ -59,7 +78,14 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set(workflowDiagramStatusState, 'computing-diagram');
|
const workflowDiagramStatus = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
workflowDiagramStatusState,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (workflowDiagramStatus !== 'done') {
|
||||||
|
set(workflowDiagramStatusState, 'computing-diagram');
|
||||||
|
}
|
||||||
|
|
||||||
set(flowState, {
|
set(flowState, {
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
@ -89,9 +115,16 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
set(workflowDiagramState, baseWorkflowRunDiagram);
|
set(workflowDiagramState, baseWorkflowRunDiagram);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(workflowDiagramStatusState, 'computing-dimensions');
|
if (workflowDiagramStatus !== 'done') {
|
||||||
|
set(workflowDiagramStatusState, 'computing-dimensions');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[],
|
[
|
||||||
|
flowState,
|
||||||
|
workflowDiagramState,
|
||||||
|
workflowDiagramStatusState,
|
||||||
|
workflowRunStepToOpenByDefaultState,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
||||||
import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
|
import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
|
||||||
import { flowState } from '@/workflow/states/flowState';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflowDiagramState';
|
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
||||||
|
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||||
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
|
import { getWorkflowVersionDiagram } from '@/workflow/workflow-diagram/utils/getWorkflowVersionDiagram';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const WorkflowVersionVisualizerEffect = ({
|
export const WorkflowVersionVisualizerEffect = ({
|
||||||
@ -15,10 +16,19 @@ export const WorkflowVersionVisualizerEffect = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const workflowVersion = useWorkflowVersion(workflowVersionId);
|
const workflowVersion = useWorkflowVersion(workflowVersionId);
|
||||||
|
|
||||||
const setFlow = useSetRecoilState(flowState);
|
const setFlow = useSetRecoilComponentStateV2(flowComponentState);
|
||||||
const setWorkflowDiagram = useSetRecoilState(workflowDiagramState);
|
const setWorkflowDiagram = useSetRecoilComponentStateV2(
|
||||||
const setWorkflowId = useSetRecoilState(workflowIdState);
|
workflowDiagramComponentState,
|
||||||
|
);
|
||||||
|
const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentStateV2(
|
||||||
|
workflowVisualizerWorkflowVersionIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDefined(workflowVersion)) {
|
if (!isDefined(workflowVersion)) {
|
||||||
setFlow(undefined);
|
setFlow(undefined);
|
||||||
@ -32,8 +42,14 @@ export const WorkflowVersionVisualizerEffect = ({
|
|||||||
steps: workflowVersion.steps,
|
steps: workflowVersion.steps,
|
||||||
});
|
});
|
||||||
|
|
||||||
setWorkflowId(workflowVersion.workflowId);
|
setWorkflowVisualizerWorkflowId(workflowVersion.workflowId);
|
||||||
}, [setFlow, setWorkflowId, workflowVersion]);
|
setWorkflowVisualizerWorkflowVersionId(workflowVersion.id);
|
||||||
|
}, [
|
||||||
|
setFlow,
|
||||||
|
setWorkflowVisualizerWorkflowId,
|
||||||
|
setWorkflowVisualizerWorkflowVersionId,
|
||||||
|
workflowVersion,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDefined(workflowVersion)) {
|
if (!isDefined(workflowVersion)) {
|
||||||
|
|||||||
@ -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 { useEffect } from 'react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
export const WorkflowVisualizerEffect = ({
|
export const WorkflowVisualizerEffect = ({
|
||||||
workflowId,
|
workflowId,
|
||||||
}: {
|
}: {
|
||||||
workflowId: string;
|
workflowId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const setWorkflowId = useSetRecoilState(workflowIdState);
|
const setWorkflowVisualizerWorkflowId = useSetRecoilComponentStateV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setWorkflowId(workflowId);
|
setWorkflowVisualizerWorkflowId(workflowId);
|
||||||
}, [setWorkflowId, workflowId]);
|
}, [setWorkflowVisualizerWorkflowId, workflowId]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,11 +9,12 @@ import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/com
|
|||||||
import { WorkflowDiagramSuccessEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramSuccessEdge';
|
import { WorkflowDiagramSuccessEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramSuccessEdge';
|
||||||
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeDefaultConfiguration';
|
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 { 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 { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
||||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { workflowDiagramState } from '../../states/workflowDiagramState';
|
import { workflowDiagramComponentState } from '../../states/workflowDiagramComponentState';
|
||||||
import { WorkflowDiagramCanvasBase } from '../WorkflowDiagramCanvasBase';
|
import { WorkflowDiagramCanvasBase } from '../WorkflowDiagramCanvasBase';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -51,63 +52,79 @@ export const DefaultEdge: Story = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => (
|
(Story) => {
|
||||||
<RecoilRoot
|
const workflowVisualizerComponentInstanceId =
|
||||||
initializeState={({ set }) => {
|
'workflow-visualizer-test-id';
|
||||||
set(workflowDiagramState, {
|
|
||||||
nodes: [
|
return (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={({ set }) => {
|
||||||
|
set(
|
||||||
|
workflowDiagramComponentState.atomFamily({
|
||||||
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
id: 'trigger-1',
|
nodes: [
|
||||||
type: 'default',
|
{
|
||||||
position: { x: 100, y: 100 },
|
id: 'trigger-1',
|
||||||
data: {
|
type: 'default',
|
||||||
nodeType: 'trigger',
|
position: { x: 100, y: 100 },
|
||||||
triggerType: 'DATABASE_EVENT',
|
data: {
|
||||||
name: 'When record is created',
|
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 },
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
data: {
|
value={{
|
||||||
nodeType: 'action',
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
actionType: 'CREATE_RECORD',
|
}}
|
||||||
name: 'Create record',
|
>
|
||||||
},
|
<StyledContainer>
|
||||||
},
|
<Story />
|
||||||
{
|
</StyledContainer>
|
||||||
id: 'create-step-1',
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
type: 'create-step',
|
</RecoilRoot>
|
||||||
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',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<StyledContainer>
|
|
||||||
<Story />
|
|
||||||
</StyledContainer>
|
|
||||||
</RecoilRoot>
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,49 +141,65 @@ export const SuccessEdge: Story = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => (
|
(Story) => {
|
||||||
<RecoilRoot
|
const workflowVisualizerComponentInstanceId =
|
||||||
initializeState={({ set }) => {
|
'workflow-visualizer-test-id';
|
||||||
set(workflowDiagramState, {
|
|
||||||
nodes: [
|
return (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={({ set }) => {
|
||||||
|
set(
|
||||||
|
workflowDiagramComponentState.atomFamily({
|
||||||
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
id: 'trigger-1',
|
nodes: [
|
||||||
type: 'default',
|
{
|
||||||
position: { x: 100, y: 100 },
|
id: 'trigger-1',
|
||||||
data: {
|
type: 'default',
|
||||||
nodeType: 'trigger',
|
position: { x: 100, y: 100 },
|
||||||
triggerType: 'DATABASE_EVENT',
|
data: {
|
||||||
name: 'When record is created',
|
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 },
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
data: {
|
value={{
|
||||||
nodeType: 'action',
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
actionType: 'CREATE_RECORD',
|
}}
|
||||||
name: 'Create record',
|
>
|
||||||
},
|
<StyledContainer>
|
||||||
},
|
<Story />
|
||||||
],
|
</StyledContainer>
|
||||||
edges: [
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
{
|
</RecoilRoot>
|
||||||
...WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION,
|
);
|
||||||
id: 'edge-1',
|
},
|
||||||
source: 'trigger-1',
|
|
||||||
target: 'action-1',
|
|
||||||
type: 'success',
|
|
||||||
label: '1 item',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<StyledContainer>
|
|
||||||
<Story />
|
|
||||||
</StyledContainer>
|
|
||||||
</RecoilRoot>
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
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 { act, renderHook } from '@testing-library/react';
|
||||||
import { useReactFlow } from '@xyflow/react';
|
import { useReactFlow } from '@xyflow/react';
|
||||||
import { RecoilRoot, useRecoilState } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
jest.mock('@xyflow/react', () => ({
|
jest.mock('@xyflow/react', () => ({
|
||||||
useReactFlow: jest.fn(),
|
useReactFlow: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
<RecoilRoot>{children}</RecoilRoot>
|
<RecoilRoot>
|
||||||
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: 'test-instance-id',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('useTriggerNodeSelection', () => {
|
describe('useTriggerNodeSelection', () => {
|
||||||
@ -31,7 +41,9 @@ describe('useTriggerNodeSelection', () => {
|
|||||||
const [
|
const [
|
||||||
workflowDiagramTriggerNodeSelection,
|
workflowDiagramTriggerNodeSelection,
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
setWorkflowDiagramTriggerNodeSelection,
|
||||||
] = useRecoilState(workflowDiagramTriggerNodeSelectionState);
|
] = useRecoilComponentStateV2(
|
||||||
|
workflowDiagramTriggerNodeSelectionComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
useTriggerNodeSelection();
|
useTriggerNodeSelection();
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { workflowDiagramStatusState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusState';
|
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||||
import { workflowRunStepToOpenByDefaultState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
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 { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
@ -17,6 +19,21 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
|||||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
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(
|
const handleWorkflowRunDiagramCanvasInit = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
() => {
|
() => {
|
||||||
@ -43,8 +60,11 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (isDefined(workflowStepToOpenByDefault)) {
|
if (isDefined(workflowStepToOpenByDefault)) {
|
||||||
const workflowId = getSnapshotValue(snapshot, workflowIdState);
|
const workflowVisualizerWorkflowId = getSnapshotValue(
|
||||||
if (!isDefined(workflowId)) {
|
snapshot,
|
||||||
|
workflowVisualizerWorkflowIdState,
|
||||||
|
);
|
||||||
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
|
'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);
|
set(workflowSelectedNodeState, workflowStepToOpenByDefault.id);
|
||||||
|
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
workflowId,
|
workflowId: workflowVisualizerWorkflowId,
|
||||||
|
workflowRunId,
|
||||||
title: workflowStepToOpenByDefault.data.name,
|
title: workflowStepToOpenByDefault.data.name,
|
||||||
icon: getIcon(
|
icon: getIcon(
|
||||||
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
|
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
|
||||||
@ -65,7 +86,16 @@ export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
|||||||
set(workflowRunStepToOpenByDefaultState, undefined);
|
set(workflowRunStepToOpenByDefaultState, undefined);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[getIcon, isInRightDrawer, openWorkflowRunViewStepInCommandMenu],
|
[
|
||||||
|
workflowDiagramStatusState,
|
||||||
|
isInRightDrawer,
|
||||||
|
workflowRunStepToOpenByDefaultState,
|
||||||
|
workflowVisualizerWorkflowIdState,
|
||||||
|
workflowSelectedNodeState,
|
||||||
|
openWorkflowRunViewStepInCommandMenu,
|
||||||
|
workflowRunId,
|
||||||
|
getIcon,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
|
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';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useStartNodeCreation = () => {
|
export const useStartNodeCreation = () => {
|
||||||
const setWorkflowCreateStepFromParentStepId = useSetRecoilState(
|
const setWorkflowCreateStepFromParentStepId = useSetRecoilComponentStateV2(
|
||||||
workflowCreateStepFromParentStepIdState,
|
workflowCreateStepFromParentStepIdComponentState,
|
||||||
);
|
);
|
||||||
const { openStepSelectInCommandMenu } = useWorkflowCommandMenu();
|
const { openStepSelectInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used in a context where dependencies shouldn't change much.
|
* This function is used in a context where dependencies shouldn't change much.
|
||||||
@ -22,14 +25,14 @@ export const useStartNodeCreation = () => {
|
|||||||
(parentNodeId: string) => {
|
(parentNodeId: string) => {
|
||||||
setWorkflowCreateStepFromParentStepId(parentNodeId);
|
setWorkflowCreateStepFromParentStepId(parentNodeId);
|
||||||
|
|
||||||
if (isDefined(workflowId)) {
|
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||||
openStepSelectInCommandMenu(workflowId);
|
openStepSelectInCommandMenu(workflowVisualizerWorkflowId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
setWorkflowCreateStepFromParentStepId,
|
setWorkflowCreateStepFromParentStepId,
|
||||||
workflowId,
|
workflowVisualizerWorkflowId,
|
||||||
openStepSelectInCommandMenu,
|
openStepSelectInCommandMenu,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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 {
|
import {
|
||||||
WorkflowDiagramEdge,
|
WorkflowDiagramEdge,
|
||||||
WorkflowDiagramNode,
|
WorkflowDiagramNode,
|
||||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { useReactFlow } from '@xyflow/react';
|
import { useReactFlow } from '@xyflow/react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useTriggerNodeSelection = () => {
|
export const useTriggerNodeSelection = () => {
|
||||||
@ -14,7 +14,9 @@ export const useTriggerNodeSelection = () => {
|
|||||||
const [
|
const [
|
||||||
workflowDiagramTriggerNodeSelection,
|
workflowDiagramTriggerNodeSelection,
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
setWorkflowDiagramTriggerNodeSelection,
|
||||||
] = useRecoilState(workflowDiagramTriggerNodeSelectionState);
|
] = useRecoilComponentStateV2(
|
||||||
|
workflowDiagramTriggerNodeSelectionComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDefined(workflowDiagramTriggerNodeSelection)) {
|
if (!isDefined(workflowDiagramTriggerNodeSelection)) {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useWorkflowSelectedNodeOrThrow = () => {
|
export const useWorkflowSelectedNodeOrThrow = () => {
|
||||||
const workflowSelectedNode = useRecoilValue(workflowSelectedNodeState);
|
const workflowSelectedNode = useRecoilComponentValueV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
if (!isDefined(workflowSelectedNode)) {
|
if (!isDefined(workflowSelectedNode)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
|
||||||
|
|
||||||
|
export const WorkflowRunVisualizerComponentInstanceContext =
|
||||||
|
createComponentInstanceContext({
|
||||||
|
instanceId: '',
|
||||||
|
});
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
|
||||||
|
|
||||||
|
export const WorkflowVisualizerComponentInstanceContext =
|
||||||
|
createComponentInstanceContext({
|
||||||
|
instanceId: '',
|
||||||
|
});
|
||||||
@ -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,
|
||||||
|
});
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { WorkflowDiagram } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
|
|
||||||
export const workflowDiagramState = createState<WorkflowDiagram | undefined>({
|
|
||||||
key: 'workflowDiagramState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -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<WorkflowDiagramStatus>({
|
||||||
|
key: 'workflowDiagramStatusComponentState',
|
||||||
|
defaultValue: 'computing-diagram',
|
||||||
|
componentInstanceContext: WorkflowRunVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
|
|
||||||
export const workflowDiagramStatusState = createState<
|
|
||||||
'computing-diagram' | 'computing-dimensions' | 'done'
|
|
||||||
>({
|
|
||||||
key: 'workflowDiagramStatusState',
|
|
||||||
defaultValue: 'computing-diagram',
|
|
||||||
});
|
|
||||||
@ -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<string | undefined>({
|
||||||
|
key: 'workflowDiagramTriggerNodeSelectionComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
export const workflowDiagramTriggerNodeSelectionState = createState<
|
|
||||||
string | undefined
|
|
||||||
>({
|
|
||||||
key: 'workflowDiagramTriggerNodeSelectionState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { RefObject } from 'react';
|
|
||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
|
|
||||||
export const workflowReactFlowRefState =
|
|
||||||
createState<RefObject<HTMLDivElement> | null>({
|
|
||||||
key: 'workflowReactFlowRefState',
|
|
||||||
defaultValue: null,
|
|
||||||
});
|
|
||||||
@ -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,
|
||||||
|
});
|
||||||
@ -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,
|
|
||||||
});
|
|
||||||
@ -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,
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
|
|
||||||
export const workflowSelectedNodeState = createState<string | undefined>({
|
|
||||||
key: 'workflowSelectedNodeState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
export type WorkflowDiagramStatus =
|
||||||
|
| 'computing-diagram'
|
||||||
|
| 'computing-dimensions'
|
||||||
|
| 'done';
|
||||||
@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -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 (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={({ set }) => {
|
||||||
|
set(
|
||||||
|
workflowCreateStepFromParentStepIdComponentState.atomFamily({
|
||||||
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
|
}),
|
||||||
|
'parent-step-id',
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
|
value={{
|
||||||
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
|
</RecoilRoot>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -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 { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
|
||||||
import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
|
import { workflowLastCreatedStepIdComponentState } from '@/workflow/states/workflowLastCreatedStepIdComponentState';
|
||||||
import {
|
import {
|
||||||
WorkflowStepType,
|
WorkflowStepType,
|
||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
} from '@/workflow/types/Workflow';
|
} 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 { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
|
||||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
|
import { workflowCreateStepFromParentStepIdComponentState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdComponentState';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useCreateStep = ({
|
export const useCreateStep = ({
|
||||||
@ -16,13 +17,15 @@ export const useCreateStep = ({
|
|||||||
workflow: WorkflowWithCurrentVersion;
|
workflow: WorkflowWithCurrentVersion;
|
||||||
}) => {
|
}) => {
|
||||||
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
|
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||||
const setWorkflowLastCreatedStepId = useSetRecoilState(
|
workflowSelectedNodeComponentState,
|
||||||
workflowLastCreatedStepIdState,
|
);
|
||||||
|
const setWorkflowLastCreatedStepId = useSetRecoilComponentStateV2(
|
||||||
|
workflowLastCreatedStepIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const workflowCreateStepFromParentStepId = useRecoilValue(
|
const workflowCreateStepFromParentStepId = useRecoilComponentValueV2(
|
||||||
workflowCreateStepFromParentStepIdState,
|
workflowCreateStepFromParentStepIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
||||||
|
|||||||
@ -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<string | undefined>({
|
||||||
|
key: 'workflowCreateStepFromParentStepIdComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
export const workflowCreateStepFromParentStepIdState = createState<
|
|
||||||
string | undefined
|
|
||||||
>({
|
|
||||||
key: 'workflowCreateStepFromParentStepId',
|
|
||||||
defaultValue: undefined,
|
|
||||||
});
|
|
||||||
@ -3,7 +3,7 @@ import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-func
|
|||||||
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
|
import { useUpdateOneServerlessFunction } from '@/settings/serverless-functions/hooks/useUpdateOneServerlessFunction';
|
||||||
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
|
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
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 { WorkflowCodeAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/setNestedValue';
|
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 { editor } from 'monaco-editor';
|
||||||
import { AutoTypings } from 'monaco-editor-auto-typings';
|
import { AutoTypings } from 'monaco-editor-auto-typings';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { CodeEditor } from 'twenty-ui/input';
|
|
||||||
import { IconCode, IconPlayerPlay, useIcons } from 'twenty-ui/display';
|
import { IconCode, IconPlayerPlay, useIcons } from 'twenty-ui/display';
|
||||||
|
import { CodeEditor } from 'twenty-ui/input';
|
||||||
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
|
||||||
const StyledCodeEditorContainer = styled.div`
|
const StyledCodeEditorContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -82,8 +82,10 @@ export const WorkflowEditActionServerlessFunction = ({
|
|||||||
useUpdateOneServerlessFunction(serverlessFunctionId);
|
useUpdateOneServerlessFunction(serverlessFunctionId);
|
||||||
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
||||||
|
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
const workflow = useWorkflowWithCurrentVersion(workflowId);
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
|
||||||
const { availablePackages } = useGetAvailablePackages({
|
const { availablePackages } = useGetAvailablePackages({
|
||||||
id: serverlessFunctionId,
|
id: serverlessFunctionId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import { FormTextFieldInput } from '@/object-record/record-field/form-types/comp
|
|||||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
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 { WorkflowSendEmailAction } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
@ -20,11 +21,11 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
||||||
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
|
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 { JsonValue } from 'type-fest';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
import { IconPlus, useIcons } from 'twenty-ui/display';
|
|
||||||
import { SelectOption } from 'twenty-ui/input';
|
|
||||||
|
|
||||||
type WorkflowEditActionSendEmailProps = {
|
type WorkflowEditActionSendEmailProps = {
|
||||||
action: WorkflowSendEmailAction;
|
action: WorkflowSendEmailAction;
|
||||||
@ -53,8 +54,10 @@ export const WorkflowEditActionSendEmail = ({
|
|||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||||
|
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
const redirectUrl = `/object/workflow/${workflowId}`;
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const redirectUrl = `/object/workflow/${workflowVisualizerWorkflowId}`;
|
||||||
|
|
||||||
const [formData, setFormData] = useState<SendEmailFormData>({
|
const [formData, setFormData] = useState<SendEmailFormData>({
|
||||||
connectedAccountId: action.settings.input.connectedAccountId,
|
connectedAccountId: action.settings.input.connectedAccountId,
|
||||||
|
|||||||
@ -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 <RightDrawerWorkflowSelectTriggerTypeContent workflow={workflow} />;
|
|
||||||
};
|
|
||||||
@ -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 (
|
|
||||||
<RightDrawerStepListContainer>
|
|
||||||
<RightDrawerWorkflowSelectStepTitle>
|
|
||||||
Data
|
|
||||||
</RightDrawerWorkflowSelectStepTitle>
|
|
||||||
{DATABASE_TRIGGER_TYPES.map((action) => (
|
|
||||||
<MenuItemCommand
|
|
||||||
key={action.defaultLabel}
|
|
||||||
LeftIcon={getIcon(action.icon)}
|
|
||||||
text={action.defaultLabel}
|
|
||||||
onClick={handleTriggerTypeClick(action)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
<RightDrawerWorkflowSelectStepTitle>
|
|
||||||
Others
|
|
||||||
</RightDrawerWorkflowSelectStepTitle>
|
|
||||||
{OTHER_TRIGGER_TYPES.map((action) => (
|
|
||||||
<MenuItemCommand
|
|
||||||
key={action.defaultLabel}
|
|
||||||
LeftIcon={getIcon(action.icon)}
|
|
||||||
text={action.defaultLabel}
|
|
||||||
onClick={handleTriggerTypeClick(action)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</RightDrawerStepListContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -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 { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
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 { WorkflowWebhookTrigger } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
@ -54,7 +55,9 @@ export const WorkflowEditTriggerWebhookForm = ({
|
|||||||
const [errorMessages, setErrorMessages] = useState<FormErrorMessages>({});
|
const [errorMessages, setErrorMessages] = useState<FormErrorMessages>({});
|
||||||
const [errorMessagesVisible, setErrorMessagesVisible] = useState(false);
|
const [errorMessagesVisible, setErrorMessagesVisible] = useState(false);
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const workflowId = useRecoilValue(workflowIdState);
|
const workflowVisualizerWorkflowId = useRecoilComponentValueV2(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|
||||||
const onBlur = () => {
|
const onBlur = () => {
|
||||||
@ -66,7 +69,7 @@ export const WorkflowEditTriggerWebhookForm = ({
|
|||||||
const headerIcon = getTriggerIcon(trigger);
|
const headerIcon = getTriggerIcon(trigger);
|
||||||
const headerType = getTriggerHeaderType(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 displayWebhookUrl = webhookUrl.replace(/^(https?:\/\/)?(www\.)?/, '');
|
||||||
|
|
||||||
const copyToClipboard = async () => {
|
const copyToClipboard = async () => {
|
||||||
|
|||||||
@ -13,13 +13,12 @@ import { isRecordOutputSchema } from '@/workflow/workflow-variables/utils/isReco
|
|||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
|
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionState';
|
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
|
import { getCurrentSubStepFromPath } from '@/workflow/workflow-variables/utils/getCurrentSubStepFromPath';
|
||||||
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
|
import { getStepHeaderLabel } from '@/workflow/workflow-variables/utils/getStepHeaderLabel';
|
||||||
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
|
import { isLinkOutputSchema } from '@/workflow/workflow-variables/utils/isLinkOutputSchema';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import {
|
import {
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
@ -42,13 +41,15 @@ export const WorkflowVariablesDropdownFieldItems = ({
|
|||||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||||
const [searchInputValue, setSearchInputValue] = useState('');
|
const [searchInputValue, setSearchInputValue] = useState('');
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilComponentStateV2(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
'workflow-serverless-function-tab-list-component-id',
|
'workflow-serverless-function-tab-list-component-id',
|
||||||
);
|
);
|
||||||
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilState(
|
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilComponentStateV2(
|
||||||
workflowDiagramTriggerNodeSelectionState,
|
workflowDiagramTriggerNodeSelectionComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const getDisplayedSubStepFields = () => {
|
const getDisplayedSubStepFields = () => {
|
||||||
|
|||||||
@ -1,52 +1,75 @@
|
|||||||
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema';
|
||||||
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext';
|
||||||
import { flowState } from '@/workflow/states/flowState';
|
import { flowComponentState } from '@/workflow/states/flowComponentState';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { WorkflowVersion } from '@/workflow/types/Workflow';
|
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 { Decorator } from '@storybook/react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import {
|
import {
|
||||||
getWorkflowMock,
|
getWorkflowMock,
|
||||||
getWorkflowNodeIdMock,
|
getWorkflowNodeIdMock,
|
||||||
} from '~/testing/mock-data/workflow';
|
} from '~/testing/mock-data/workflow';
|
||||||
|
|
||||||
export const WorkflowStepDecorator: Decorator = (Story) => {
|
export const WorkflowStepDecorator: Decorator = (Story) => {
|
||||||
const setWorkflowId = useSetRecoilState(workflowIdState);
|
const workflowVisualizerComponentInstanceId = 'workflow-visualizer-test-id';
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
|
||||||
const setFlow = useSetRecoilState(flowState);
|
|
||||||
const workflowVersion = getWorkflowMock().versions.edges[0]
|
const workflowVersion = getWorkflowMock().versions.edges[0]
|
||||||
.node as WorkflowVersion;
|
.node as WorkflowVersion;
|
||||||
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
const { populateStepsOutputSchema } = useStepsOutputSchema();
|
||||||
const [ready, setReady] = useState(false);
|
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(() => {
|
useEffect(() => {
|
||||||
setWorkflowId(getWorkflowMock().id);
|
handleMount();
|
||||||
setWorkflowSelectedNode(getWorkflowNodeIdMock());
|
}, [handleMount]);
|
||||||
setFlow({
|
|
||||||
workflowVersionId: workflowVersion.id,
|
|
||||||
trigger: workflowVersion.trigger,
|
|
||||||
steps: workflowVersion.steps,
|
|
||||||
});
|
|
||||||
populateStepsOutputSchema(workflowVersion);
|
|
||||||
setReady(true);
|
|
||||||
}, [
|
|
||||||
setWorkflowId,
|
|
||||||
setWorkflowSelectedNode,
|
|
||||||
populateStepsOutputSchema,
|
|
||||||
workflowVersion,
|
|
||||||
setFlow,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowStepContextProvider
|
<WorkflowVisualizerComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
workflowVersionId: workflowVersion.id,
|
instanceId: workflowVisualizerComponentInstanceId,
|
||||||
workflowRunId: '123',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{ready && <Story />}
|
<WorkflowStepContextProvider
|
||||||
</WorkflowStepContextProvider>
|
value={{
|
||||||
|
workflowVersionId: workflowVersion.id,
|
||||||
|
workflowRunId: '123',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ready && <Story />}
|
||||||
|
</WorkflowStepContextProvider>
|
||||||
|
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user