Add workflow success edge (#10120)
- Refactor the handles: the source handles are now part of the edges as markerStart - **As the source handles are now part of the edges, we can delete the `markLeafNodes` logic; this can be done in another PR**. See https://github.com/twentyhq/core-team-issues/issues/386 - Create a custom edge component for the default edge - Create a custom edge component for the success edge; this includes a label **The edges can be tested in Storybook. I wrote two stories for the edges.** | Default | Success | |--------|--------| |  |  |
This commit is contained in:
committed by
GitHub
parent
4f06b83d7f
commit
179d3ae2a4
@ -28,7 +28,9 @@ test('Create workflow', async ({ page }) => {
|
|||||||
|
|
||||||
const nameInput = page.getByRole('textbox');
|
const nameInput = page.getByRole('textbox');
|
||||||
await nameInput.fill(NEW_WORKFLOW_NAME);
|
await nameInput.fill(NEW_WORKFLOW_NAME);
|
||||||
await nameInput.press('Enter');
|
|
||||||
|
const workflowDiagramContainer = page.locator('.react-flow__renderer');
|
||||||
|
await workflowDiagramContainer.click();
|
||||||
|
|
||||||
const body = await createWorkflowResponse.json();
|
const body = await createWorkflowResponse.json();
|
||||||
const newWorkflowId = body.data.createWorkflow.id;
|
const newWorkflowId = body.data.createWorkflow.id;
|
||||||
|
|||||||
@ -80,7 +80,7 @@ export const CardComponents: Record<CardType, CardComponentType> = {
|
|||||||
[CardType.WorkflowCard]: ({ targetableObject }) => (
|
[CardType.WorkflowCard]: ({ targetableObject }) => (
|
||||||
<>
|
<>
|
||||||
<WorkflowVisualizerEffect workflowId={targetableObject.id} />
|
<WorkflowVisualizerEffect workflowId={targetableObject.id} />
|
||||||
<WorkflowVisualizer targetableObject={targetableObject} />
|
<WorkflowVisualizer workflowId={targetableObject.id} />
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { workflowDiagramState } from '@/workflow/workflow-diagram/states/workflo
|
|||||||
import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState';
|
import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState';
|
||||||
import {
|
import {
|
||||||
WorkflowDiagramEdge,
|
WorkflowDiagramEdge,
|
||||||
|
WorkflowDiagramEdgeType,
|
||||||
WorkflowDiagramNode,
|
WorkflowDiagramNode,
|
||||||
WorkflowDiagramNodeType,
|
WorkflowDiagramNodeType,
|
||||||
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
} from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
@ -17,6 +18,7 @@ import styled from '@emotion/styled';
|
|||||||
import {
|
import {
|
||||||
Background,
|
Background,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
|
EdgeProps,
|
||||||
FitViewOptions,
|
FitViewOptions,
|
||||||
NodeChange,
|
NodeChange,
|
||||||
NodeProps,
|
NodeProps,
|
||||||
@ -61,8 +63,6 @@ const StyledResetReactflowStyles = styled.div`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
--xy-edge-stroke: ${({ theme }) => theme.border.color.strong};
|
|
||||||
|
|
||||||
--xy-node-border-radius: none;
|
--xy-node-border-radius: none;
|
||||||
--xy-node-border: none;
|
--xy-node-border: none;
|
||||||
--xy-node-background-color: none;
|
--xy-node-background-color: none;
|
||||||
@ -85,6 +85,7 @@ const defaultFitViewOptions = {
|
|||||||
export const WorkflowDiagramCanvasBase = ({
|
export const WorkflowDiagramCanvasBase = ({
|
||||||
status,
|
status,
|
||||||
nodeTypes,
|
nodeTypes,
|
||||||
|
edgeTypes,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
status: WorkflowVersionStatus;
|
status: WorkflowVersionStatus;
|
||||||
@ -99,6 +100,17 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
>
|
>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
edgeTypes: Partial<
|
||||||
|
Record<
|
||||||
|
WorkflowDiagramEdgeType,
|
||||||
|
React.ComponentType<
|
||||||
|
EdgeProps & {
|
||||||
|
data: any;
|
||||||
|
type: any;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -223,6 +235,7 @@ export const WorkflowDiagramCanvasBase = ({
|
|||||||
minZoom={defaultFitViewOptions.minZoom}
|
minZoom={defaultFitViewOptions.minZoom}
|
||||||
maxZoom={defaultFitViewOptions.maxZoom}
|
maxZoom={defaultFitViewOptions.maxZoom}
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
|
edgeTypes={edgeTypes}
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={handleNodesChange}
|
onNodesChange={handleNodesChange}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
|||||||
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 { WorkflowDiagramCreateStepNode } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode';
|
import { WorkflowDiagramCreateStepNode } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode';
|
||||||
|
import { WorkflowDiagramDefaultEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdge';
|
||||||
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
||||||
import { WorkflowDiagramStepNodeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable';
|
import { WorkflowDiagramStepNodeEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeEditable';
|
||||||
import { ReactFlowProvider } from '@xyflow/react';
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
@ -20,6 +21,9 @@ export const WorkflowDiagramCanvasEditable = ({
|
|||||||
'create-step': WorkflowDiagramCreateStepNode,
|
'create-step': WorkflowDiagramCreateStepNode,
|
||||||
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
||||||
}}
|
}}
|
||||||
|
edgeTypes={{
|
||||||
|
default: WorkflowDiagramDefaultEdge,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<WorkflowDiagramCanvasEditableEffect />
|
<WorkflowDiagramCanvasEditableEffect />
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { WorkflowVersion } from '@/workflow/types/Workflow';
|
import { WorkflowVersion } 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 { WorkflowDiagramCanvasReadonlyEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasReadonlyEffect';
|
||||||
|
import { WorkflowDiagramDefaultEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdge';
|
||||||
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
||||||
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
||||||
|
import { WorkflowDiagramSuccessEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramSuccessEdge';
|
||||||
import { ReactFlowProvider } from '@xyflow/react';
|
import { ReactFlowProvider } from '@xyflow/react';
|
||||||
|
|
||||||
export const WorkflowDiagramCanvasReadonly = ({
|
export const WorkflowDiagramCanvasReadonly = ({
|
||||||
@ -18,6 +20,10 @@ export const WorkflowDiagramCanvasReadonly = ({
|
|||||||
default: WorkflowDiagramStepNodeReadonly,
|
default: WorkflowDiagramStepNodeReadonly,
|
||||||
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
||||||
}}
|
}}
|
||||||
|
edgeTypes={{
|
||||||
|
default: WorkflowDiagramDefaultEdge,
|
||||||
|
success: WorkflowDiagramSuccessEdge,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<WorkflowDiagramCanvasReadonlyEffect />
|
<WorkflowDiagramCanvasReadonlyEffect />
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
|
import { EDGE_GRAY_CIRCLE_MARKED_ID } from '@/workflow/workflow-diagram/constants/EdgeGrayCircleMarkedId';
|
||||||
|
import { EDGE_GREEN_CIRCLE_MARKED_ID } from '@/workflow/workflow-diagram/constants/EdgeGreenCircleMarkedId';
|
||||||
|
import { EDGE_GREEN_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeGreenRoundedArrowMarkerId';
|
||||||
|
import { EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX } from '@/workflow/workflow-diagram/constants/EdgeGreenRoundedArrowMarkerWidthPx';
|
||||||
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
|
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
|
||||||
|
import { NODE_HANDLE_HEIGHT_PX } from '@/workflow/workflow-diagram/constants/NodeHandleHeightPx';
|
||||||
|
import { NODE_HANDLE_WIDTH_PX } from '@/workflow/workflow-diagram/constants/NodeHandleWidthPx';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
export const WorkflowDiagramCustomMarkers = () => {
|
export const WorkflowDiagramCustomMarkers = () => {
|
||||||
@ -19,6 +25,53 @@ export const WorkflowDiagramCustomMarkers = () => {
|
|||||||
fill={theme.border.color.strong}
|
fill={theme.border.color.strong}
|
||||||
/>
|
/>
|
||||||
</marker>
|
</marker>
|
||||||
|
|
||||||
|
<marker
|
||||||
|
id={EDGE_GREEN_ROUNDED_ARROW_MARKER_ID}
|
||||||
|
markerHeight={5}
|
||||||
|
markerWidth={EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX}
|
||||||
|
refX={EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX / 2}
|
||||||
|
refY={2.5}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0.31094 1.1168C0.178029 0.917434 0.320947 0.650391 0.560555 0.650391H5.43945C5.67905 0.650391 5.82197 0.917434 5.68906 1.1168L3.62404 4.21433C3.32717 4.65963 2.67283 4.65963 2.37596 4.21433L0.31094 1.1168Z"
|
||||||
|
fill={theme.tag.text.turquoise}
|
||||||
|
/>
|
||||||
|
</marker>
|
||||||
|
|
||||||
|
<marker
|
||||||
|
markerHeight={NODE_HANDLE_HEIGHT_PX}
|
||||||
|
markerWidth={NODE_HANDLE_WIDTH_PX}
|
||||||
|
refX={NODE_HANDLE_WIDTH_PX / 2}
|
||||||
|
refY={NODE_HANDLE_HEIGHT_PX}
|
||||||
|
id={EDGE_GRAY_CIRCLE_MARKED_ID}
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
height={NODE_HANDLE_HEIGHT_PX}
|
||||||
|
width={NODE_HANDLE_WIDTH_PX}
|
||||||
|
rx="2"
|
||||||
|
fill={theme.border.color.strong}
|
||||||
|
/>
|
||||||
|
</marker>
|
||||||
|
|
||||||
|
<marker
|
||||||
|
markerHeight={5}
|
||||||
|
markerWidth={5}
|
||||||
|
refX={2}
|
||||||
|
refY={2.5}
|
||||||
|
id={EDGE_GREEN_CIRCLE_MARKED_ID}
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
x={0.5}
|
||||||
|
y={0.5}
|
||||||
|
height={3}
|
||||||
|
width={3}
|
||||||
|
rx="1.5"
|
||||||
|
fill="white"
|
||||||
|
stroke={theme.tag.text.turquoise}
|
||||||
|
strokeWidth={1}
|
||||||
|
/>
|
||||||
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import { BaseEdge, EdgeProps, getStraightPath } from '@xyflow/react';
|
||||||
|
|
||||||
|
type WorkflowDiagramDefaultEdgeProps = EdgeProps;
|
||||||
|
|
||||||
|
export const WorkflowDiagramDefaultEdge = ({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
markerStart,
|
||||||
|
markerEnd,
|
||||||
|
}: WorkflowDiagramDefaultEdgeProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const [edgePath] = getStraightPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseEdge
|
||||||
|
markerStart={markerStart}
|
||||||
|
markerEnd={markerEnd}
|
||||||
|
path={edgePath}
|
||||||
|
style={{ stroke: theme.border.color.strong }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -150,15 +150,13 @@ const StyledStepNodeLabel = styled.div<{
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledHandle = styled(Handle)`
|
export const StyledHandle = styled(Handle)`
|
||||||
background-color: ${({ theme }) => theme.grayScale.gray25};
|
|
||||||
border: none;
|
|
||||||
width: ${NODE_HANDLE_WIDTH_PX}px;
|
|
||||||
height: ${NODE_HANDLE_HEIGHT_PX}px;
|
height: ${NODE_HANDLE_HEIGHT_PX}px;
|
||||||
|
width: ${NODE_HANDLE_WIDTH_PX}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSourceHandle = styled(StyledHandle)`
|
const StyledSourceHandle = styled(StyledHandle)`
|
||||||
background-color: ${({ theme }) => theme.border.color.strong};
|
|
||||||
left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
|
left: ${NODE_ICON_WIDTH + NODE_ICON_LEFT_MARGIN + NODE_BORDER_WIDTH}px;
|
||||||
|
visibility: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledTargetHandle = styled(StyledSourceHandle)`
|
const StyledTargetHandle = styled(StyledSourceHandle)`
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
import { EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX } from '@/workflow/workflow-diagram/constants/EdgeGreenRoundedArrowMarkerWidthPx';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import {
|
||||||
|
BaseEdge,
|
||||||
|
EdgeLabelRenderer,
|
||||||
|
EdgeProps,
|
||||||
|
getStraightPath,
|
||||||
|
} from '@xyflow/react';
|
||||||
|
import { Label } from 'twenty-ui';
|
||||||
|
|
||||||
|
const StyledLabel = styled(Label)`
|
||||||
|
color: ${({ theme }) => theme.tag.text.turquoise};
|
||||||
|
`;
|
||||||
|
|
||||||
|
type WorkflowDiagramSuccessEdgeProps = EdgeProps;
|
||||||
|
|
||||||
|
export const WorkflowDiagramSuccessEdge = ({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
markerStart,
|
||||||
|
markerEnd,
|
||||||
|
label,
|
||||||
|
}: WorkflowDiagramSuccessEdgeProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const [edgePath, labelX, labelY] = getStraightPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BaseEdge
|
||||||
|
markerStart={markerStart}
|
||||||
|
markerEnd={markerEnd}
|
||||||
|
path={edgePath}
|
||||||
|
style={{ stroke: theme.tag.text.turquoise }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EdgeLabelRenderer>
|
||||||
|
<StyledLabel
|
||||||
|
variant="small"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
transform: `translate(0, -50%) translate(${labelX}px, ${labelY}px) translateX(${EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX / 2 + 3}px)`,
|
||||||
|
pointerEvents: 'all',
|
||||||
|
}}
|
||||||
|
className="nodrag nopan"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</StyledLabel>
|
||||||
|
</EdgeLabelRenderer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,17 +1,10 @@
|
|||||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { WorkflowDiagramCanvasEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable';
|
import { WorkflowDiagramCanvasEditable } from '@/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditable';
|
||||||
import { WorkflowDiagramEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramEffect';
|
import { WorkflowDiagramEffect } from '@/workflow/workflow-diagram/components/WorkflowDiagramEffect';
|
||||||
import '@xyflow/react/dist/style.css';
|
import '@xyflow/react/dist/style.css';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const WorkflowVisualizer = ({
|
export const WorkflowVisualizer = ({ workflowId }: { workflowId: string }) => {
|
||||||
targetableObject,
|
|
||||||
}: {
|
|
||||||
targetableObject: ActivityTargetableObject;
|
|
||||||
}) => {
|
|
||||||
const workflowId = targetableObject.id;
|
|
||||||
|
|
||||||
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -0,0 +1,178 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
|
import { WorkflowDiagramCreateStepNode } from '@/workflow/workflow-diagram/components/WorkflowDiagramCreateStepNode';
|
||||||
|
import { WorkflowDiagramDefaultEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramDefaultEdge';
|
||||||
|
import { WorkflowDiagramEmptyTrigger } from '@/workflow/workflow-diagram/components/WorkflowDiagramEmptyTrigger';
|
||||||
|
import { WorkflowDiagramStepNodeReadonly } from '@/workflow/workflow-diagram/components/WorkflowDiagramStepNodeReadonly';
|
||||||
|
import { WorkflowDiagramSuccessEdge } from '@/workflow/workflow-diagram/components/WorkflowDiagramSuccessEdge';
|
||||||
|
import { WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeDefaultConfiguration';
|
||||||
|
import { WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION } from '@/workflow/workflow-diagram/constants/WorkflowVisualizerEdgeSuccessConfiguration';
|
||||||
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
|
import { ReactflowDecorator } from '~/testing/decorators/ReactflowDecorator';
|
||||||
|
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||||
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
import { workflowDiagramState } from '../../states/workflowDiagramState';
|
||||||
|
import { WorkflowDiagramCanvasBase } from '../WorkflowDiagramCanvasBase';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
height: 400px;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const meta: Meta = {
|
||||||
|
title: 'Modules/Workflow/WorkflowDiagram/WorkflowDiagramCustomMarkers',
|
||||||
|
component: WorkflowDiagramCanvasBase,
|
||||||
|
parameters: {
|
||||||
|
msw: graphqlMocks,
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
WorkspaceDecorator,
|
||||||
|
ObjectMetadataItemsDecorator,
|
||||||
|
ReactflowDecorator,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof WorkflowDiagramCanvasBase>;
|
||||||
|
|
||||||
|
export const DefaultEdge: Story = {
|
||||||
|
args: {
|
||||||
|
status: 'DRAFT',
|
||||||
|
nodeTypes: {
|
||||||
|
default: WorkflowDiagramStepNodeReadonly,
|
||||||
|
'create-step': WorkflowDiagramCreateStepNode,
|
||||||
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
||||||
|
},
|
||||||
|
edgeTypes: {
|
||||||
|
default: WorkflowDiagramDefaultEdge,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={({ set }) => {
|
||||||
|
set(workflowDiagramState, {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'trigger-1',
|
||||||
|
type: 'default',
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
data: {
|
||||||
|
nodeType: 'trigger',
|
||||||
|
triggerType: 'DATABASE_EVENT',
|
||||||
|
name: 'When record is created',
|
||||||
|
isLeafNode: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'action-1',
|
||||||
|
type: 'default',
|
||||||
|
position: { x: 300, y: 100 },
|
||||||
|
data: {
|
||||||
|
nodeType: 'action',
|
||||||
|
actionType: 'CREATE_RECORD',
|
||||||
|
name: 'Create record',
|
||||||
|
isLeafNode: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'create-step-1',
|
||||||
|
type: 'create-step',
|
||||||
|
position: { x: 500, y: 100 },
|
||||||
|
data: {
|
||||||
|
nodeType: 'create-step',
|
||||||
|
parentNodeId: 'action-1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
|
||||||
|
id: 'edge-1',
|
||||||
|
source: 'trigger-1',
|
||||||
|
target: 'action-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION,
|
||||||
|
id: 'edge-2',
|
||||||
|
source: 'action-1',
|
||||||
|
target: 'create-step-1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StyledContainer>
|
||||||
|
<Story />
|
||||||
|
</StyledContainer>
|
||||||
|
</RecoilRoot>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SuccessEdge: Story = {
|
||||||
|
args: {
|
||||||
|
status: 'DRAFT',
|
||||||
|
nodeTypes: {
|
||||||
|
default: WorkflowDiagramStepNodeReadonly,
|
||||||
|
'create-step': WorkflowDiagramCreateStepNode,
|
||||||
|
'empty-trigger': WorkflowDiagramEmptyTrigger,
|
||||||
|
},
|
||||||
|
edgeTypes: {
|
||||||
|
default: WorkflowDiagramDefaultEdge,
|
||||||
|
success: WorkflowDiagramSuccessEdge,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<RecoilRoot
|
||||||
|
initializeState={({ set }) => {
|
||||||
|
set(workflowDiagramState, {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'trigger-1',
|
||||||
|
type: 'default',
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
data: {
|
||||||
|
nodeType: 'trigger',
|
||||||
|
triggerType: 'DATABASE_EVENT',
|
||||||
|
name: 'When record is created',
|
||||||
|
isLeafNode: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'action-1',
|
||||||
|
type: 'default',
|
||||||
|
position: { x: 300, y: 100 },
|
||||||
|
data: {
|
||||||
|
nodeType: 'action',
|
||||||
|
actionType: 'CREATE_RECORD',
|
||||||
|
name: 'Create record',
|
||||||
|
isLeafNode: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
...WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION,
|
||||||
|
id: 'edge-1',
|
||||||
|
source: 'trigger-1',
|
||||||
|
target: 'action-1',
|
||||||
|
type: 'success',
|
||||||
|
label: '1 item',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<StyledContainer>
|
||||||
|
<Story />
|
||||||
|
</StyledContainer>
|
||||||
|
</RecoilRoot>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const EDGE_GRAY_CIRCLE_MARKED_ID = 'workflow-edge-gray-circle';
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const EDGE_GREEN_CIRCLE_MARKED_ID = 'workflow-edge-green-circle';
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export const EDGE_GREEN_ROUNDED_ARROW_MARKER_ID =
|
||||||
|
'workflow-edge-green-arrow-rounded';
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const EDGE_GREEN_ROUNDED_ARROW_MARKER_WIDTH_PX = 6;
|
||||||
@ -1 +1 @@
|
|||||||
export const EDGE_ROUNDED_ARROW_MARKER_ID = 'arrow-rounded';
|
export const EDGE_ROUNDED_ARROW_MARKER_ID = 'workflow-edge-arrow-rounded';
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
import { EDGE_GRAY_CIRCLE_MARKED_ID } from '@/workflow/workflow-diagram/constants/EdgeGrayCircleMarkedId';
|
||||||
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
|
import { EDGE_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeRoundedArrowMarkerId';
|
||||||
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
|
|
||||||
export const WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION = {
|
export const WORKFLOW_VISUALIZER_EDGE_DEFAULT_CONFIGURATION = {
|
||||||
|
markerStart: EDGE_GRAY_CIRCLE_MARKED_ID,
|
||||||
markerEnd: EDGE_ROUNDED_ARROW_MARKER_ID,
|
markerEnd: EDGE_ROUNDED_ARROW_MARKER_ID,
|
||||||
deletable: false,
|
deletable: false,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { EDGE_GREEN_CIRCLE_MARKED_ID } from '@/workflow/workflow-diagram/constants/EdgeGreenCircleMarkedId';
|
||||||
|
import { EDGE_GREEN_ROUNDED_ARROW_MARKER_ID } from '@/workflow/workflow-diagram/constants/EdgeGreenRoundedArrowMarkerId';
|
||||||
|
import { WorkflowDiagramEdge } from '@/workflow/workflow-diagram/types/WorkflowDiagram';
|
||||||
|
|
||||||
|
export const WORKFLOW_VISUALIZER_EDGE_SUCCESS_CONFIGURATION = {
|
||||||
|
markerStart: EDGE_GREEN_CIRCLE_MARKED_ID,
|
||||||
|
markerEnd: EDGE_GREEN_ROUNDED_ARROW_MARKER_ID,
|
||||||
|
deletable: false,
|
||||||
|
selectable: false,
|
||||||
|
} satisfies Partial<WorkflowDiagramEdge>;
|
||||||
@ -47,3 +47,5 @@ export type WorkflowDiagramNodeType =
|
|||||||
| 'default'
|
| 'default'
|
||||||
| 'empty-trigger'
|
| 'empty-trigger'
|
||||||
| 'create-step';
|
| 'create-step';
|
||||||
|
|
||||||
|
export type WorkflowDiagramEdgeType = 'default' | 'success';
|
||||||
|
|||||||
@ -133,7 +133,8 @@ describe('getWorkflowVersionDiagram', () => {
|
|||||||
{
|
{
|
||||||
"deletable": false,
|
"deletable": false,
|
||||||
"id": "8f3b2121-f194-4ba4-9fbf-0",
|
"id": "8f3b2121-f194-4ba4-9fbf-0",
|
||||||
"markerEnd": "arrow-rounded",
|
"markerEnd": "workflow-edge-arrow-rounded",
|
||||||
|
"markerStart": "workflow-edge-gray-circle",
|
||||||
"selectable": false,
|
"selectable": false,
|
||||||
"source": "trigger",
|
"source": "trigger",
|
||||||
"target": "step-1",
|
"target": "step-1",
|
||||||
|
|||||||
Reference in New Issue
Block a user