Replace useOnSelectionChange with onClick listeners for steps opening (#13672)
This PR cleans a few parts of the workflow features and fixes a few improper behaviors. Here is a non-exaustive list of improved things: - Clicking on an action will always reset the command menu's navigation stack. Previously, the behavior wasn't unified between workflows, workflow versions and workflow runs. - Opening a step in the side panel is now down in the `onClick` event handler put on individual Reactflow nodes. This makes interoperability between filters (which are buttons on edges) and traditional actions. - Simplified the code that automatically opens pending forms in the side panel. This feature should now work more predictably. - Splitted the `WorkflowDiagramEmptyTrigger` component into `WorkflowDiagramEmptyTriggerEditable` and `WorkflowDiagramEmptyTriggerReadonly`. This makes handling events easier as the behavior isn't the same in both cases. - Dropped all `useOnSelectionChange` hooks that were used to open steps in the side panel upon user selection. - Created a specific `WorkflowRunDiagramStepNode` instead of using `WorkflowDiagramStepNodeReadonly` in `WorkflowRunDiagramCanvas` - Deleted `useHandleWorkflowRunDiagramCanvasInit` as it was used to open the initially selected step in the command menu, which is now handled in an effect that works for all cases, including workflow run's state refreshing. Closes https://github.com/twentyhq/core-team-issues/issues/1227 Closes https://github.com/twentyhq/twenty/issues/11923
This commit is contained in:
committed by
GitHub
parent
787f8b75ab
commit
b8cd4491c2
+36
-1
@@ -1,4 +1,8 @@
|
|||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import {
|
import {
|
||||||
WorkflowActionType,
|
WorkflowActionType,
|
||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
@@ -10,6 +14,9 @@ import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
|||||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||||
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
|
import { RECORD_ACTIONS } from '@/workflow/workflow-steps/workflow-actions/constants/RecordActions';
|
||||||
import { useFilteredOtherActions } from '@/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions';
|
import { useFilteredOtherActions } from '@/workflow/workflow-steps/workflow-actions/hooks/useFilteredOtherActions';
|
||||||
|
import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
import { MenuItemCommand } from 'twenty-ui/navigation';
|
import { MenuItemCommand } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
@@ -30,22 +37,50 @@ export const CommandMenuWorkflowSelectActionContent = ({
|
|||||||
const [workflowInsertStepIds, setWorkflowInsertStepIds] =
|
const [workflowInsertStepIds, setWorkflowInsertStepIds] =
|
||||||
useRecoilComponentState(workflowInsertStepIdsComponentState);
|
useRecoilComponentState(workflowInsertStepIdsComponentState);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
const handleCreateStep = async (actionType: WorkflowActionType) => {
|
const handleCreateStep = async (actionType: WorkflowActionType) => {
|
||||||
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
|
throw new Error(
|
||||||
|
'Workflow ID must be configured for the edge when creating a step',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const { parentStepId, nextStepId, position } = workflowInsertStepIds;
|
const { parentStepId, nextStepId, position } = workflowInsertStepIds;
|
||||||
|
|
||||||
await createStep({
|
const createdStep = await createStep({
|
||||||
newStepType: actionType,
|
newStepType: actionType,
|
||||||
parentStepId,
|
parentStepId,
|
||||||
nextStepId,
|
nextStepId,
|
||||||
position,
|
position,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!isDefined(createdStep)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setWorkflowInsertStepIds({
|
setWorkflowInsertStepIds({
|
||||||
parentStepId: undefined,
|
parentStepId: undefined,
|
||||||
nextStepId: undefined,
|
nextStepId: undefined,
|
||||||
position: undefined,
|
position: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
closeRightClickMenu();
|
closeRightClickMenu();
|
||||||
|
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
|
||||||
|
openWorkflowEditStepInCommandMenu(
|
||||||
|
workflowVisualizerWorkflowId,
|
||||||
|
createdStep.name,
|
||||||
|
getIcon(getActionIcon(createdStep.type as WorkflowActionType)),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+7
-1
@@ -112,7 +112,13 @@ export const useRunWorkflowRunOpeningInCommandMenuSideEffects = () => {
|
|||||||
recordId,
|
recordId,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
(steps) => [...steps, stepToOpenByDefault.id],
|
(steps) => [
|
||||||
|
...steps,
|
||||||
|
{
|
||||||
|
stepId: stepToOpenByDefault.id,
|
||||||
|
isInRightDrawer: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
);
|
);
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
workflowId: workflowRunRecord.workflowId,
|
workflowId: workflowRunRecord.workflowId,
|
||||||
|
|||||||
+3
-3
@@ -4,7 +4,7 @@ import { WorkflowDiagramBlankEdge } from '@/workflow/workflow-diagram/components
|
|||||||
import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase';
|
import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase';
|
||||||
import { WorkflowDiagramCanvasEditableEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect';
|
import { WorkflowDiagramCanvasEditableEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect';
|
||||||
import { WorkflowDiagramDefaultEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable';
|
import { WorkflowDiagramDefaultEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeEditable';
|
||||||
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
import { WorkflowDiagramEmptyTriggerEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTriggerEditable';
|
||||||
import { WorkflowDiagramFilterEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable';
|
import { WorkflowDiagramFilterEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeEditable';
|
||||||
import { WorkflowDiagramFilteringDisabledEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeEditable';
|
import { WorkflowDiagramFilteringDisabledEdgeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeEditable';
|
||||||
import { WorkflowDiagramStepNodeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable';
|
import { WorkflowDiagramStepNodeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable';
|
||||||
@@ -19,7 +19,7 @@ import { useCreateEdge } from '@/workflow/workflow-steps/hooks/useCreateEdge';
|
|||||||
import { useDeleteEdge } from '@/workflow/workflow-steps/hooks/useDeleteEdge';
|
import { useDeleteEdge } from '@/workflow/workflow-steps/hooks/useDeleteEdge';
|
||||||
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
import { useUpdateStep } from '@/workflow/workflow-steps/hooks/useUpdateStep';
|
||||||
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger';
|
||||||
import { Connection, ReactFlowProvider, addEdge } from '@xyflow/react';
|
import { addEdge, Connection, ReactFlowProvider } from '@xyflow/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ export const WorkflowDiagramCanvasEditable = ({
|
|||||||
<WorkflowDiagramCanvasBase
|
<WorkflowDiagramCanvasBase
|
||||||
nodeTypes={{
|
nodeTypes={{
|
||||||
default: WorkflowDiagramStepNodeEditable,
|
default: WorkflowDiagramStepNodeEditable,
|
||||||
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
'empty-trigger': WorkflowDiagramEmptyTriggerEditable,
|
||||||
}}
|
}}
|
||||||
edgeTypes={{
|
edgeTypes={{
|
||||||
blank: WorkflowDiagramBlankEdge,
|
blank: WorkflowDiagramBlankEdge,
|
||||||
|
|||||||
+4
-100
@@ -1,103 +1,17 @@
|
|||||||
import { useCallback, useContext } from 'react';
|
|
||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
|
||||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
|
||||||
|
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
|
||||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
|
||||||
import { EMPTY_TRIGGER_STEP_ID } from '@/workflow/workflow-diagram/constants/EmptyTriggerStepId';
|
|
||||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
|
||||||
import {
|
|
||||||
WorkflowDiagramNode,
|
|
||||||
WorkflowDiagramStepNodeData,
|
|
||||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
|
||||||
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { useIcons } from 'twenty-ui/display';
|
|
||||||
import { useEdgeSelected } from '@/workflow/workflow-diagram/hooks/useEdgeSelected';
|
import { useEdgeSelected } from '@/workflow/workflow-diagram/hooks/useEdgeSelected';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const WorkflowDiagramCanvasEditableEffect = () => {
|
export const WorkflowDiagramCanvasEditableEffect = () => {
|
||||||
const { getIcon } = useIcons();
|
|
||||||
|
|
||||||
const {
|
|
||||||
openWorkflowTriggerTypeInCommandMenu,
|
|
||||||
openWorkflowEditStepInCommandMenu,
|
|
||||||
} = useWorkflowCommandMenu();
|
|
||||||
|
|
||||||
const { setEdgeSelected, clearEdgeSelection } = useEdgeSelected();
|
const { setEdgeSelected, clearEdgeSelection } = useEdgeSelected();
|
||||||
|
|
||||||
const isWorkflowBranchEnabled = useIsFeatureEnabled(
|
const isWorkflowBranchEnabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IS_WORKFLOW_BRANCH_ENABLED,
|
FeatureFlagKey.IS_WORKFLOW_BRANCH_ENABLED,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
|
||||||
workflowSelectedNodeComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
|
||||||
commandMenuNavigationStackState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
|
||||||
|
|
||||||
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
|
||||||
workflowVisualizerWorkflowIdComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectedNodes = useCallback(
|
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
|
||||||
const selectedNode = nodes[0] as WorkflowDiagramNode | undefined;
|
|
||||||
|
|
||||||
if (!isInRightDrawer) {
|
|
||||||
setCommandMenuNavigationStack([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefined(selectedNode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID;
|
|
||||||
if (isEmptyTriggerNode) {
|
|
||||||
if (isDefined(workflowVisualizerWorkflowId)) {
|
|
||||||
openWorkflowTriggerTypeInCommandMenu(workflowVisualizerWorkflowId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
|
|
||||||
|
|
||||||
setWorkflowSelectedNode(selectedNode.id);
|
|
||||||
|
|
||||||
if (isDefined(workflowVisualizerWorkflowId)) {
|
|
||||||
openWorkflowEditStepInCommandMenu(
|
|
||||||
workflowVisualizerWorkflowId,
|
|
||||||
selectedNodeData.name,
|
|
||||||
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
isInRightDrawer,
|
|
||||||
setCommandMenuNavigationStack,
|
|
||||||
workflowVisualizerWorkflowId,
|
|
||||||
openWorkflowTriggerTypeInCommandMenu,
|
|
||||||
openWorkflowEditStepInCommandMenu,
|
|
||||||
getIcon,
|
|
||||||
setWorkflowSelectedNode,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectedEdges = useCallback(
|
const handleSelectedEdges = useCallback(
|
||||||
({ edges }: OnSelectionChangeParams) => {
|
({ edges }: OnSelectionChangeParams) => {
|
||||||
if (!isWorkflowBranchEnabled) {
|
if (!isWorkflowBranchEnabled) {
|
||||||
@@ -119,19 +33,9 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
[isWorkflowBranchEnabled, setEdgeSelected, clearEdgeSelection],
|
[isWorkflowBranchEnabled, setEdgeSelected, clearEdgeSelection],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSelectionChange = useCallback(
|
|
||||||
(onSelectionChangeParams: OnSelectionChangeParams) => {
|
|
||||||
handleSelectedNodes(onSelectionChangeParams);
|
|
||||||
handleSelectedEdges(onSelectionChangeParams);
|
|
||||||
},
|
|
||||||
[handleSelectedNodes, handleSelectedEdges],
|
|
||||||
);
|
|
||||||
|
|
||||||
useOnSelectionChange({
|
useOnSelectionChange({
|
||||||
onChange: handleSelectionChange,
|
onChange: handleSelectedEdges,
|
||||||
});
|
});
|
||||||
|
|
||||||
useTriggerNodeSelection();
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-5
@@ -1,8 +1,7 @@
|
|||||||
import { WorkflowVersionStatus } from '@/workflow/types/Workflow';
|
import { WorkflowVersionStatus } from '@/workflow/types/Workflow';
|
||||||
import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase';
|
import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasBase';
|
||||||
import { WorkflowDiagramCanvasReadonlyEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect';
|
|
||||||
import { WorkflowDiagramDefaultEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeReadonly';
|
import { WorkflowDiagramDefaultEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeReadonly';
|
||||||
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
import { WorkflowDiagramEmptyTriggerReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTriggerReadonly';
|
||||||
import { WorkflowDiagramFilterEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeReadonly';
|
import { WorkflowDiagramFilterEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeReadonly';
|
||||||
import { WorkflowDiagramFilteringDisabledEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeReadonly';
|
import { WorkflowDiagramFilteringDisabledEdgeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeReadonly';
|
||||||
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
||||||
@@ -23,7 +22,7 @@ export const WorkflowDiagramCanvasReadonly = ({
|
|||||||
<WorkflowDiagramCanvasBase
|
<WorkflowDiagramCanvasBase
|
||||||
nodeTypes={{
|
nodeTypes={{
|
||||||
default: WorkflowDiagramStepNodeReadonly,
|
default: WorkflowDiagramStepNodeReadonly,
|
||||||
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
'empty-trigger': WorkflowDiagramEmptyTriggerReadonly,
|
||||||
}}
|
}}
|
||||||
edgeTypes={{
|
edgeTypes={{
|
||||||
'filtering-disabled--readonly':
|
'filtering-disabled--readonly':
|
||||||
@@ -35,8 +34,6 @@ export const WorkflowDiagramCanvasReadonly = ({
|
|||||||
tagColor={tagProps.color}
|
tagColor={tagProps.color}
|
||||||
tagText={tagProps.text}
|
tagText={tagProps.text}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<WorkflowDiagramCanvasReadonlyEffect />
|
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
-76
@@ -1,76 +0,0 @@
|
|||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
|
||||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
|
||||||
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
|
||||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
|
||||||
import {
|
|
||||||
WorkflowDiagramNode,
|
|
||||||
WorkflowDiagramStepNodeData,
|
|
||||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
|
||||||
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { useIcons } from 'twenty-ui/display';
|
|
||||||
|
|
||||||
export const WorkflowDiagramCanvasReadonlyEffect = () => {
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
|
||||||
workflowSelectedNodeComponentState,
|
|
||||||
);
|
|
||||||
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
|
||||||
|
|
||||||
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
|
||||||
workflowVisualizerWorkflowIdComponentState,
|
|
||||||
);
|
|
||||||
const workflowVisualizerWorkflowVersionId = useRecoilComponentValue(
|
|
||||||
workflowVisualizerWorkflowVersionIdComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectionChange = useCallback(
|
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
isDefined(workflowVisualizerWorkflowId) &&
|
|
||||||
isDefined(workflowVisualizerWorkflowVersionId)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedNode = nodes[0] as WorkflowDiagramNode | undefined;
|
|
||||||
|
|
||||||
if (!isDefined(selectedNode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setWorkflowSelectedNode(selectedNode.id);
|
|
||||||
|
|
||||||
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
|
|
||||||
|
|
||||||
openWorkflowViewStepInCommandMenu({
|
|
||||||
workflowId: workflowVisualizerWorkflowId,
|
|
||||||
workflowVersionId: workflowVisualizerWorkflowVersionId,
|
|
||||||
title: selectedNodeData.name,
|
|
||||||
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[
|
|
||||||
setWorkflowSelectedNode,
|
|
||||||
openWorkflowViewStepInCommandMenu,
|
|
||||||
workflowVisualizerWorkflowId,
|
|
||||||
workflowVisualizerWorkflowVersionId,
|
|
||||||
getIcon,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
useOnSelectionChange({
|
|
||||||
onChange: handleSelectionChange,
|
|
||||||
});
|
|
||||||
|
|
||||||
useTriggerNodeSelection();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
+17
-3
@@ -1,19 +1,23 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseEdge';
|
||||||
|
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeButtonGroup';
|
||||||
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
||||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||||
|
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
|
||||||
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
|
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
|
||||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||||
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
import { useCreateStep } from '@/workflow/workflow-steps/hooks/useCreateStep';
|
||||||
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
|
|
||||||
import { EdgeLabelRenderer, EdgeProps, getBezierPath } from '@xyflow/react';
|
import { EdgeLabelRenderer, EdgeProps, getBezierPath } from '@xyflow/react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconFilter, IconPlus } from 'twenty-ui/display';
|
import { IconFilter, IconPlus } from 'twenty-ui/display';
|
||||||
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseEdge';
|
|
||||||
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeButtonGroup';
|
|
||||||
|
|
||||||
type WorkflowDiagramDefaultEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
type WorkflowDiagramDefaultEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
||||||
|
|
||||||
@@ -28,6 +32,8 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
|
|||||||
markerStart,
|
markerStart,
|
||||||
markerEnd,
|
markerEnd,
|
||||||
}: WorkflowDiagramDefaultEdgeEditableProps) => {
|
}: WorkflowDiagramDefaultEdgeEditableProps) => {
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
const { isEdgeHovered } = useEdgeHovered();
|
const { isEdgeHovered } = useEdgeHovered();
|
||||||
|
|
||||||
const [edgePath, labelX, labelY] = getBezierPath({
|
const [edgePath, labelX, labelY] = getBezierPath({
|
||||||
@@ -51,6 +57,10 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
|
|||||||
nextStepId: target,
|
nextStepId: target,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
const { openWorkflowEditFilterInCommandMenu } =
|
const { openWorkflowEditFilterInCommandMenu } =
|
||||||
useOpenWorkflowEditFilterInCommandMenu();
|
useOpenWorkflowEditFilterInCommandMenu();
|
||||||
|
|
||||||
@@ -65,6 +75,10 @@ export const WorkflowDiagramDefaultEdgeEditable = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
openWorkflowEditFilterInCommandMenu({
|
openWorkflowEditFilterInCommandMenu({
|
||||||
stepId: createdStep.id,
|
stepId: createdStep.id,
|
||||||
stepName: createdStep.name,
|
stepName: createdStep.name,
|
||||||
|
|||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
const StyledStepNodeLabelIconContainer = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
background: ${({ theme }) => theme.background.transparent.light};
|
|
||||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: ${({ theme }) => theme.spacing(3)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const WorkflowDiagramEmptyTrigger = () => {
|
|
||||||
return (
|
|
||||||
<WorkflowDiagramStepNodeBase
|
|
||||||
id={'trigger'}
|
|
||||||
name="Add a Trigger"
|
|
||||||
nodeType="trigger"
|
|
||||||
variant="empty"
|
|
||||||
Icon={<StyledStepNodeLabelIconContainer />}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
const StyledStepNodeLabelIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const WorkflowDiagramEmptyTriggerEditable = () => {
|
||||||
|
const { t } = useLingui();
|
||||||
|
|
||||||
|
const { openWorkflowTriggerTypeInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WorkflowDiagramStepNodeBase
|
||||||
|
id="trigger"
|
||||||
|
name={t`Add a Trigger`}
|
||||||
|
nodeType="trigger"
|
||||||
|
variant="empty"
|
||||||
|
Icon={<StyledStepNodeLabelIconContainer />}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
openWorkflowTriggerTypeInCommandMenu(workflowVisualizerWorkflowId);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
||||||
|
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
||||||
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
|
import { TRIGGER_STEP_ID } from '@/workflow/workflow-trigger/constants/TriggerStepId';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
|
const StyledStepNodeLabelIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const WorkflowDiagramEmptyTriggerReadonly = () => {
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
const { t } = useLingui();
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflowVisualizerWorkflowVersionId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowVersionIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WorkflowDiagramStepNodeBase
|
||||||
|
id="trigger"
|
||||||
|
name={t`Add a Trigger`}
|
||||||
|
nodeType="trigger"
|
||||||
|
variant="empty"
|
||||||
|
Icon={<StyledStepNodeLabelIconContainer />}
|
||||||
|
onClick={() => {
|
||||||
|
if (
|
||||||
|
!isDefined(workflowVisualizerWorkflowId) ||
|
||||||
|
!isDefined(workflowVisualizerWorkflowVersionId)
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
'Workflow ID and Version ID must be defined to open the command menu.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorkflowSelectedNode(TRIGGER_STEP_ID);
|
||||||
|
|
||||||
|
openWorkflowViewStepInCommandMenu({
|
||||||
|
workflowId: workflowVisualizerWorkflowId,
|
||||||
|
workflowVersionId: workflowVisualizerWorkflowVersionId,
|
||||||
|
title: t`Add a Trigger`,
|
||||||
|
icon: getIcon(null),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
+16
-3
@@ -1,3 +1,5 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
@@ -9,9 +11,12 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
|||||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseEdge';
|
||||||
|
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeButtonGroup';
|
||||||
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
||||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||||
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
import { WORKFLOW_DIAGRAM_EDGE_OPTIONS_CLICK_OUTSIDE_ID } from '@/workflow/workflow-diagram/constants/WorkflowDiagramEdgeOptionsClickOutsideId';
|
||||||
|
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
|
||||||
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
|
import { useOpenWorkflowEditFilterInCommandMenu } from '@/workflow/workflow-diagram/hooks/useOpenWorkflowEditFilterInCommandMenu';
|
||||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||||
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
|
import { workflowDiagramPanOnDragComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramPanOnDragComponentState';
|
||||||
@@ -26,6 +31,8 @@ import { css } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { EdgeLabelRenderer, EdgeProps, getBezierPath } from '@xyflow/react';
|
import { EdgeLabelRenderer, EdgeProps, getBezierPath } from '@xyflow/react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import {
|
import {
|
||||||
IconDotsVertical,
|
IconDotsVertical,
|
||||||
@@ -35,9 +42,6 @@ import {
|
|||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { IconButtonGroup } from 'twenty-ui/input';
|
import { IconButtonGroup } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
import { useEdgeHovered } from '@/workflow/workflow-diagram/hooks/useEdgeHovered';
|
|
||||||
import { WorkflowDiagramBaseEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseEdge';
|
|
||||||
import { WorkflowDiagramEdgeButtonGroup } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeButtonGroup';
|
|
||||||
|
|
||||||
type WorkflowDiagramFilterEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
type WorkflowDiagramFilterEdgeEditableProps = EdgeProps<WorkflowDiagramEdge>;
|
||||||
|
|
||||||
@@ -94,10 +98,15 @@ export const WorkflowDiagramFilterEdgeEditable = ({
|
|||||||
workflowVisualizerWorkflowIdComponentState,
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
);
|
);
|
||||||
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
|
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
const { deleteStep } = useDeleteStep({ workflow });
|
const { deleteStep } = useDeleteStep({ workflow });
|
||||||
const { startNodeCreation, isNodeCreationStarted } = useStartNodeCreation();
|
const { startNodeCreation, isNodeCreationStarted } = useStartNodeCreation();
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
const { openDropdown } = useOpenDropdown();
|
const { openDropdown } = useOpenDropdown();
|
||||||
const { closeDropdown } = useCloseDropdown();
|
const { closeDropdown } = useCloseDropdown();
|
||||||
|
|
||||||
@@ -130,6 +139,10 @@ export const WorkflowDiagramFilterEdgeEditable = ({
|
|||||||
useOpenWorkflowEditFilterInCommandMenu();
|
useOpenWorkflowEditFilterInCommandMenu();
|
||||||
|
|
||||||
const handleFilterButtonClick = () => {
|
const handleFilterButtonClick = () => {
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
openWorkflowEditFilterInCommandMenu({
|
openWorkflowEditFilterInCommandMenu({
|
||||||
stepId: data.stepId,
|
stepId: data.stepId,
|
||||||
stepName: data.name,
|
stepName: data.name,
|
||||||
|
|||||||
+14
@@ -1,3 +1,5 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
import { WorkflowDiagramEdgeV2Container } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2Container';
|
||||||
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
import { WorkflowDiagramEdgeV2VisibilityContainer } from '@/workflow/workflow-diagram/components/WorkflowDiagramEdgeV2VisibilityContainer';
|
||||||
@@ -18,6 +20,8 @@ import {
|
|||||||
EdgeProps,
|
EdgeProps,
|
||||||
getBezierPath,
|
getBezierPath,
|
||||||
} from '@xyflow/react';
|
} from '@xyflow/react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { IconFilter } from 'twenty-ui/display';
|
import { IconFilter } from 'twenty-ui/display';
|
||||||
import { IconButtonGroup } from 'twenty-ui/input';
|
import { IconButtonGroup } from 'twenty-ui/input';
|
||||||
|
|
||||||
@@ -62,6 +66,8 @@ export const WorkflowDiagramFilterEdgeReadonly = ({
|
|||||||
}: WorkflowDiagramFilterEdgeReadonlyProps) => {
|
}: WorkflowDiagramFilterEdgeReadonlyProps) => {
|
||||||
assertFilterEdgeDataOrThrow(data);
|
assertFilterEdgeDataOrThrow(data);
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const [edgePath, labelX, labelY] = getBezierPath({
|
const [edgePath, labelX, labelY] = getBezierPath({
|
||||||
@@ -81,7 +87,15 @@ export const WorkflowDiagramFilterEdgeReadonly = ({
|
|||||||
const { openWorkflowViewFilterInCommandMenu } =
|
const { openWorkflowViewFilterInCommandMenu } =
|
||||||
useOpenWorkflowViewFilterInCommandMenu();
|
useOpenWorkflowViewFilterInCommandMenu();
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleFilterButtonClick = () => {
|
const handleFilterButtonClick = () => {
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
openWorkflowViewFilterInCommandMenu({
|
openWorkflowViewFilterInCommandMenu({
|
||||||
stepId: data.stepId,
|
stepId: data.stepId,
|
||||||
stepName: data.name,
|
stepName: data.name,
|
||||||
|
|||||||
+3
@@ -150,6 +150,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
RightFloatingElement,
|
RightFloatingElement,
|
||||||
BottomHoverFloatingElement,
|
BottomHoverFloatingElement,
|
||||||
displayHandle = true,
|
displayHandle = true,
|
||||||
|
onClick,
|
||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
onMouseLeave,
|
onMouseLeave,
|
||||||
}: {
|
}: {
|
||||||
@@ -161,6 +162,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
RightFloatingElement?: React.ReactNode;
|
RightFloatingElement?: React.ReactNode;
|
||||||
BottomHoverFloatingElement?: React.ReactNode;
|
BottomHoverFloatingElement?: React.ReactNode;
|
||||||
displayHandle?: boolean;
|
displayHandle?: boolean;
|
||||||
|
onClick?: () => void;
|
||||||
onMouseEnter?: (event: MouseEvent<HTMLDivElement>) => void;
|
onMouseEnter?: (event: MouseEvent<HTMLDivElement>) => void;
|
||||||
onMouseLeave?: (event: MouseEvent<HTMLDivElement>) => void;
|
onMouseLeave?: (event: MouseEvent<HTMLDivElement>) => void;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -172,6 +174,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
<StyledStepNodeContainer
|
<StyledStepNodeContainer
|
||||||
className="workflow-node-container"
|
className="workflow-node-container"
|
||||||
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
data-click-outside-id={WORKFLOW_DIAGRAM_STEP_NODE_BASE_CLICK_OUTSIDE_ID}
|
||||||
|
onClick={onClick}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
>
|
>
|
||||||
|
|||||||
+41
@@ -1,10 +1,20 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
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 { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const WorkflowDiagramStepNodeEditable = ({
|
export const WorkflowDiagramStepNodeEditable = ({
|
||||||
id,
|
id,
|
||||||
@@ -15,6 +25,8 @@ export const WorkflowDiagramStepNodeEditable = ({
|
|||||||
data: WorkflowDiagramStepNodeData;
|
data: WorkflowDiagramStepNodeData;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
workflowVisualizerWorkflowIdComponentState,
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
);
|
);
|
||||||
@@ -28,12 +40,41 @@ export const WorkflowDiagramStepNodeEditable = ({
|
|||||||
workflow: workflowWithCurrentVersion,
|
workflow: workflowWithCurrentVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowDiagramStepNodeEditableContent
|
<WorkflowDiagramStepNodeEditableContent
|
||||||
id={id}
|
id={id}
|
||||||
data={data}
|
data={data}
|
||||||
variant="default"
|
variant="default"
|
||||||
selected={selected ?? false}
|
selected={selected ?? false}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorkflowSelectedNode(id);
|
||||||
|
|
||||||
|
if (isDefined(workflowVisualizerWorkflowId)) {
|
||||||
|
openWorkflowEditStepInCommandMenu(
|
||||||
|
workflowVisualizerWorkflowId,
|
||||||
|
data.name,
|
||||||
|
getIcon(getWorkflowNodeIconKey(data)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
deleteStep(id);
|
deleteStep(id);
|
||||||
}}
|
}}
|
||||||
|
|||||||
+8
-5
@@ -1,13 +1,13 @@
|
|||||||
|
import { WorkflowDiagramCreateStepElement } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepElement';
|
||||||
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
||||||
import { WorkflowDiagramStepNodeIcon } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeIcon';
|
import { WorkflowDiagramStepNodeIcon } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeIcon';
|
||||||
|
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||||
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { WorkflowDiagramNodeVariant } from '@/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant';
|
import { WorkflowDiagramNodeVariant } from '@/workflow/workflow-diagram/types/WorkflowDiagramNodeVariant';
|
||||||
import { FloatingIconButton } from 'twenty-ui/input';
|
|
||||||
import { IconTrash } from 'twenty-ui/display';
|
|
||||||
import { WorkflowDiagramCreateStepElement } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepElement';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
import { useState } from 'react';
|
||||||
|
import { IconTrash } from 'twenty-ui/display';
|
||||||
|
import { FloatingIconButton } from 'twenty-ui/input';
|
||||||
|
|
||||||
const StyledDeleteButtonContainer = styled.div`
|
const StyledDeleteButtonContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -39,12 +39,14 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
|||||||
selected,
|
selected,
|
||||||
variant,
|
variant,
|
||||||
onDelete,
|
onDelete,
|
||||||
|
onClick,
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
data: WorkflowDiagramStepNodeData;
|
data: WorkflowDiagramStepNodeData;
|
||||||
variant: WorkflowDiagramNodeVariant;
|
variant: WorkflowDiagramNodeVariant;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
|
onClick?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
@@ -60,6 +62,7 @@ export const WorkflowDiagramStepNodeEditableContent = ({
|
|||||||
<WorkflowDiagramStepNodeBase
|
<WorkflowDiagramStepNodeBase
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
|
onClick={onClick}
|
||||||
id={id}
|
id={id}
|
||||||
name={data.name}
|
name={data.name}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
|
|||||||
+55
-1
@@ -1,8 +1,20 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState';
|
||||||
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
||||||
import { WorkflowDiagramStepNodeIcon } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeIcon';
|
import { WorkflowDiagramStepNodeIcon } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeIcon';
|
||||||
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { getNodeVariantFromStepRunStatus } from '@/workflow/workflow-diagram/utils/getNodeVariantFromStepRunStatus';
|
import { getNodeVariantFromStepRunStatus } from '@/workflow/workflow-diagram/utils/getNodeVariantFromStepRunStatus';
|
||||||
import React from 'react';
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const WorkflowDiagramStepNodeReadonly = ({
|
export const WorkflowDiagramStepNodeReadonly = ({
|
||||||
id,
|
id,
|
||||||
@@ -11,6 +23,27 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
|||||||
id: string;
|
id: string;
|
||||||
data: WorkflowDiagramStepNodeData;
|
data: WorkflowDiagramStepNodeData;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflowVisualizerWorkflowVersionId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowVersionIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowDiagramStepNodeBase
|
<WorkflowDiagramStepNodeBase
|
||||||
id={id}
|
id={id}
|
||||||
@@ -19,6 +52,27 @@ export const WorkflowDiagramStepNodeReadonly = ({
|
|||||||
nodeType={data.nodeType}
|
nodeType={data.nodeType}
|
||||||
Icon={<WorkflowDiagramStepNodeIcon data={data} />}
|
Icon={<WorkflowDiagramStepNodeIcon data={data} />}
|
||||||
displayHandle={false}
|
displayHandle={false}
|
||||||
|
onClick={() => {
|
||||||
|
if (
|
||||||
|
!isDefined(workflowVisualizerWorkflowId) ||
|
||||||
|
!isDefined(workflowVisualizerWorkflowVersionId)
|
||||||
|
) {
|
||||||
|
throw new Error('Workflow ID and Version ID must be defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorkflowSelectedNode(id);
|
||||||
|
|
||||||
|
openWorkflowViewStepInCommandMenu({
|
||||||
|
workflowId: workflowVisualizerWorkflowId,
|
||||||
|
workflowVersionId: workflowVisualizerWorkflowVersionId,
|
||||||
|
title: data.name,
|
||||||
|
icon: getIcon(getWorkflowNodeIconKey(data)),
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-10
@@ -3,9 +3,7 @@ import { WorkflowDiagramCanvasBase } from '@/workflow/workflow-diagram/component
|
|||||||
import { WorkflowDiagramDefaultEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeRun';
|
import { WorkflowDiagramDefaultEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdgeRun';
|
||||||
import { WorkflowDiagramFilterEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeRun';
|
import { WorkflowDiagramFilterEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilterEdgeRun';
|
||||||
import { WorkflowDiagramFilteringDisabledEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeRun';
|
import { WorkflowDiagramFilteringDisabledEdgeRun } from '@/workflow/workflow-diagram/components/WorkflowDiagramFilteringDisabledEdgeRun';
|
||||||
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
import { WorkflowRunDiagramStepNode } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramStepNode';
|
||||||
import { WorkflowRunDiagramCanvasEffect } from '@/workflow/workflow-diagram/components/WorkflowRunDiagramCanvasEffect';
|
|
||||||
import { useHandleWorkflowRunDiagramCanvasInit } from '@/workflow/workflow-diagram/hooks/useHandleWorkflowRunDiagramCanvasInit';
|
|
||||||
import { getWorkflowRunStatusTagProps } from '@/workflow/workflow-diagram/utils/getWorkflowRunStatusTagProps';
|
import { getWorkflowRunStatusTagProps } from '@/workflow/workflow-diagram/utils/getWorkflowRunStatusTagProps';
|
||||||
import { ReactFlowProvider } from '@xyflow/react';
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
|
|
||||||
@@ -18,14 +16,11 @@ export const WorkflowRunDiagramCanvas = ({
|
|||||||
workflowRunStatus,
|
workflowRunStatus,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { handleWorkflowRunDiagramCanvasInit } =
|
|
||||||
useHandleWorkflowRunDiagramCanvasInit();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<WorkflowDiagramCanvasBase
|
<WorkflowDiagramCanvasBase
|
||||||
nodeTypes={{
|
nodeTypes={{
|
||||||
default: WorkflowDiagramStepNodeReadonly,
|
default: WorkflowRunDiagramStepNode,
|
||||||
}}
|
}}
|
||||||
edgeTypes={{
|
edgeTypes={{
|
||||||
'filtering-disabled--run': WorkflowDiagramFilteringDisabledEdgeRun,
|
'filtering-disabled--run': WorkflowDiagramFilteringDisabledEdgeRun,
|
||||||
@@ -35,10 +30,7 @@ export const WorkflowRunDiagramCanvas = ({
|
|||||||
tagContainerTestId="workflow-run-status"
|
tagContainerTestId="workflow-run-status"
|
||||||
tagColor={tagProps.color}
|
tagColor={tagProps.color}
|
||||||
tagText={tagProps.text}
|
tagText={tagProps.text}
|
||||||
onInit={handleWorkflowRunDiagramCanvasInit}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<WorkflowRunDiagramCanvasEffect />
|
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
-91
@@ -1,91 +0,0 @@
|
|||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
|
||||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
|
||||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
|
||||||
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
|
||||||
import { WorkflowRunDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
|
||||||
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { useIcons } from 'twenty-ui/display';
|
|
||||||
|
|
||||||
export const WorkflowRunDiagramCanvasEffect = () => {
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
|
|
||||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
|
||||||
|
|
||||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
|
||||||
|
|
||||||
const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackState(
|
|
||||||
workflowVisualizerWorkflowIdComponentState,
|
|
||||||
);
|
|
||||||
const workflowDiagramStatusState = useRecoilComponentCallbackState(
|
|
||||||
workflowDiagramStatusComponentState,
|
|
||||||
);
|
|
||||||
const workflowSelectedNodeState = useRecoilComponentCallbackState(
|
|
||||||
workflowSelectedNodeComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectionChange = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
|
||||||
const workflowId = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowVisualizerWorkflowIdState,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isDefined(workflowId)) {
|
|
||||||
throw new Error('Expected the workflowId to be defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const workflowDiagramStatus = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowDiagramStatusState,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The `handleSelectionChange` function is called when the diagram initializes and
|
|
||||||
// a node is selected. In this case, we don't want to execute the rest of this function.
|
|
||||||
// We open the Side Panel® synchronously after ReactFlow is initialized and a node is selected,
|
|
||||||
// animations perform better that way.
|
|
||||||
if (workflowDiagramStatus !== 'done') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedNode = nodes[0] as WorkflowRunDiagramNode | undefined;
|
|
||||||
|
|
||||||
if (!isDefined(selectedNode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set(workflowSelectedNodeState, selectedNode.id);
|
|
||||||
|
|
||||||
const selectedNodeData = selectedNode.data;
|
|
||||||
|
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
|
||||||
workflowId,
|
|
||||||
workflowRunId,
|
|
||||||
title: selectedNodeData.name,
|
|
||||||
icon: getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
|
||||||
workflowSelectedNode: selectedNode.id,
|
|
||||||
stepExecutionStatus: selectedNodeData.runStatus,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[
|
|
||||||
workflowVisualizerWorkflowIdState,
|
|
||||||
workflowDiagramStatusState,
|
|
||||||
workflowSelectedNodeState,
|
|
||||||
openWorkflowRunViewStepInCommandMenu,
|
|
||||||
workflowRunId,
|
|
||||||
getIcon,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
useOnSelectionChange({
|
|
||||||
onChange: handleSelectionChange,
|
|
||||||
});
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
|
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
||||||
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
|
||||||
|
import { WorkflowDiagramStepNodeIcon } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeIcon';
|
||||||
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
|
import { WorkflowRunDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
|
import { getNodeVariantFromStepRunStatus } from '@/workflow/workflow-diagram/utils/getNodeVariantFromStepRunStatus';
|
||||||
|
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
|
export const WorkflowRunDiagramStepNode = ({
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
data: WorkflowRunDiagramStepNodeData;
|
||||||
|
}) => {
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
|
const workflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
const workflowRunId = useWorkflowRunIdOrThrow();
|
||||||
|
|
||||||
|
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||||
|
workflowSelectedNodeComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WorkflowDiagramStepNodeBase
|
||||||
|
id={id}
|
||||||
|
name={data.name}
|
||||||
|
variant={getNodeVariantFromStepRunStatus(data.runStatus)}
|
||||||
|
nodeType={data.nodeType}
|
||||||
|
Icon={<WorkflowDiagramStepNodeIcon data={data} />}
|
||||||
|
displayHandle={false}
|
||||||
|
onClick={() => {
|
||||||
|
if (!isDefined(workflowId)) {
|
||||||
|
throw new Error('Workflow ID must be defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorkflowSelectedNode(id);
|
||||||
|
|
||||||
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
|
workflowId,
|
||||||
|
workflowRunId,
|
||||||
|
title: data.name,
|
||||||
|
icon: getIcon(getWorkflowNodeIconKey(data)),
|
||||||
|
workflowSelectedNode: id,
|
||||||
|
stepExecutionStatus: data.runStatus,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
+61
-63
@@ -13,7 +13,6 @@ import { WorkflowRunState } from '@/workflow/types/Workflow';
|
|||||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||||
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
||||||
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
||||||
import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
|
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
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';
|
||||||
@@ -52,9 +51,6 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
const workflowDiagramStatusState = useRecoilComponentCallbackState(
|
const workflowDiagramStatusState = useRecoilComponentCallbackState(
|
||||||
workflowDiagramStatusComponentState,
|
workflowDiagramStatusComponentState,
|
||||||
);
|
);
|
||||||
const workflowRunStepToOpenByDefaultState = useRecoilComponentCallbackState(
|
|
||||||
workflowRunStepToOpenByDefaultComponentState,
|
|
||||||
);
|
|
||||||
const workflowSelectedNodeState = useRecoilComponentCallbackState(
|
const workflowSelectedNodeState = useRecoilComponentCallbackState(
|
||||||
workflowSelectedNodeComponentState,
|
workflowSelectedNodeComponentState,
|
||||||
);
|
);
|
||||||
@@ -126,67 +122,70 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
isWorkflowFilteringEnabled,
|
isWorkflowFilteringEnabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isDefined(stepToOpenByDefault)) {
|
|
||||||
if (isInRightDrawer) {
|
|
||||||
set(workflowDiagramState, baseWorkflowRunDiagram);
|
|
||||||
|
|
||||||
const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
|
||||||
);
|
|
||||||
const hasStepAlreadyBeenOpenedAutomatically =
|
|
||||||
workflowRunDiagramAutomaticallyOpenedSteps.includes(
|
|
||||||
stepToOpenByDefault.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
workflowDiagramStatus === 'done' &&
|
|
||||||
!hasStepAlreadyBeenOpenedAutomatically
|
|
||||||
) {
|
|
||||||
set(workflowSelectedNodeState, stepToOpenByDefault.id);
|
|
||||||
|
|
||||||
const workflowVisualizerWorkflowId = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowVisualizerWorkflowIdState,
|
|
||||||
);
|
|
||||||
if (!isDefined(workflowVisualizerWorkflowId)) {
|
|
||||||
throw new Error(
|
|
||||||
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(workflowRunDiagramAutomaticallyOpenedStepsState, [
|
|
||||||
...workflowRunDiagramAutomaticallyOpenedSteps,
|
|
||||||
stepToOpenByDefault.id,
|
|
||||||
]);
|
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
|
||||||
workflowId: workflowVisualizerWorkflowId,
|
|
||||||
workflowRunId,
|
|
||||||
title: stepToOpenByDefault.data.name,
|
|
||||||
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
|
|
||||||
workflowSelectedNode: stepToOpenByDefault.id,
|
|
||||||
stepExecutionStatus: stepToOpenByDefault.data.runStatus,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const workflowRunDiagram = selectWorkflowDiagramNode({
|
|
||||||
diagram: baseWorkflowRunDiagram,
|
|
||||||
nodeIdToSelect: stepToOpenByDefault.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
set(workflowDiagramState, workflowRunDiagram);
|
|
||||||
set(workflowRunStepToOpenByDefaultState, {
|
|
||||||
id: stepToOpenByDefault.id,
|
|
||||||
data: stepToOpenByDefault.data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
set(workflowDiagramState, baseWorkflowRunDiagram);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workflowDiagramStatus !== 'done') {
|
if (workflowDiagramStatus !== 'done') {
|
||||||
set(workflowDiagramStatusState, 'computing-dimensions');
|
set(workflowDiagramStatusState, 'computing-dimensions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isDefined(stepToOpenByDefault)) {
|
||||||
|
set(workflowDiagramState, baseWorkflowRunDiagram);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||||
|
);
|
||||||
|
const hasStepAlreadyBeenOpenedAutomatically =
|
||||||
|
workflowRunDiagramAutomaticallyOpenedSteps.some(
|
||||||
|
(step) =>
|
||||||
|
step.stepId === stepToOpenByDefault.id &&
|
||||||
|
step.isInRightDrawer === isInRightDrawer,
|
||||||
|
);
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
workflowVisualizerWorkflowIdState,
|
||||||
|
);
|
||||||
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
|
throw new Error(
|
||||||
|
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInRightDrawer) {
|
||||||
|
set(workflowDiagramState, baseWorkflowRunDiagram);
|
||||||
|
} else {
|
||||||
|
const workflowRunDiagram = selectWorkflowDiagramNode({
|
||||||
|
diagram: baseWorkflowRunDiagram,
|
||||||
|
nodeIdToSelect: stepToOpenByDefault.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
set(workflowDiagramState, workflowRunDiagram);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStepAlreadyBeenOpenedAutomatically) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(workflowSelectedNodeState, stepToOpenByDefault.id);
|
||||||
|
|
||||||
|
set(workflowRunDiagramAutomaticallyOpenedStepsState, [
|
||||||
|
...workflowRunDiagramAutomaticallyOpenedSteps,
|
||||||
|
{
|
||||||
|
stepId: stepToOpenByDefault.id,
|
||||||
|
isInRightDrawer,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
openWorkflowRunViewStepInCommandMenu({
|
||||||
|
workflowId: workflowVisualizerWorkflowId,
|
||||||
|
workflowRunId,
|
||||||
|
title: stepToOpenByDefault.data.name,
|
||||||
|
icon: getIcon(getWorkflowNodeIconKey(stepToOpenByDefault.data)),
|
||||||
|
workflowSelectedNode: stepToOpenByDefault.id,
|
||||||
|
stepExecutionStatus: stepToOpenByDefault.data.runStatus,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
flowState,
|
flowState,
|
||||||
@@ -197,7 +196,6 @@ export const WorkflowRunVisualizerEffect = ({
|
|||||||
workflowDiagramStatusState,
|
workflowDiagramStatusState,
|
||||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
workflowRunDiagramAutomaticallyOpenedStepsState,
|
||||||
workflowRunId,
|
workflowRunId,
|
||||||
workflowRunStepToOpenByDefaultState,
|
|
||||||
workflowSelectedNodeState,
|
workflowSelectedNodeState,
|
||||||
workflowVisualizerWorkflowIdState,
|
workflowVisualizerWorkflowIdState,
|
||||||
],
|
],
|
||||||
|
|||||||
+11
-9
@@ -1,24 +1,26 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
import '@xyflow/react/dist/style.css';
|
|
||||||
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
|
||||||
import { WorkflowDiagramEmptyTrigger } from '../WorkflowDiagramEmptyTrigger';
|
|
||||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
|
||||||
import { RecoilRoot } from 'recoil';
|
|
||||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||||
|
import '@xyflow/react/dist/style.css';
|
||||||
|
import { RecoilRoot } from 'recoil';
|
||||||
|
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||||
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
|
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
||||||
|
import { WorkflowDiagramEmptyTriggerEditable } from '../WorkflowDiagramEmptyTriggerEditable';
|
||||||
|
|
||||||
const meta: Meta<typeof WorkflowDiagramEmptyTrigger> = {
|
const meta: Meta<typeof WorkflowDiagramEmptyTriggerEditable> = {
|
||||||
title: 'Modules/Workflow/WorkflowDiagramEmptyTrigger',
|
title: 'Modules/Workflow/WorkflowDiagramEmptyTriggerEditable',
|
||||||
component: WorkflowDiagramEmptyTrigger,
|
component: WorkflowDiagramEmptyTriggerEditable,
|
||||||
args: {
|
args: {
|
||||||
data: {
|
data: {
|
||||||
nodeType: 'empty-trigger',
|
nodeType: 'empty-trigger',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
decorators: [I18nFrontDecorator],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof WorkflowDiagramEmptyTrigger>;
|
type Story = StoryObj<typeof WorkflowDiagramEmptyTriggerEditable>;
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
decorators: [
|
decorators: [
|
||||||
-8
@@ -1,8 +0,0 @@
|
|||||||
import { NODE_BORDER_WIDTH } from '@/workflow/workflow-diagram/constants/NodeBorderWidth';
|
|
||||||
|
|
||||||
export const STEP_ICON_WIDTH = 24;
|
|
||||||
|
|
||||||
const STEP_PADDING = 8;
|
|
||||||
|
|
||||||
export const CREATE_STEP_NODE_WIDTH =
|
|
||||||
STEP_ICON_WIDTH + STEP_PADDING + NODE_BORDER_WIDTH;
|
|
||||||
-79
@@ -1,79 +0,0 @@
|
|||||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
|
||||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
|
||||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
|
||||||
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
|
||||||
import { act, renderHook } from '@testing-library/react';
|
|
||||||
import { useReactFlow } from '@xyflow/react';
|
|
||||||
import { RecoilRoot } from 'recoil';
|
|
||||||
|
|
||||||
jest.mock('@xyflow/react', () => ({
|
|
||||||
useReactFlow: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
||||||
<RecoilRoot>
|
|
||||||
<WorkflowVisualizerComponentInstanceContext.Provider
|
|
||||||
value={{
|
|
||||||
instanceId: 'test-instance-id',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</WorkflowVisualizerComponentInstanceContext.Provider>
|
|
||||||
</RecoilRoot>
|
|
||||||
);
|
|
||||||
|
|
||||||
describe('useTriggerNodeSelection', () => {
|
|
||||||
const mockSetNodes = jest.fn();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
(useReactFlow as jest.Mock).mockReturnValue({
|
|
||||||
setNodes: mockSetNodes,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should trigger node selection', () => {
|
|
||||||
const { result } = renderHook(
|
|
||||||
() => {
|
|
||||||
const [
|
|
||||||
workflowDiagramTriggerNodeSelection,
|
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
|
||||||
] = useRecoilComponentState(
|
|
||||||
workflowDiagramTriggerNodeSelectionComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
useTriggerNodeSelection();
|
|
||||||
|
|
||||||
return {
|
|
||||||
workflowDiagramTriggerNodeSelection,
|
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wrapper,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const mockNodeId = 'test-node-id';
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
result.current.setWorkflowDiagramTriggerNodeSelection(mockNodeId);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.current.workflowDiagramTriggerNodeSelection).toBeUndefined();
|
|
||||||
|
|
||||||
expect(mockSetNodes).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not trigger update if state is not defined', () => {
|
|
||||||
renderHook(() => useTriggerNodeSelection(), {
|
|
||||||
wrapper,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure updateNode is not called when state is undefined
|
|
||||||
expect(mockSetNodes).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
-124
@@ -1,124 +0,0 @@
|
|||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
|
||||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
|
||||||
import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow';
|
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
|
||||||
import { workflowDiagramStatusComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramStatusComponentState';
|
|
||||||
import { workflowRunDiagramAutomaticallyOpenedStepsComponentState } from '@/workflow/workflow-diagram/states/workflowRunDiagramAutomaticallyOpenedStepsComponentState';
|
|
||||||
import { workflowRunStepToOpenByDefaultComponentState } from '@/workflow/workflow-diagram/states/workflowRunStepToOpenByDefaultComponentState';
|
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
import { useIcons } from 'twenty-ui/display';
|
|
||||||
|
|
||||||
export const useHandleWorkflowRunDiagramCanvasInit = () => {
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
|
|
||||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
|
||||||
const { isInRightDrawer } = useContext(ActionMenuContext);
|
|
||||||
|
|
||||||
const workflowRunId = useWorkflowRunIdOrThrow();
|
|
||||||
|
|
||||||
const workflowVisualizerWorkflowIdState = useRecoilComponentCallbackState(
|
|
||||||
workflowVisualizerWorkflowIdComponentState,
|
|
||||||
);
|
|
||||||
const workflowDiagramStatusState = useRecoilComponentCallbackState(
|
|
||||||
workflowDiagramStatusComponentState,
|
|
||||||
);
|
|
||||||
const workflowRunStepToOpenByDefaultState = useRecoilComponentCallbackState(
|
|
||||||
workflowRunStepToOpenByDefaultComponentState,
|
|
||||||
);
|
|
||||||
const workflowSelectedNodeState = useRecoilComponentCallbackState(
|
|
||||||
workflowSelectedNodeComponentState,
|
|
||||||
);
|
|
||||||
const workflowRunDiagramAutomaticallyOpenedStepsState =
|
|
||||||
useRecoilComponentCallbackState(
|
|
||||||
workflowRunDiagramAutomaticallyOpenedStepsComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleWorkflowRunDiagramCanvasInit = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
() => {
|
|
||||||
const workflowDiagramStatus = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowDiagramStatusState,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (workflowDiagramStatus !== 'computing-dimensions') {
|
|
||||||
throw new Error(
|
|
||||||
'Sequence error: reactflow should be considered initialized only when the workflow diagram status is computing-dimensions.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(workflowDiagramStatusState, 'done');
|
|
||||||
|
|
||||||
if (isInRightDrawer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const workflowStepToOpenByDefault = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowRunStepToOpenByDefaultState,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDefined(workflowStepToOpenByDefault)) {
|
|
||||||
const workflowVisualizerWorkflowId = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowVisualizerWorkflowIdState,
|
|
||||||
);
|
|
||||||
if (!isDefined(workflowVisualizerWorkflowId)) {
|
|
||||||
throw new Error(
|
|
||||||
'The workflow id must be set; ensure the workflow id is always set before rendering the workflow diagram.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(workflowSelectedNodeState, workflowStepToOpenByDefault.id);
|
|
||||||
|
|
||||||
const workflowRunDiagramAutomaticallyOpenedSteps = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
|
||||||
);
|
|
||||||
const hasStepAlreadyBeenOpenedAutomatically =
|
|
||||||
workflowRunDiagramAutomaticallyOpenedSteps.includes(
|
|
||||||
workflowStepToOpenByDefault.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
// FIXME: This is a workaround to avoid opening a workflow run step twice when going from the side panel to the fullscreen show page.
|
|
||||||
// The step is opened in the `handleSelectionChange` function of `WorkflowRunDiagramCanvasEffect`. I think it shouldn't be opened there but
|
|
||||||
// we should keep opening the step here, in `handleWorkflowRunDiagramCanvasInit`.
|
|
||||||
if (!hasStepAlreadyBeenOpenedAutomatically) {
|
|
||||||
openWorkflowRunViewStepInCommandMenu({
|
|
||||||
workflowId: workflowVisualizerWorkflowId,
|
|
||||||
workflowRunId,
|
|
||||||
title: workflowStepToOpenByDefault.data.name,
|
|
||||||
icon: getIcon(
|
|
||||||
getWorkflowNodeIconKey(workflowStepToOpenByDefault.data),
|
|
||||||
),
|
|
||||||
workflowSelectedNode: workflowStepToOpenByDefault.id,
|
|
||||||
stepExecutionStatus: workflowStepToOpenByDefault.data.runStatus,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
set(workflowRunStepToOpenByDefaultState, undefined);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
workflowDiagramStatusState,
|
|
||||||
isInRightDrawer,
|
|
||||||
workflowRunStepToOpenByDefaultState,
|
|
||||||
workflowVisualizerWorkflowIdState,
|
|
||||||
workflowSelectedNodeState,
|
|
||||||
workflowRunDiagramAutomaticallyOpenedStepsState,
|
|
||||||
openWorkflowRunViewStepInCommandMenu,
|
|
||||||
workflowRunId,
|
|
||||||
getIcon,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleWorkflowRunDiagramCanvasInit,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
+19
-4
@@ -1,13 +1,17 @@
|
|||||||
import { useCallback } from 'react';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
|
||||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
import { workflowInsertStepIdsComponentState } from '@/workflow/workflow-steps/states/workflowInsertStepIdsComponentState';
|
||||||
|
import { useCallback, useContext } from 'react';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const useStartNodeCreation = () => {
|
export const useStartNodeCreation = () => {
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
const [workflowInsertStepIds, setWorkflowInsertStepIds] =
|
const [workflowInsertStepIds, setWorkflowInsertStepIds] =
|
||||||
useRecoilComponentState(workflowInsertStepIdsComponentState);
|
useRecoilComponentState(workflowInsertStepIdsComponentState);
|
||||||
|
|
||||||
@@ -17,6 +21,10 @@ export const useStartNodeCreation = () => {
|
|||||||
workflowVisualizerWorkflowIdComponentState,
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
* That's why its wrapped in a `useCallback` hook. Removing memoization might break the app unexpectedly.
|
* That's why its wrapped in a `useCallback` hook. Removing memoization might break the app unexpectedly.
|
||||||
@@ -33,15 +41,22 @@ export const useStartNodeCreation = () => {
|
|||||||
}) => {
|
}) => {
|
||||||
setWorkflowInsertStepIds({ parentStepId, nextStepId, position });
|
setWorkflowInsertStepIds({ parentStepId, nextStepId, position });
|
||||||
|
|
||||||
if (isDefined(workflowVisualizerWorkflowId)) {
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
openStepSelectInCommandMenu(workflowVisualizerWorkflowId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isInRightDrawer) {
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
openStepSelectInCommandMenu(workflowVisualizerWorkflowId);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
setWorkflowInsertStepIds,
|
setWorkflowInsertStepIds,
|
||||||
workflowVisualizerWorkflowId,
|
workflowVisualizerWorkflowId,
|
||||||
|
isInRightDrawer,
|
||||||
openStepSelectInCommandMenu,
|
openStepSelectInCommandMenu,
|
||||||
|
setCommandMenuNavigationStack,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
|
||||||
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
|
||||||
import {
|
|
||||||
WorkflowDiagramEdge,
|
|
||||||
WorkflowDiagramNode,
|
|
||||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
import { useReactFlow } from '@xyflow/react';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
export const useTriggerNodeSelection = () => {
|
|
||||||
const reactflow = useReactFlow<WorkflowDiagramNode, WorkflowDiagramEdge>();
|
|
||||||
|
|
||||||
const [
|
|
||||||
workflowDiagramTriggerNodeSelection,
|
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
|
||||||
] = useRecoilComponentState(
|
|
||||||
workflowDiagramTriggerNodeSelectionComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isDefined(workflowDiagramTriggerNodeSelection)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reactflow.setNodes((nodes) =>
|
|
||||||
nodes.map((node) => ({
|
|
||||||
...node,
|
|
||||||
selected: workflowDiagramTriggerNodeSelection === node.id,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
setWorkflowDiagramTriggerNodeSelection(undefined);
|
|
||||||
}, [
|
|
||||||
reactflow,
|
|
||||||
setWorkflowDiagramTriggerNodeSelection,
|
|
||||||
workflowDiagramTriggerNodeSelection,
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
|
||||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
|
||||||
|
|
||||||
export const workflowDiagramTriggerNodeSelectionComponentState =
|
|
||||||
createComponentState<string | undefined>({
|
|
||||||
key: 'workflowDiagramTriggerNodeSelectionComponentState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
|
||||||
});
|
|
||||||
+1
-1
@@ -2,7 +2,7 @@ import { createComponentState } from '@/ui/utilities/state/component-state/utils
|
|||||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||||
|
|
||||||
export const workflowRunDiagramAutomaticallyOpenedStepsComponentState =
|
export const workflowRunDiagramAutomaticallyOpenedStepsComponentState =
|
||||||
createComponentState<string[]>({
|
createComponentState<{ stepId: string; isInRightDrawer: boolean }[]>({
|
||||||
key: 'workflowRunDiagramAutomaticallyOpenedStepsComponentState',
|
key: 'workflowRunDiagramAutomaticallyOpenedStepsComponentState',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
||||||
|
|||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
|
||||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
|
||||||
import { WorkflowRunDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
|
||||||
|
|
||||||
export const workflowRunStepToOpenByDefaultComponentState =
|
|
||||||
createComponentState<
|
|
||||||
| {
|
|
||||||
id: string;
|
|
||||||
data: WorkflowRunDiagramStepNodeData;
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
>({
|
|
||||||
key: 'workflowRunStepToOpenByDefaultComponentState',
|
|
||||||
defaultValue: undefined,
|
|
||||||
componentInstanceContext: WorkflowVisualizerComponentInstanceContext,
|
|
||||||
});
|
|
||||||
@@ -30,8 +30,6 @@ export const useDeleteStep = ({
|
|||||||
const deleteStep = async (stepId: string) => {
|
const deleteStep = async (stepId: string) => {
|
||||||
assertWorkflowWithCurrentVersionIsDefined(workflow);
|
assertWorkflowWithCurrentVersionIsDefined(workflow);
|
||||||
|
|
||||||
closeCommandMenu();
|
|
||||||
|
|
||||||
const workflowVersionId = await getUpdatableWorkflowVersion(workflow);
|
const workflowVersionId = await getUpdatableWorkflowVersion(workflow);
|
||||||
|
|
||||||
if (!isDefined(workflowVersionId)) {
|
if (!isDefined(workflowVersionId)) {
|
||||||
@@ -51,6 +49,9 @@ export const useDeleteStep = ({
|
|||||||
stepId,
|
stepId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeCommandMenu();
|
||||||
|
|
||||||
deleteStepOutputSchema({
|
deleteStepOutputSchema({
|
||||||
stepId,
|
stepId,
|
||||||
workflowVersionId,
|
workflowVersionId,
|
||||||
|
|||||||
+47
-4
@@ -1,10 +1,16 @@
|
|||||||
|
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||||
|
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||||
import { workflowDiagramTriggerNodeSelectionComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramTriggerNodeSelectionComponentState';
|
import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState';
|
||||||
|
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||||
import { getVariableTemplateFromPath } from '@/workflow/workflow-variables/utils/getVariableTemplateFromPath';
|
import { getVariableTemplateFromPath } from '@/workflow/workflow-variables/utils/getVariableTemplateFromPath';
|
||||||
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 { useIcons } from 'twenty-ui/display';
|
||||||
import {
|
import {
|
||||||
BaseOutputSchema,
|
BaseOutputSchema,
|
||||||
LinkOutputSchema,
|
LinkOutputSchema,
|
||||||
@@ -35,9 +41,17 @@ export const useVariableDropdown = ({
|
|||||||
onSelect,
|
onSelect,
|
||||||
onBack,
|
onBack,
|
||||||
}: UseVariableDropdownProps): UseVariableDropdownReturn => {
|
}: UseVariableDropdownProps): UseVariableDropdownReturn => {
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
const [currentPath, setCurrentPath] = useState<string[]>([]);
|
||||||
const [searchInputValue, setSearchInputValue] = useState('');
|
const [searchInputValue, setSearchInputValue] = useState('');
|
||||||
|
|
||||||
|
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||||
|
|
||||||
|
const workflowVisualizerWorkflowId = useRecoilComponentValue(
|
||||||
|
workflowVisualizerWorkflowIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
const setWorkflowSelectedNode = useSetRecoilComponentState(
|
||||||
workflowSelectedNodeComponentState,
|
workflowSelectedNodeComponentState,
|
||||||
);
|
);
|
||||||
@@ -45,8 +59,11 @@ export const useVariableDropdown = ({
|
|||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
'workflow-serverless-function-tab-list-component-id',
|
'workflow-serverless-function-tab-list-component-id',
|
||||||
);
|
);
|
||||||
const setWorkflowDiagramTriggerNodeSelection = useSetRecoilComponentState(
|
const setWorkflowDiagram = useSetRecoilComponentState(
|
||||||
workflowDiagramTriggerNodeSelectionComponentState,
|
workflowDiagramComponentState,
|
||||||
|
);
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const getDisplayedSubStepFields = () => {
|
const getDisplayedSubStepFields = () => {
|
||||||
@@ -83,8 +100,34 @@ export const useVariableDropdown = ({
|
|||||||
const handleSelectLinkOutputSchema = (
|
const handleSelectLinkOutputSchema = (
|
||||||
linkOutputSchema: LinkOutputSchema,
|
linkOutputSchema: LinkOutputSchema,
|
||||||
) => {
|
) => {
|
||||||
|
if (!isDefined(workflowVisualizerWorkflowId)) {
|
||||||
|
throw new Error('Workflow ID must be configured');
|
||||||
|
}
|
||||||
|
|
||||||
setWorkflowSelectedNode(step.id);
|
setWorkflowSelectedNode(step.id);
|
||||||
setWorkflowDiagramTriggerNodeSelection(step.id);
|
|
||||||
|
setWorkflowDiagram((diagram) => {
|
||||||
|
if (!isDefined(diagram)) {
|
||||||
|
throw new Error('Workflow diagram must be defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...diagram,
|
||||||
|
nodes: diagram.nodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
selected: node.id === step.id,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
|
||||||
|
openWorkflowEditStepInCommandMenu(
|
||||||
|
workflowVisualizerWorkflowId,
|
||||||
|
step.name,
|
||||||
|
getIcon(step.icon),
|
||||||
|
);
|
||||||
|
|
||||||
if (isDefined(linkOutputSchema.link.tab)) {
|
if (isDefined(linkOutputSchema.link.tab)) {
|
||||||
setActiveTabId(linkOutputSchema.link.tab);
|
setActiveTabId(linkOutputSchema.link.tab);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user