## Features
- Fetch a workflow and display it in a tree with the React Flow library
- The nodes are positioned by an algorithm
- The feature is put behind a feature flag. The `/workflow/:id` route is
disabled if the flag is off.
- I started implementing a right drawer. That's a big WIP and it will be
finished in another PR.
## How to test this feature
1. Create a workflow instance in the database through a GraphQL query.
See below for instructions.
2. After enabling the feature flag, you should be able to see the
workflow you created in the workflows list. To visualize the workflow,
go to the `/workflow/:id` page where the id is the id of the workflow.
See the video for a quick way to do so.
```gql
// First
mutation createWorkflow($data: WorkflowCreateInput!) {
createWorkflow(data: $data) {
id
}
}
// Result
{
"data": {
"name": "test"
}
}
// Second
mutation createWorkflowVersion($data: WorkflowVersionCreateInput!) {
createWorkflowVersion (data: $data) {
id
}
}
// Result
{
"data": {
"name": "v1",
"trigger": {
"name": "trigger",
"displayName": "New or Updated Row",
"type": "DATABASE_EVENT",
"settings": {
"eventName": "company.created",
"triggerName": "Company Created"
},
"nextAction": {
"name": "step_1",
"displayName": "Code",
"type": "CODE",
"valid": true,
"settings": {
"serverlessFunctionId": "function_id",
"errorHandlingOptions": {
"retryOnFailure": {
"value": false
},
"continueOnFailure": {
"value": false
}
}
}
}
},
"workflowId": "workflow_id"
}
}
```
https://github.com/user-attachments/assets/42bbd98c-5e13-447c-9307-461a18ac2195
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram';
|
|
import styled from '@emotion/styled';
|
|
import { Handle, Position } from '@xyflow/react';
|
|
|
|
const StyledStepNodeContainer = styled.div`
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
padding-bottom: 12px;
|
|
padding-top: 6px;
|
|
`;
|
|
|
|
const StyledStepNodeType = styled.div`
|
|
background-color: ${({ theme }) => theme.background.tertiary};
|
|
border-radius: ${({ theme }) => theme.border.radius.sm}
|
|
${({ theme }) => theme.border.radius.sm} 0 0;
|
|
|
|
color: ${({ theme }) => theme.color.gray50};
|
|
font-size: ${({ theme }) => theme.font.size.xs};
|
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
|
|
|
padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)};
|
|
position: absolute;
|
|
top: 0;
|
|
transform: translateY(-100%);
|
|
|
|
.selectable.selected &,
|
|
.selectable:focus &,
|
|
.selectable:focus-visible & {
|
|
background-color: ${({ theme }) => theme.color.blue};
|
|
color: ${({ theme }) => theme.font.color.inverted};
|
|
}
|
|
`;
|
|
|
|
const StyledStepNodeInnerContainer = styled.div`
|
|
background-color: ${({ theme }) => theme.background.secondary};
|
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
|
display: flex;
|
|
gap: ${({ theme }) => theme.spacing(2)};
|
|
padding: ${({ theme }) => theme.spacing(2)};
|
|
|
|
position: relative;
|
|
box-shadow: ${({ theme }) => theme.boxShadow.superHeavy};
|
|
|
|
.selectable.selected &,
|
|
.selectable:focus &,
|
|
.selectable:focus-visible & {
|
|
background-color: ${({ theme }) => theme.color.blue10};
|
|
border-color: ${({ theme }) => theme.color.blue};
|
|
}
|
|
`;
|
|
|
|
const StyledStepNodeLabel = styled.div`
|
|
font-size: ${({ theme }) => theme.font.size.md};
|
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
|
`;
|
|
|
|
const StyledSourceHandle = styled(Handle)`
|
|
background-color: ${({ theme }) => theme.color.gray50};
|
|
`;
|
|
|
|
export const StyledTargetHandle = styled(Handle)`
|
|
visibility: hidden;
|
|
`;
|
|
|
|
export const WorkflowShowPageDiagramStepNode = ({
|
|
data,
|
|
}: {
|
|
data: WorkflowDiagramStepNodeData;
|
|
}) => {
|
|
return (
|
|
<StyledStepNodeContainer>
|
|
{data.nodeType !== 'trigger' ? (
|
|
<StyledTargetHandle type="target" position={Position.Top} />
|
|
) : null}
|
|
|
|
<StyledStepNodeInnerContainer>
|
|
<StyledStepNodeType>{data.nodeType}</StyledStepNodeType>
|
|
|
|
<StyledStepNodeLabel>{data.label}</StyledStepNodeLabel>
|
|
</StyledStepNodeInnerContainer>
|
|
|
|
<StyledSourceHandle type="source" position={Position.Bottom} />
|
|
</StyledStepNodeContainer>
|
|
);
|
|
};
|