diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx
index e421d3ccd..920d75a7e 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode.tsx
@@ -1,3 +1,8 @@
+import { NODE_BORDER_WIDTH } from '@/workflow/workflow-diagram/constants/NodeBorderWidth';
+import { NODE_HANDLE_HEIGHT_PX } from '@/workflow/workflow-diagram/constants/NodeHandleHeightPx';
+import { NODE_HANDLE_WIDTH_PX } from '@/workflow/workflow-diagram/constants/NodeHandleWidthPx';
+import { NODE_ICON_LEFT_MARGIN } from '@/workflow/workflow-diagram/constants/NodeIconLeftMargin';
+import { NODE_ICON_WIDTH } from '@/workflow/workflow-diagram/constants/NodeIconWidth';
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import styled from '@emotion/styled';
import { Handle, Position } from '@xyflow/react';
@@ -21,7 +26,7 @@ const StyledStepNodeType = styled.div`
${({ theme }) => theme.border.radius.sm} 0 0;
color: ${({ theme }) => theme.font.color.light};
- font-size: ${({ theme }) => theme.font.size.md};
+ font-size: 9px;
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-left: ${({ theme }) => theme.spacing(2)};
@@ -38,9 +43,8 @@ const StyledStepNodeType = styled.div`
const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
background-color: ${({ theme }) => theme.background.secondary};
- border: 1px solid ${({ theme }) => theme.border.color.medium};
- border-style: ${({ variant }) =>
- variant === 'placeholder' ? 'dashed' : null};
+ border: ${NODE_BORDER_WIDTH}px solid
+ ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md};
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
@@ -61,7 +65,7 @@ const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
align-items: center;
display: flex;
- font-size: ${({ theme }) => theme.font.size.lg};
+ font-size: 13px;
font-weight: ${({ theme }) => theme.font.weight.medium};
column-gap: ${({ theme }) => theme.spacing(2)};
color: ${({ variant, theme }) =>
@@ -71,16 +75,19 @@ const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
max-width: 200px;
`;
-const StyledSourceHandle = styled(Handle)`
+export const StyledHandle = styled(Handle)`
background-color: ${({ theme }) => theme.grayScale.gray25};
border: none;
- width: 4px;
- height: 4px;
- left: ${({ theme }) => theme.spacing(10)};
+ width: ${NODE_HANDLE_WIDTH_PX}px;
+ height: ${NODE_HANDLE_HEIGHT_PX}px;
`;
-export const StyledTargetHandle = styled(Handle)`
- left: ${({ theme }) => theme.spacing(10)};
+const StyledSourceHandle = styled(StyledHandle)`
+ left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
+`;
+
+const StyledTargetHandle = styled(StyledSourceHandle)`
+ left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
visibility: hidden;
`;
@@ -88,7 +95,7 @@ const StyledRightFloatingElementContainer = styled.div`
display: flex;
align-items: center;
position: absolute;
- right: ${({ theme }) => theme.spacing(-3)};
+ right: ${({ theme }) => theme.spacing(-4)};
bottom: 0;
top: 0;
transform: translateX(100%);
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode.tsx
index 493b00d3b..1b6b84365 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode.tsx
@@ -1,15 +1,19 @@
+import { StyledHandle } from '@/workflow/workflow-diagram/components/WorkflowDiagramBaseStepNode';
+import { NODE_BORDER_WIDTH } from '@/workflow/workflow-diagram/constants/NodeBorderWidth';
+import { NODE_ICON_LEFT_MARGIN } from '@/workflow/workflow-diagram/constants/NodeIconLeftMargin';
+import { NODE_ICON_WIDTH } from '@/workflow/workflow-diagram/constants/NodeIconWidth';
import styled from '@emotion/styled';
-import { Handle, Position } from '@xyflow/react';
+import { Position } from '@xyflow/react';
import { IconButton, IconPlus } from 'twenty-ui';
const StyledContainer = styled.div`
- padding-left: ${({ theme }) => theme.spacing(6)};
padding-top: ${({ theme }) => theme.spacing(1)};
+ transform: translateX(-50%);
position: relative;
+ left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
`;
-export const StyledTargetHandle = styled(Handle)`
- left: ${({ theme }) => theme.spacing(10)};
+const StyledTargetHandle = styled(StyledHandle)`
visibility: hidden;
`;
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger.tsx
index 0f59db3dc..c5efa221c 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger.tsx
@@ -22,7 +22,10 @@ export const WorkflowDiagramEmptyTrigger = () => {
variant="placeholder"
Icon={
-
+
}
/>
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase.tsx
index b754defb7..69230cc14 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase.tsx
@@ -33,7 +33,7 @@ export const WorkflowDiagramStepNodeBase = ({
return (
@@ -43,7 +43,7 @@ export const WorkflowDiagramStepNodeBase = ({
return (
@@ -58,14 +58,18 @@ export const WorkflowDiagramStepNodeBase = ({
case 'CODE': {
return (
-
+
);
}
case 'SEND_EMAIL': {
return (
-
+
);
}
@@ -75,7 +79,7 @@ export const WorkflowDiagramStepNodeBase = ({
return (
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
index 845bb6217..a3d2f5572 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable.tsx
@@ -1,11 +1,10 @@
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { workflowIdState } from '@/workflow/states/workflowIdState';
import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined';
-import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
+import { WorkflowDiagramStepNodeEditableContent } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent';
import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
import { useRecoilValue } from 'recoil';
-import { FloatingIconButton, IconTrash } from 'twenty-ui';
export const WorkflowDiagramStepNodeEditable = ({
id,
@@ -26,19 +25,12 @@ export const WorkflowDiagramStepNodeEditable = ({
});
return (
- {
- deleteStep(id);
- }}
- />
- ) : undefined
- }
+ selected={selected ?? false}
+ onDelete={() => {
+ deleteStep(id);
+ }}
/>
);
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent.tsx
new file mode 100644
index 000000000..183988863
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditableContent.tsx
@@ -0,0 +1,28 @@
+import { WorkflowDiagramStepNodeBase } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeBase';
+import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
+import { FloatingIconButton, IconTrash } from 'twenty-ui';
+
+export const WorkflowDiagramStepNodeEditableContent = ({
+ data,
+ selected,
+ onDelete,
+}: {
+ data: WorkflowDiagramStepNodeData;
+ selected: boolean;
+ onDelete: () => void;
+}) => {
+ return (
+
+ ) : undefined
+ }
+ />
+ );
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCreateStepNode.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCreateStepNode.stories.tsx
new file mode 100644
index 000000000..1c029d6ec
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramCreateStepNode.stories.tsx
@@ -0,0 +1,42 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { ReactFlowProvider } from '@xyflow/react';
+import '@xyflow/react/dist/style.css';
+import { ComponentDecorator } from 'twenty-ui';
+import { WorkflowDiagramCreateStepNode } from '../WorkflowDiagramCreateStepNode';
+
+const meta: Meta = {
+ title: 'Modules/Workflow/WorkflowDiagramCreateStepNode',
+ component: WorkflowDiagramCreateStepNode,
+ decorators: [
+ ComponentDecorator,
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export const Selected: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTrigger.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTrigger.stories.tsx
new file mode 100644
index 000000000..e7b5aac82
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramEmptyTrigger.stories.tsx
@@ -0,0 +1,43 @@
+import { Meta, StoryObj } from '@storybook/react';
+import { ComponentDecorator } from 'twenty-ui';
+
+import { ReactFlowProvider } from '@xyflow/react';
+import '@xyflow/react/dist/style.css';
+import { WorkflowDiagramEmptyTrigger } from '../WorkflowDiagramEmptyTrigger';
+
+const meta: Meta = {
+ title: 'Modules/Workflow/WorkflowDiagramEmptyTrigger',
+ component: WorkflowDiagramEmptyTrigger,
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+
+
+ ),
+ ComponentDecorator,
+ ],
+};
+
+export const Selected: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ (Story) => (
+
+
+
+ ),
+ ComponentDecorator,
+ ],
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx
new file mode 100644
index 000000000..45e979ea4
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/__stories__/WorkflowDiagramStepNodeEditableContent.stories.tsx
@@ -0,0 +1,150 @@
+import { Meta, StoryObj } from '@storybook/react';
+
+import { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
+import { fn } from '@storybook/test';
+import { ReactFlowProvider } from '@xyflow/react';
+import '@xyflow/react/dist/style.css';
+import { CatalogDecorator, CatalogStory } from 'twenty-ui';
+import { graphqlMocks } from '~/testing/graphqlMocks';
+import { WorkflowDiagramStepNodeEditableContent } from '../WorkflowDiagramStepNodeEditableContent';
+
+const meta: Meta = {
+ title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent',
+ component: WorkflowDiagramStepNodeEditableContent,
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const All: CatalogStory<
+ Story,
+ typeof WorkflowDiagramStepNodeEditableContent
+> = {
+ args: {
+ onDelete: fn(),
+ selected: false,
+ },
+ parameters: {
+ msw: graphqlMocks,
+ catalog: {
+ options: {
+ elementContainer: {
+ width: 250,
+ style: { position: 'relative' },
+ },
+ },
+ dimensions: [
+ {
+ name: 'step type',
+ values: [
+ {
+ nodeType: 'trigger',
+ triggerType: 'DATABASE_EVENT',
+ name: 'Record is Created',
+ },
+ { nodeType: 'trigger', triggerType: 'MANUAL', name: 'Manual' },
+ {
+ nodeType: 'action',
+ actionType: 'CREATE_RECORD',
+ name: 'Create Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'UPDATE_RECORD',
+ name: 'Update Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'DELETE_RECORD',
+ name: 'Delete Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'SEND_EMAIL',
+ name: 'Send Email',
+ },
+ { nodeType: 'action', actionType: 'CODE', name: 'Code' },
+ ] satisfies WorkflowDiagramStepNodeData[],
+ props: (data: WorkflowDiagramStepNodeData) => ({ data }),
+ },
+ ],
+ },
+ },
+ decorators: [
+ CatalogDecorator,
+ (Story) => {
+ return (
+
+
+
+ );
+ },
+ ],
+};
+export const AllSelected: CatalogStory<
+ Story,
+ typeof WorkflowDiagramStepNodeEditableContent
+> = {
+ args: {
+ onDelete: fn(),
+ selected: true,
+ },
+ parameters: {
+ msw: graphqlMocks,
+ catalog: {
+ options: {
+ elementContainer: {
+ width: 250,
+ style: { position: 'relative' },
+ className: 'selectable selected',
+ },
+ },
+ dimensions: [
+ {
+ name: 'step type',
+ values: [
+ {
+ nodeType: 'trigger',
+ triggerType: 'DATABASE_EVENT',
+ name: 'Record is Created',
+ },
+ { nodeType: 'trigger', triggerType: 'MANUAL', name: 'Manual' },
+ {
+ nodeType: 'action',
+ actionType: 'CREATE_RECORD',
+ name: 'Create Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'UPDATE_RECORD',
+ name: 'Update Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'DELETE_RECORD',
+ name: 'Delete Record',
+ },
+ {
+ nodeType: 'action',
+ actionType: 'SEND_EMAIL',
+ name: 'Send Email',
+ },
+ { nodeType: 'action', actionType: 'CODE', name: 'Code' },
+ ] satisfies WorkflowDiagramStepNodeData[],
+ props: (data: WorkflowDiagramStepNodeData) => ({ data }),
+ },
+ ],
+ },
+ },
+ decorators: [
+ CatalogDecorator,
+ (Story) => {
+ return (
+
+
+
+ );
+ },
+ ],
+};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeBorderWidth.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeBorderWidth.ts
new file mode 100644
index 000000000..da353c77b
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeBorderWidth.ts
@@ -0,0 +1 @@
+export const NODE_BORDER_WIDTH = 1;
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleHeightPx.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleHeightPx.ts
new file mode 100644
index 000000000..3a0b4349e
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleHeightPx.ts
@@ -0,0 +1,3 @@
+import { NODE_HANDLE_WIDTH_PX } from './NodeHandleWidthPx';
+
+export const NODE_HANDLE_HEIGHT_PX = NODE_HANDLE_WIDTH_PX;
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleWidthPx.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleWidthPx.ts
new file mode 100644
index 000000000..81ce92f81
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeHandleWidthPx.ts
@@ -0,0 +1 @@
+export const NODE_HANDLE_WIDTH_PX = 4;
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconLeftMargin.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconLeftMargin.ts
new file mode 100644
index 000000000..4f719adfb
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconLeftMargin.ts
@@ -0,0 +1,5 @@
+import { THEME_COMMON } from 'twenty-ui';
+
+export const NODE_ICON_LEFT_MARGIN = Number(
+ THEME_COMMON.spacing(2).replace('px', ''),
+);
diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconWidth.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconWidth.ts
new file mode 100644
index 000000000..49e17655d
--- /dev/null
+++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/constants/NodeIconWidth.ts
@@ -0,0 +1,5 @@
+import { THEME_COMMON } from 'twenty-ui';
+
+export const NODE_ICON_WIDTH = Number(
+ THEME_COMMON.spacing(6).replace('px', ''),
+);
diff --git a/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx b/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx
index ab43a7df1..97920be14 100644
--- a/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx
+++ b/packages/twenty-ui/src/testing/decorators/CatalogDecorator.tsx
@@ -1,7 +1,7 @@
-import { ComponentProps, JSX } from 'react';
import styled from '@emotion/styled';
import { isNumber, isString } from '@sniptt/guards';
import { Decorator } from '@storybook/react';
+import { ComponentProps, JSX } from 'react';
const StyledColumnTitle = styled.h1`
font-size: ${({ theme }) => theme.font.size.lg};
@@ -91,6 +91,8 @@ export type CatalogDimension<
export type CatalogOptions = {
elementContainer?: {
width?: number;
+ style?: React.CSSProperties;
+ className?: string;
};
};
@@ -135,6 +137,8 @@ export const CatalogDecorator: Decorator = (Story, context) => {