Raphaël Bosi
2025-01-23 14:44:21 +01:00
committed by GitHub
parent cc53cb3b7b
commit 337b6a86ab
21 changed files with 582 additions and 83 deletions

View File

@ -8,11 +8,15 @@ import { EMPTY_TRIGGER_STEP_ID } from '@/workflow/workflow-diagram/constants/Emp
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
import { WorkflowDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import {
WorkflowDiagramNode,
WorkflowDiagramStepNodeData,
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { getWorkflowNodeIcon } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIcon';
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
import { useCallback } from 'react';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-ui';
import { IconBolt, isDefined } from 'twenty-ui';
export const WorkflowDiagramCanvasEditableEffect = () => {
const { startNodeCreation } = useStartNodeCreation();
@ -37,7 +41,10 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID;
if (isEmptyTriggerNode) {
openRightDrawer(RightDrawerPages.WorkflowStepSelectTriggerType);
openRightDrawer(RightDrawerPages.WorkflowStepSelectTriggerType, {
title: 'Trigger Type',
Icon: IconBolt,
});
return;
}
@ -53,9 +60,14 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
return;
}
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
setWorkflowSelectedNode(selectedNode.id);
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
openRightDrawer(RightDrawerPages.WorkflowStepEdit);
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: selectedNodeData.name,
Icon: getWorkflowNodeIcon(selectedNodeData),
});
},
[
setWorkflowSelectedNode,

View File

@ -5,7 +5,11 @@ import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPage
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
import { WorkflowDiagramNode } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import {
WorkflowDiagramNode,
WorkflowDiagramStepNodeData,
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { getWorkflowNodeIcon } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIcon';
import { OnSelectionChangeParams, useOnSelectionChange } from '@xyflow/react';
import { useCallback } from 'react';
import { useSetRecoilState } from 'recoil';
@ -30,7 +34,12 @@ export const WorkflowDiagramCanvasReadonlyEffect = () => {
setWorkflowSelectedNode(selectedNode.id);
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
openRightDrawer(RightDrawerPages.WorkflowStepView);
const selectedNodeData = selectedNode.data as WorkflowDiagramStepNodeData;
openRightDrawer(RightDrawerPages.WorkflowStepView, {
title: selectedNodeData.name,
Icon: getWorkflowNodeIcon(selectedNodeData),
});
},
[
setWorkflowSelectedNode,

View File

@ -1,15 +1,9 @@
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
import { WorkflowDiagramBaseStepNode } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode';
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { getWorkflowNodeIcon } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIcon';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import {
IconAddressBook,
IconCode,
IconHandMove,
IconMail,
IconPlaylistAdd,
} from 'twenty-ui';
const StyledStepNodeLabelIconContainer = styled.div`
align-items: center;
@ -29,6 +23,8 @@ export const WorkflowDiagramStepNodeBase = ({
}) => {
const theme = useTheme();
const Icon = getWorkflowNodeIcon(data);
const renderStepIcon = () => {
switch (data.nodeType) {
case 'trigger': {
@ -36,7 +32,7 @@ export const WorkflowDiagramStepNodeBase = ({
case 'DATABASE_EVENT': {
return (
<StyledStepNodeLabelIconContainer>
<IconPlaylistAdd
<Icon
size={theme.icon.size.lg}
color={theme.font.color.tertiary}
/>
@ -46,7 +42,7 @@ export const WorkflowDiagramStepNodeBase = ({
case 'MANUAL': {
return (
<StyledStepNodeLabelIconContainer>
<IconHandMove
<Icon
size={theme.icon.size.lg}
color={theme.font.color.tertiary}
/>
@ -62,17 +58,14 @@ export const WorkflowDiagramStepNodeBase = ({
case 'CODE': {
return (
<StyledStepNodeLabelIconContainer>
<IconCode
size={theme.icon.size.lg}
color={theme.color.orange}
/>
<Icon size={theme.icon.size.lg} color={theme.color.orange} />
</StyledStepNodeLabelIconContainer>
);
}
case 'SEND_EMAIL': {
return (
<StyledStepNodeLabelIconContainer>
<IconMail size={theme.icon.size.lg} color={theme.color.blue} />
<Icon size={theme.icon.size.lg} color={theme.color.blue} />
</StyledStepNodeLabelIconContainer>
);
}
@ -81,7 +74,7 @@ export const WorkflowDiagramStepNodeBase = ({
case 'DELETE_RECORD': {
return (
<StyledStepNodeLabelIconContainer>
<IconAddressBook
<Icon
size={theme.icon.size.lg}
color={theme.font.color.tertiary}
stroke={theme.icon.stroke.sm}

View File

@ -5,6 +5,7 @@ import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
import { useCallback } from 'react';
import { useSetRecoilState } from 'recoil';
import { IconSettingsAutomation } from 'twenty-ui';
export const useStartNodeCreation = () => {
const { openRightDrawer } = useRightDrawer();
@ -22,7 +23,10 @@ export const useStartNodeCreation = () => {
setWorkflowCreateStepFromParentStepId(parentNodeId);
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
openRightDrawer(RightDrawerPages.WorkflowStepSelectAction);
openRightDrawer(RightDrawerPages.WorkflowStepSelectAction, {
title: 'Select Action',
Icon: IconSettingsAutomation,
});
},
[openRightDrawer, setWorkflowCreateStepFromParentStepId, setHotkeyScope],
);

View File

@ -0,0 +1,56 @@
import {
WorkflowActionType,
WorkflowTriggerType,
} from '@/workflow/types/Workflow';
import { assertUnreachable } from '@/workflow/utils/assertUnreachable';
import {
IconAddressBook,
IconCode,
IconHandMove,
IconMail,
IconPlaylistAdd,
} from 'twenty-ui';
export const getWorkflowNodeIcon = (
data:
| {
nodeType: 'trigger';
triggerType: WorkflowTriggerType;
}
| {
nodeType: 'action';
actionType: WorkflowActionType;
},
) => {
switch (data.nodeType) {
case 'trigger': {
switch (data.triggerType) {
case 'DATABASE_EVENT': {
return IconPlaylistAdd;
}
case 'MANUAL': {
return IconHandMove;
}
}
return assertUnreachable(data.triggerType);
}
case 'action': {
switch (data.actionType) {
case 'CODE': {
return IconCode;
}
case 'SEND_EMAIL': {
return IconMail;
}
case 'CREATE_RECORD':
case 'UPDATE_RECORD':
case 'DELETE_RECORD': {
return IconAddressBook;
}
}
return assertUnreachable(data.actionType);
}
}
};

View File

@ -5,7 +5,7 @@ import { useCreateStep } from '../useCreateStep';
const mockOpenRightDrawer = jest.fn();
const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
data: { createWorkflowVersionStep: { id: '1' } },
data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
});
jest.mock('recoil', () => ({

View File

@ -7,6 +7,7 @@ import {
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
import { getWorkflowNodeIcon } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIcon';
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
import { useRecoilValue, useSetRecoilState } from 'recoil';
@ -17,7 +18,6 @@ export const useCreateStep = ({
}: {
workflow: WorkflowWithCurrentVersion;
}) => {
const { openRightDrawer } = useRightDrawer();
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
const setWorkflowLastCreatedStepId = useSetRecoilState(
@ -30,6 +30,8 @@ export const useCreateStep = ({
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
const { openRightDrawer } = useRightDrawer();
const createStep = async (newStepType: WorkflowStepType) => {
if (!isDefined(workflowCreateStepFromParentStepId)) {
throw new Error('Select a step to create a new step from first.');
@ -50,7 +52,14 @@ export const useCreateStep = ({
setWorkflowSelectedNode(createdStep.id);
setWorkflowLastCreatedStepId(createdStep.id);
openRightDrawer(RightDrawerPages.WorkflowStepEdit);
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: createdStep.name,
Icon: getWorkflowNodeIcon({
nodeType: 'action',
actionType: createdStep.type as WorkflowStepType,
}),
});
};
return {

View File

@ -63,7 +63,10 @@ export const RightDrawerWorkflowSelectTriggerTypeContent = ({
setWorkflowSelectedNode(TRIGGER_STEP_ID);
openRightDrawer(RightDrawerPages.WorkflowStepEdit);
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: action.name,
Icon: action.icon,
});
}}
/>
))}
@ -84,7 +87,10 @@ export const RightDrawerWorkflowSelectTriggerTypeContent = ({
setWorkflowSelectedNode(TRIGGER_STEP_ID);
openRightDrawer(RightDrawerPages.WorkflowStepEdit);
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: action.name,
Icon: action.icon,
});
}}
/>
))}