-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## 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
- Loading branch information
Showing
30 changed files
with
1,012 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ | |
"workerDirectory": "public" | ||
}, | ||
"dependencies": { | ||
"@xyflow/react": "^12.0.4", | ||
"transliteration": "^2.3.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflow.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
const StyledContainer = styled.div` | ||
box-sizing: border-box; | ||
display: flex; | ||
flex-direction: column; | ||
height: 100%; | ||
justify-content: flex-start; | ||
overflow-y: auto; | ||
position: relative; | ||
`; | ||
|
||
const StyledChatArea = styled.div` | ||
flex: 1; | ||
display: flex; | ||
flex-direction: column; | ||
overflow-y: scroll; | ||
padding: ${({ theme }) => theme.spacing(6)}; | ||
padding-bottom: 0px; | ||
`; | ||
|
||
const StyledNewMessageArea = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
padding: ${({ theme }) => theme.spacing(6)}; | ||
padding-top: 0px; | ||
`; | ||
|
||
export const RightDrawerWorkflow = () => { | ||
const handleCreateCodeBlock = () => {}; | ||
|
||
return ( | ||
<StyledContainer> | ||
<StyledChatArea>{/* TODO */}</StyledChatArea> | ||
<StyledNewMessageArea> | ||
<button onClick={handleCreateCodeBlock}>Create code block</button> | ||
</StyledNewMessageArea> | ||
</StyledContainer> | ||
); | ||
}; |
86 changes: 86 additions & 0 deletions
86
packages/twenty-front/src/modules/workflow/components/WorkflowShowPageDiagram.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { WorkflowShowPageDiagramCreateStepNode } from '@/workflow/components/WorkflowShowPageDiagramCreateStepNode.tsx'; | ||
import { WorkflowShowPageDiagramStepNode } from '@/workflow/components/WorkflowShowPageDiagramStepNode'; | ||
import { showPageWorkflowDiagramState } from '@/workflow/states/showPageWorkflowDiagramState'; | ||
import { | ||
WorkflowDiagram, | ||
WorkflowDiagramEdge, | ||
WorkflowDiagramNode, | ||
} from '@/workflow/types/WorkflowDiagram'; | ||
import { getOrganizedDiagram } from '@/workflow/utils/getOrganizedDiagram'; | ||
import { | ||
applyEdgeChanges, | ||
applyNodeChanges, | ||
Background, | ||
EdgeChange, | ||
NodeChange, | ||
ReactFlow, | ||
} from '@xyflow/react'; | ||
import '@xyflow/react/dist/style.css'; | ||
import { useMemo } from 'react'; | ||
import { useSetRecoilState } from 'recoil'; | ||
import { GRAY_SCALE, isDefined } from 'twenty-ui'; | ||
|
||
export const WorkflowShowPageDiagram = ({ | ||
diagram, | ||
}: { | ||
diagram: WorkflowDiagram; | ||
}) => { | ||
const { nodes, edges } = useMemo( | ||
() => getOrganizedDiagram(diagram), | ||
[diagram], | ||
); | ||
|
||
const setShowPageWorkflowDiagram = useSetRecoilState( | ||
showPageWorkflowDiagramState, | ||
); | ||
|
||
const handleNodesChange = ( | ||
nodeChanges: Array<NodeChange<WorkflowDiagramNode>>, | ||
) => { | ||
setShowPageWorkflowDiagram((diagram) => { | ||
if (isDefined(diagram) === false) { | ||
throw new Error( | ||
'It must be impossible for the nodes to be updated if the diagram is not defined yet. Be sure the diagram is rendered only when defined.', | ||
); | ||
} | ||
|
||
return { | ||
...diagram, | ||
nodes: applyNodeChanges(nodeChanges, diagram.nodes), | ||
}; | ||
}); | ||
}; | ||
|
||
const handleEdgesChange = ( | ||
edgeChanges: Array<EdgeChange<WorkflowDiagramEdge>>, | ||
) => { | ||
setShowPageWorkflowDiagram((diagram) => { | ||
if (isDefined(diagram) === false) { | ||
throw new Error( | ||
'It must be impossible for the edges to be updated if the diagram is not defined yet. Be sure the diagram is rendered only when defined.', | ||
); | ||
} | ||
|
||
return { | ||
...diagram, | ||
edges: applyEdgeChanges(edgeChanges, diagram.edges), | ||
}; | ||
}); | ||
}; | ||
|
||
return ( | ||
<ReactFlow | ||
nodeTypes={{ | ||
default: WorkflowShowPageDiagramStepNode, | ||
'create-step': WorkflowShowPageDiagramCreateStepNode, | ||
}} | ||
fitView | ||
nodes={nodes.map((node) => ({ ...node, draggable: false }))} | ||
edges={edges} | ||
onNodesChange={handleNodesChange} | ||
onEdgesChange={handleEdgesChange} | ||
> | ||
<Background color={GRAY_SCALE.gray25} size={2} /> | ||
</ReactFlow> | ||
); | ||
}; |
26 changes: 26 additions & 0 deletions
26
...wenty-front/src/modules/workflow/components/WorkflowShowPageDiagramCreateStepNode.tsx.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { IconButton } from '@/ui/input/button/components/IconButton'; | ||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; | ||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; | ||
import styled from '@emotion/styled'; | ||
import { Handle, Position } from '@xyflow/react'; | ||
import { IconPlus } from 'twenty-ui'; | ||
|
||
export const StyledTargetHandle = styled(Handle)` | ||
visibility: hidden; | ||
`; | ||
|
||
export const WorkflowShowPageDiagramCreateStepNode = () => { | ||
const { openRightDrawer } = useRightDrawer(); | ||
|
||
const handleCreateStepNodeButtonClick = () => { | ||
openRightDrawer(RightDrawerPages.Workflow); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<StyledTargetHandle type="target" position={Position.Top} /> | ||
|
||
<IconButton Icon={IconPlus} onClick={handleCreateStepNodeButtonClick} /> | ||
</div> | ||
); | ||
}; |
87 changes: 87 additions & 0 deletions
87
packages/twenty-front/src/modules/workflow/components/WorkflowShowPageDiagramStepNode.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
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> | ||
); | ||
}; |
Oops, something went wrong.