Add the new workflow not executed node type (#10030)
- Added the new workflow `not executed` node type - Fixed minor style issues - Created one big catalog for all node variants 
This commit is contained in:
committed by
GitHub
parent
5528577707
commit
700eb2d473
@ -50,18 +50,16 @@ const StyledStepNodeType = styled.div<{
|
|||||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
||||||
|
|
||||||
.selectable.selected &,
|
.selectable:is(.selected, :focus, :focus-visible) & {
|
||||||
.selectable:focus &,
|
|
||||||
.selectable:focus-visible & {
|
|
||||||
${({ nodeVariant, theme }) => {
|
${({ nodeVariant, theme }) => {
|
||||||
switch (nodeVariant) {
|
switch (nodeVariant) {
|
||||||
case 'empty':
|
case 'empty':
|
||||||
case 'default': {
|
case 'default':
|
||||||
|
case 'not-executed':
|
||||||
return css`
|
return css`
|
||||||
background-color: ${theme.color.blue};
|
background-color: ${theme.color.blue};
|
||||||
color: ${theme.font.color.inverted};
|
color: ${theme.font.color.inverted};
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -70,7 +68,7 @@ const StyledStepNodeType = styled.div<{
|
|||||||
const StyledStepNodeInnerContainer = styled.div<{
|
const StyledStepNodeInnerContainer = styled.div<{
|
||||||
variant: WorkflowDiagramNodeVariant;
|
variant: WorkflowDiagramNodeVariant;
|
||||||
}>`
|
}>`
|
||||||
background-color: ${({ theme }) => theme.background.secondary};
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
border-color: ${({ theme }) => theme.border.color.medium};
|
border-color: ${({ theme }) => theme.border.color.medium};
|
||||||
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
@ -84,26 +82,41 @@ const StyledStepNodeInnerContainer = styled.div<{
|
|||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.selectable.selected &,
|
transition: background ${({ theme }) => theme.animation.duration.fast} ease;
|
||||||
.selectable:focus &,
|
|
||||||
.selectable:focus-visible & {
|
.workflow-node-container:hover & {
|
||||||
|
${({ theme }) => {
|
||||||
|
return css`
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
${theme.background.transparent.lighter} 0%,
|
||||||
|
${theme.background.transparent.lighter} 100%
|
||||||
|
),
|
||||||
|
${theme.background.secondary};
|
||||||
|
`;
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectable:is(.selected, :focus, :focus-visible)
|
||||||
|
:is(.workflow-node-container, .workflow-node-container:hover)
|
||||||
|
& {
|
||||||
${({ theme, variant }) => {
|
${({ theme, variant }) => {
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
case 'success': {
|
case 'success': {
|
||||||
return css`
|
return css`
|
||||||
background-color: ${theme.adaptiveColors.turquoise1};
|
background: ${theme.adaptiveColors.turquoise1};
|
||||||
border-color: ${theme.adaptiveColors.turquoise4};
|
border-color: ${theme.adaptiveColors.turquoise4};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
case 'failure': {
|
case 'failure': {
|
||||||
return css`
|
return css`
|
||||||
background-color: ${theme.background.danger};
|
background: ${theme.background.danger};
|
||||||
border-color: ${theme.color.red};
|
border-color: ${theme.color.red};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return css`
|
return css`
|
||||||
background-color: ${theme.accent.quaternary};
|
background: ${theme.adaptiveColors.blue1};
|
||||||
border-color: ${theme.color.blue};
|
border-color: ${theme.color.blue};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -120,11 +133,20 @@ const StyledStepNodeLabel = styled.div<{
|
|||||||
font-size: 13px;
|
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 }) => {
|
||||||
variant === 'empty'
|
switch (variant) {
|
||||||
? theme.font.color.extraLight
|
case 'empty':
|
||||||
: theme.font.color.primary};
|
case 'not-executed':
|
||||||
|
return theme.font.color.light;
|
||||||
|
default:
|
||||||
|
return theme.font.color.primary;
|
||||||
|
}
|
||||||
|
}};
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
|
|
||||||
|
.selectable:is(.selected, :focus, :focus-visible) & {
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledHandle = styled(Handle)`
|
export const StyledHandle = styled(Handle)`
|
||||||
@ -168,7 +190,7 @@ export const WorkflowDiagramBaseStepNode = ({
|
|||||||
RightFloatingElement?: React.ReactNode;
|
RightFloatingElement?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<StyledStepNodeContainer>
|
<StyledStepNodeContainer className="workflow-node-container">
|
||||||
{nodeType !== 'trigger' ? (
|
{nodeType !== 'trigger' ? (
|
||||||
<StyledTargetHandle type="target" position={Position.Top} />
|
<StyledTargetHandle type="target" position={Position.Top} />
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -1,21 +1,33 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
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 { fn } from '@storybook/test';
|
import { fn } from '@storybook/test';
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
|
import { ComponentProps } from 'react';
|
||||||
import { CatalogDecorator, CatalogStory } from 'twenty-ui';
|
import { CatalogDecorator, CatalogStory } from 'twenty-ui';
|
||||||
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
import { WorkflowDiagramStepNodeEditableContent } from '../WorkflowDiagramStepNodeEditableContent';
|
import { WorkflowDiagramStepNodeEditableContent } from '../WorkflowDiagramStepNodeEditableContent';
|
||||||
|
|
||||||
const meta: Meta<typeof WorkflowDiagramStepNodeEditableContent> = {
|
type ComponentState = 'default' | 'hover' | 'selected';
|
||||||
|
|
||||||
|
type WrapperProps = ComponentProps<
|
||||||
|
typeof WorkflowDiagramStepNodeEditableContent
|
||||||
|
> & { state: ComponentState };
|
||||||
|
|
||||||
|
const Wrapper = (_props: WrapperProps) => {
|
||||||
|
return <div></div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const meta: Meta<WrapperProps> = {
|
||||||
title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent',
|
title: 'Modules/Workflow/WorkflowDiagramStepNodeEditableContent',
|
||||||
component: WorkflowDiagramStepNodeEditableContent,
|
component: WorkflowDiagramStepNodeEditableContent,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
|
||||||
type Story = StoryObj<typeof WorkflowDiagramStepNodeEditableContent>;
|
type Story = StoryObj<typeof Wrapper>;
|
||||||
|
|
||||||
const ALL_STEPS = [
|
const ALL_STEPS = [
|
||||||
{
|
{
|
||||||
@ -47,17 +59,13 @@ const ALL_STEPS = [
|
|||||||
{ nodeType: 'action', actionType: 'CODE', name: 'Code' },
|
{ nodeType: 'action', actionType: 'CODE', name: 'Code' },
|
||||||
] satisfies WorkflowDiagramStepNodeData[];
|
] satisfies WorkflowDiagramStepNodeData[];
|
||||||
|
|
||||||
export const All: CatalogStory<
|
export const Catalog: CatalogStory<Story, typeof Wrapper> = {
|
||||||
Story,
|
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
|
||||||
> = {
|
|
||||||
args: {
|
args: {
|
||||||
onDelete: fn(),
|
onDelete: fn(),
|
||||||
variant: 'default',
|
|
||||||
selected: false,
|
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
msw: graphqlMocks,
|
msw: graphqlMocks,
|
||||||
|
pseudo: { hover: ['.hover'] },
|
||||||
catalog: {
|
catalog: {
|
||||||
options: {
|
options: {
|
||||||
elementContainer: {
|
elementContainer: {
|
||||||
@ -71,159 +79,36 @@ export const All: CatalogStory<
|
|||||||
values: ALL_STEPS,
|
values: ALL_STEPS,
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AllSelected: CatalogStory<
|
|
||||||
Story,
|
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
|
||||||
> = {
|
|
||||||
args: {
|
|
||||||
onDelete: fn(),
|
|
||||||
variant: 'default',
|
|
||||||
selected: true,
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
catalog: {
|
|
||||||
options: {
|
|
||||||
elementContainer: {
|
|
||||||
width: 250,
|
|
||||||
style: { position: 'relative' },
|
|
||||||
className: 'selectable selected',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dimensions: [
|
|
||||||
{
|
{
|
||||||
name: 'step type',
|
name: 'variant',
|
||||||
values: ALL_STEPS,
|
values: [
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
'empty',
|
||||||
|
'default',
|
||||||
|
'success',
|
||||||
|
'failure',
|
||||||
|
'not-executed',
|
||||||
|
] satisfies WorkflowDiagramNodeVariant[],
|
||||||
|
props: (variant: WorkflowDiagramNodeVariant) => ({ variant }),
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AllSuccess: CatalogStory<
|
|
||||||
Story,
|
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
|
||||||
> = {
|
|
||||||
args: {
|
|
||||||
onDelete: fn(),
|
|
||||||
variant: 'success',
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
catalog: {
|
|
||||||
options: {
|
|
||||||
elementContainer: {
|
|
||||||
width: 250,
|
|
||||||
style: { position: 'relative' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dimensions: [
|
|
||||||
{
|
{
|
||||||
name: 'step type',
|
name: 'state',
|
||||||
values: ALL_STEPS,
|
values: ['default', 'hover', 'selected'] satisfies ComponentState[],
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
props: (state: ComponentState) => ({ state }),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
decorators: [
|
||||||
};
|
(Story, { args }) => {
|
||||||
|
return (
|
||||||
export const AllSuccessSelected: CatalogStory<
|
<div
|
||||||
Story,
|
className={`selectable ${args.state === 'selected' ? 'selected' : args.state === 'hover' ? 'workflow-node-container hover' : ''}`}
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
>
|
||||||
> = {
|
<Story />
|
||||||
args: {
|
</div>
|
||||||
onDelete: fn(),
|
);
|
||||||
variant: 'success',
|
|
||||||
selected: true,
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
catalog: {
|
|
||||||
options: {
|
|
||||||
elementContainer: {
|
|
||||||
width: 250,
|
|
||||||
style: { position: 'relative' },
|
|
||||||
className: 'selectable selected',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dimensions: [
|
|
||||||
{
|
|
||||||
name: 'step type',
|
|
||||||
values: ALL_STEPS,
|
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
CatalogDecorator,
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
ReactflowDecorator,
|
||||||
};
|
],
|
||||||
|
|
||||||
export const AllFailure: CatalogStory<
|
|
||||||
Story,
|
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
|
||||||
> = {
|
|
||||||
args: {
|
|
||||||
onDelete: fn(),
|
|
||||||
variant: 'failure',
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
catalog: {
|
|
||||||
options: {
|
|
||||||
elementContainer: {
|
|
||||||
width: 250,
|
|
||||||
style: { position: 'relative' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dimensions: [
|
|
||||||
{
|
|
||||||
name: 'step type',
|
|
||||||
values: ALL_STEPS,
|
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AllFailureSelected: CatalogStory<
|
|
||||||
Story,
|
|
||||||
typeof WorkflowDiagramStepNodeEditableContent
|
|
||||||
> = {
|
|
||||||
args: {
|
|
||||||
onDelete: fn(),
|
|
||||||
variant: 'failure',
|
|
||||||
selected: true,
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
catalog: {
|
|
||||||
options: {
|
|
||||||
elementContainer: {
|
|
||||||
width: 250,
|
|
||||||
style: { position: 'relative' },
|
|
||||||
className: 'selectable selected',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dimensions: [
|
|
||||||
{
|
|
||||||
name: 'step type',
|
|
||||||
values: ALL_STEPS,
|
|
||||||
props: (data: WorkflowDiagramStepNodeData) => ({ data }),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
decorators: [CatalogDecorator, ReactflowDecorator],
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,4 +2,5 @@ export type WorkflowDiagramNodeVariant =
|
|||||||
| 'default'
|
| 'default'
|
||||||
| 'success'
|
| 'success'
|
||||||
| 'failure'
|
| 'failure'
|
||||||
| 'empty';
|
| 'empty'
|
||||||
|
| 'not-executed';
|
||||||
|
|||||||
@ -5,4 +5,8 @@ export const ADAPTIVE_COLORS_DARK = {
|
|||||||
turquoise2: THEME_COMMON.color.turquoise70,
|
turquoise2: THEME_COMMON.color.turquoise70,
|
||||||
turquoise3: THEME_COMMON.color.turquoise60,
|
turquoise3: THEME_COMMON.color.turquoise60,
|
||||||
turquoise4: THEME_COMMON.color.turquoise50,
|
turquoise4: THEME_COMMON.color.turquoise50,
|
||||||
|
blue1: THEME_COMMON.color.blue80,
|
||||||
|
blue2: THEME_COMMON.color.blue70,
|
||||||
|
blue3: THEME_COMMON.color.blue60,
|
||||||
|
blue4: THEME_COMMON.color.blue50,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,4 +5,8 @@ export const ADAPTIVE_COLORS_LIGHT = {
|
|||||||
turquoise2: THEME_COMMON.color.turquoise20,
|
turquoise2: THEME_COMMON.color.turquoise20,
|
||||||
turquoise3: THEME_COMMON.color.turquoise30,
|
turquoise3: THEME_COMMON.color.turquoise30,
|
||||||
turquoise4: THEME_COMMON.color.turquoise40,
|
turquoise4: THEME_COMMON.color.turquoise40,
|
||||||
|
blue1: THEME_COMMON.color.blue10,
|
||||||
|
blue2: THEME_COMMON.color.blue20,
|
||||||
|
blue3: THEME_COMMON.color.blue30,
|
||||||
|
blue4: THEME_COMMON.color.blue40,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user