Improve the design of workflow nodes (#9810)
- Go over every node in the workflows and fix the styles to conform to Figma - Create stories for every node type
This commit is contained in:
committed by
GitHub
parent
337b6a86ab
commit
bbb0c9a761
@ -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 { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Handle, Position } from '@xyflow/react';
|
import { Handle, Position } from '@xyflow/react';
|
||||||
@ -21,7 +26,7 @@ const StyledStepNodeType = styled.div`
|
|||||||
${({ theme }) => theme.border.radius.sm} 0 0;
|
${({ theme }) => theme.border.radius.sm} 0 0;
|
||||||
|
|
||||||
color: ${({ theme }) => theme.font.color.light};
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: 9px;
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
|
||||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||||
@ -38,9 +43,8 @@ const StyledStepNodeType = styled.div`
|
|||||||
|
|
||||||
const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
|
const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
background-color: ${({ theme }) => theme.background.secondary};
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
border: ${NODE_BORDER_WIDTH}px solid
|
||||||
border-style: ${({ variant }) =>
|
${({ theme }) => theme.border.color.medium};
|
||||||
variant === 'placeholder' ? 'dashed' : null};
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
@ -61,7 +65,7 @@ const StyledStepNodeInnerContainer = styled.div<{ variant?: Variant }>`
|
|||||||
const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
|
const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: ${({ theme }) => theme.font.size.lg};
|
font-size: 13px;
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
column-gap: ${({ theme }) => theme.spacing(2)};
|
column-gap: ${({ theme }) => theme.spacing(2)};
|
||||||
color: ${({ variant, theme }) =>
|
color: ${({ variant, theme }) =>
|
||||||
@ -71,16 +75,19 @@ const StyledStepNodeLabel = styled.div<{ variant?: Variant }>`
|
|||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSourceHandle = styled(Handle)`
|
export const StyledHandle = styled(Handle)`
|
||||||
background-color: ${({ theme }) => theme.grayScale.gray25};
|
background-color: ${({ theme }) => theme.grayScale.gray25};
|
||||||
border: none;
|
border: none;
|
||||||
width: 4px;
|
width: ${NODE_HANDLE_WIDTH_PX}px;
|
||||||
height: 4px;
|
height: ${NODE_HANDLE_HEIGHT_PX}px;
|
||||||
left: ${({ theme }) => theme.spacing(10)};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledTargetHandle = styled(Handle)`
|
const StyledSourceHandle = styled(StyledHandle)`
|
||||||
left: ${({ theme }) => theme.spacing(10)};
|
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;
|
visibility: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -88,7 +95,7 @@ const StyledRightFloatingElementContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: ${({ theme }) => theme.spacing(-3)};
|
right: ${({ theme }) => theme.spacing(-4)};
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
|
|||||||
@ -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 styled from '@emotion/styled';
|
||||||
import { Handle, Position } from '@xyflow/react';
|
import { Position } from '@xyflow/react';
|
||||||
import { IconButton, IconPlus } from 'twenty-ui';
|
import { IconButton, IconPlus } from 'twenty-ui';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
padding-left: ${({ theme }) => theme.spacing(6)};
|
|
||||||
padding-top: ${({ theme }) => theme.spacing(1)};
|
padding-top: ${({ theme }) => theme.spacing(1)};
|
||||||
|
transform: translateX(-50%);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledTargetHandle = styled(Handle)`
|
const StyledTargetHandle = styled(StyledHandle)`
|
||||||
left: ${({ theme }) => theme.spacing(10)};
|
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,10 @@ export const WorkflowDiagramEmptyTrigger = () => {
|
|||||||
variant="placeholder"
|
variant="placeholder"
|
||||||
Icon={
|
Icon={
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<IconPlaylistAdd size={16} color={theme.font.color.tertiary} />
|
<IconPlaylistAdd
|
||||||
|
size={theme.icon.size.md}
|
||||||
|
color={theme.font.color.tertiary}
|
||||||
|
/>
|
||||||
</StyledStepNodeLabelIconContainer>
|
</StyledStepNodeLabelIconContainer>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
return (
|
return (
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<Icon
|
<Icon
|
||||||
size={theme.icon.size.lg}
|
size={theme.icon.size.md}
|
||||||
color={theme.font.color.tertiary}
|
color={theme.font.color.tertiary}
|
||||||
/>
|
/>
|
||||||
</StyledStepNodeLabelIconContainer>
|
</StyledStepNodeLabelIconContainer>
|
||||||
@ -43,7 +43,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
return (
|
return (
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<Icon
|
<Icon
|
||||||
size={theme.icon.size.lg}
|
size={theme.icon.size.md}
|
||||||
color={theme.font.color.tertiary}
|
color={theme.font.color.tertiary}
|
||||||
/>
|
/>
|
||||||
</StyledStepNodeLabelIconContainer>
|
</StyledStepNodeLabelIconContainer>
|
||||||
@ -58,14 +58,18 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
case 'CODE': {
|
case 'CODE': {
|
||||||
return (
|
return (
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<Icon size={theme.icon.size.lg} color={theme.color.orange} />
|
<Icon
|
||||||
|
size={theme.icon.size.md}
|
||||||
|
color={theme.color.orange}
|
||||||
|
stroke={theme.icon.stroke.sm}
|
||||||
|
/>
|
||||||
</StyledStepNodeLabelIconContainer>
|
</StyledStepNodeLabelIconContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'SEND_EMAIL': {
|
case 'SEND_EMAIL': {
|
||||||
return (
|
return (
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<Icon size={theme.icon.size.lg} color={theme.color.blue} />
|
<Icon size={theme.icon.size.md} color={theme.color.blue} />
|
||||||
</StyledStepNodeLabelIconContainer>
|
</StyledStepNodeLabelIconContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -75,7 +79,7 @@ export const WorkflowDiagramStepNodeBase = ({
|
|||||||
return (
|
return (
|
||||||
<StyledStepNodeLabelIconContainer>
|
<StyledStepNodeLabelIconContainer>
|
||||||
<Icon
|
<Icon
|
||||||
size={theme.icon.size.lg}
|
size={theme.icon.size.md}
|
||||||
color={theme.font.color.tertiary}
|
color={theme.font.color.tertiary}
|
||||||
stroke={theme.icon.stroke.sm}
|
stroke={theme.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||||
import { assertWorkflowWithCurrentVersionIsDefined } from '@/workflow/utils/assertWorkflowWithCurrentVersionIsDefined';
|
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 { WorkflowDiagramStepNodeData } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
import { useDeleteStep } from '@/workflow/workflow-steps/hooks/useDeleteStep';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { FloatingIconButton, IconTrash } from 'twenty-ui';
|
|
||||||
|
|
||||||
export const WorkflowDiagramStepNodeEditable = ({
|
export const WorkflowDiagramStepNodeEditable = ({
|
||||||
id,
|
id,
|
||||||
@ -26,19 +25,12 @@ export const WorkflowDiagramStepNodeEditable = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkflowDiagramStepNodeBase
|
<WorkflowDiagramStepNodeEditableContent
|
||||||
data={data}
|
data={data}
|
||||||
RightFloatingElement={
|
selected={selected ?? false}
|
||||||
selected ? (
|
onDelete={() => {
|
||||||
<FloatingIconButton
|
deleteStep(id);
|
||||||
size="medium"
|
}}
|
||||||
Icon={IconTrash}
|
|
||||||
onClick={() => {
|
|
||||||
deleteStep(id);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 (
|
||||||
|
<WorkflowDiagramStepNodeBase
|
||||||
|
data={data}
|
||||||
|
RightFloatingElement={
|
||||||
|
selected ? (
|
||||||
|
<FloatingIconButton
|
||||||
|
size="medium"
|
||||||
|
Icon={IconTrash}
|
||||||
|
onClick={onDelete}
|
||||||
|
/>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -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<typeof WorkflowDiagramCreateStepNode> = {
|
||||||
|
title: 'Modules/Workflow/WorkflowDiagramCreateStepNode',
|
||||||
|
component: WorkflowDiagramCreateStepNode,
|
||||||
|
decorators: [
|
||||||
|
ComponentDecorator,
|
||||||
|
(Story) => (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<Story />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof WorkflowDiagramCreateStepNode>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Selected: Story = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<div className="selectable selected" style={{ position: 'relative' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -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<typeof WorkflowDiagramEmptyTrigger> = {
|
||||||
|
title: 'Modules/Workflow/WorkflowDiagramEmptyTrigger',
|
||||||
|
component: WorkflowDiagramEmptyTrigger,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof WorkflowDiagramEmptyTrigger>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<div style={{ position: 'relative' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
</ReactFlowProvider>
|
||||||
|
),
|
||||||
|
ComponentDecorator,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Selected: Story = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<div className="selectable selected" style={{ position: 'relative' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
(Story) => (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<Story />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
),
|
||||||
|
ComponentDecorator,
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -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<typeof WorkflowDiagramStepNodeEditableContent> = {
|
||||||
|
title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent',
|
||||||
|
component: WorkflowDiagramStepNodeEditableContent,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof WorkflowDiagramStepNodeEditableContent>;
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<Story />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
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 (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<Story />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const NODE_BORDER_WIDTH = 1;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { NODE_HANDLE_WIDTH_PX } from './NodeHandleWidthPx';
|
||||||
|
|
||||||
|
export const NODE_HANDLE_HEIGHT_PX = NODE_HANDLE_WIDTH_PX;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const NODE_HANDLE_WIDTH_PX = 4;
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { THEME_COMMON } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const NODE_ICON_LEFT_MARGIN = Number(
|
||||||
|
THEME_COMMON.spacing(2).replace('px', ''),
|
||||||
|
);
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { THEME_COMMON } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const NODE_ICON_WIDTH = Number(
|
||||||
|
THEME_COMMON.spacing(6).replace('px', ''),
|
||||||
|
);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { ComponentProps, JSX } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNumber, isString } from '@sniptt/guards';
|
import { isNumber, isString } from '@sniptt/guards';
|
||||||
import { Decorator } from '@storybook/react';
|
import { Decorator } from '@storybook/react';
|
||||||
|
import { ComponentProps, JSX } from 'react';
|
||||||
|
|
||||||
const StyledColumnTitle = styled.h1`
|
const StyledColumnTitle = styled.h1`
|
||||||
font-size: ${({ theme }) => theme.font.size.lg};
|
font-size: ${({ theme }) => theme.font.size.lg};
|
||||||
@ -91,6 +91,8 @@ export type CatalogDimension<
|
|||||||
export type CatalogOptions = {
|
export type CatalogOptions = {
|
||||||
elementContainer?: {
|
elementContainer?: {
|
||||||
width?: number;
|
width?: number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,6 +137,8 @@ export const CatalogDecorator: Decorator = (Story, context) => {
|
|||||||
</StyledElementTitle>
|
</StyledElementTitle>
|
||||||
<StyledElementContainer
|
<StyledElementContainer
|
||||||
width={options?.elementContainer?.width}
|
width={options?.elementContainer?.width}
|
||||||
|
style={options?.elementContainer?.style}
|
||||||
|
className={options?.elementContainer?.className}
|
||||||
>
|
>
|
||||||
<Story
|
<Story
|
||||||
args={{
|
args={{
|
||||||
|
|||||||
Reference in New Issue
Block a user