-
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.
- Create a workflow version when the user visits an empty workflow. - If the trigger is not defined yet and the user selects either the standard object type or the event type first, we automatically select the first option of the other value. Indeed, every state update is automatically saved on the backend and we need both standard object and event types to save the event name. - Introduces a change in the backend. I removed the assertions that throw when a workflow version is not complete, that is, when it doesn't have a defined trigger, which is the case when scaffolding a new workflow with a first empty workflow version. - We should keep validating the workflow versions, at least when we publish them. That should be done in a second step.
- Loading branch information
Showing
26 changed files
with
548 additions
and
269 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
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
109 changes: 109 additions & 0 deletions
109
packages/twenty-front/src/modules/workflow/components/WorkflowDiagramBaseStepNode.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,109 @@ | ||
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram'; | ||
import styled from '@emotion/styled'; | ||
import { Handle, Position } from '@xyflow/react'; | ||
import React from 'react'; | ||
import { capitalize } from '~/utils/string/capitalize'; | ||
|
||
type Variant = 'placeholder'; | ||
|
||
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<{ variant?: Variant }>` | ||
background-color: ${({ theme }) => theme.background.secondary}; | ||
border: 1px solid ${({ theme }) => theme.border.color.medium}; | ||
border-style: ${({ variant }) => | ||
variant === 'placeholder' ? 'dashed' : null}; | ||
border-radius: ${({ theme }) => theme.border.radius.md}; | ||
display: flex; | ||
gap: ${({ theme }) => theme.spacing(2)}; | ||
padding: ${({ theme }) => theme.spacing(2)}; | ||
position: relative; | ||
box-shadow: ${({ variant, theme }) => | ||
variant === 'placeholder' ? 'none' : 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<{ variant?: Variant }>` | ||
align-items: center; | ||
display: flex; | ||
font-size: ${({ theme }) => theme.font.size.md}; | ||
font-weight: ${({ theme }) => theme.font.weight.medium}; | ||
column-gap: ${({ theme }) => theme.spacing(2)}; | ||
color: ${({ variant, theme }) => | ||
variant === 'placeholder' ? theme.font.color.extraLight : null}; | ||
`; | ||
|
||
const StyledSourceHandle = styled(Handle)` | ||
background-color: ${({ theme }) => theme.color.gray50}; | ||
`; | ||
|
||
export const StyledTargetHandle = styled(Handle)` | ||
visibility: hidden; | ||
`; | ||
|
||
export const WorkflowDiagramBaseStepNode = ({ | ||
nodeType, | ||
label, | ||
variant, | ||
Icon, | ||
}: { | ||
nodeType: WorkflowDiagramStepNodeData['nodeType']; | ||
label: string; | ||
variant?: Variant; | ||
Icon?: React.ReactNode; | ||
}) => { | ||
return ( | ||
<StyledStepNodeContainer> | ||
{nodeType !== 'trigger' ? ( | ||
<StyledTargetHandle type="target" position={Position.Top} /> | ||
) : null} | ||
|
||
<StyledStepNodeInnerContainer variant={variant}> | ||
<StyledStepNodeType>{capitalize(nodeType)}</StyledStepNodeType> | ||
|
||
<StyledStepNodeLabel variant={variant}> | ||
{Icon} | ||
|
||
{label} | ||
</StyledStepNodeLabel> | ||
</StyledStepNodeInnerContainer> | ||
|
||
<StyledSourceHandle type="source" position={Position.Bottom} /> | ||
</StyledStepNodeContainer> | ||
); | ||
}; |
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
30 changes: 30 additions & 0 deletions
30
packages/twenty-front/src/modules/workflow/components/WorkflowDiagramEmptyTrigger.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,30 @@ | ||
import { WorkflowDiagramBaseStepNode } from '@/workflow/components/WorkflowDiagramBaseStepNode'; | ||
import { useTheme } from '@emotion/react'; | ||
import styled from '@emotion/styled'; | ||
import { IconPlaylistAdd } from 'twenty-ui'; | ||
|
||
const StyledStepNodeLabelIconContainer = styled.div` | ||
align-items: center; | ||
background: ${({ theme }) => theme.background.transparent.light}; | ||
border-radius: ${({ theme }) => theme.spacing(1)}; | ||
display: flex; | ||
justify-content: center; | ||
padding: ${({ theme }) => theme.spacing(1)}; | ||
`; | ||
|
||
export const WorkflowDiagramEmptyTrigger = () => { | ||
const theme = useTheme(); | ||
|
||
return ( | ||
<WorkflowDiagramBaseStepNode | ||
label="Add a Trigger" | ||
nodeType="trigger" | ||
variant="placeholder" | ||
Icon={ | ||
<StyledStepNodeLabelIconContainer> | ||
<IconPlaylistAdd size={16} color={theme.font.color.tertiary} /> | ||
</StyledStepNodeLabelIconContainer> | ||
} | ||
/> | ||
); | ||
}; |
113 changes: 40 additions & 73 deletions
113
packages/twenty-front/src/modules/workflow/components/WorkflowDiagramStepNode.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 |
---|---|---|
@@ -1,87 +1,54 @@ | ||
import { WorkflowDiagramBaseStepNode } from '@/workflow/components/WorkflowDiagramBaseStepNode'; | ||
import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram'; | ||
import { useTheme } from '@emotion/react'; | ||
import styled from '@emotion/styled'; | ||
import { Handle, Position } from '@xyflow/react'; | ||
import { IconCode, IconPlaylistAdd } from 'twenty-ui'; | ||
|
||
const StyledStepNodeContainer = styled.div` | ||
const StyledStepNodeLabelIconContainer = styled.div` | ||
align-items: center; | ||
background: ${({ theme }) => theme.background.transparent.light}; | ||
border-radius: ${({ theme }) => theme.spacing(1)}; | ||
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; | ||
justify-content: center; | ||
padding: ${({ theme }) => theme.spacing(1)}; | ||
`; | ||
|
||
export const WorkflowDiagramStepNode = ({ | ||
data, | ||
}: { | ||
data: WorkflowDiagramStepNodeData; | ||
}) => { | ||
return ( | ||
<StyledStepNodeContainer> | ||
{data.nodeType !== 'trigger' ? ( | ||
<StyledTargetHandle type="target" position={Position.Top} /> | ||
) : null} | ||
|
||
<StyledStepNodeInnerContainer> | ||
<StyledStepNodeType>{data.nodeType}</StyledStepNodeType> | ||
const theme = useTheme(); | ||
|
||
const renderStepIcon = () => { | ||
switch (data.nodeType) { | ||
case 'trigger': { | ||
return ( | ||
<StyledStepNodeLabelIconContainer> | ||
<IconPlaylistAdd | ||
size={theme.icon.size.sm} | ||
color={theme.font.color.tertiary} | ||
/> | ||
</StyledStepNodeLabelIconContainer> | ||
); | ||
} | ||
case 'action': { | ||
return ( | ||
<StyledStepNodeLabelIconContainer> | ||
<IconCode size={theme.icon.size.sm} color={theme.color.orange} /> | ||
</StyledStepNodeLabelIconContainer> | ||
); | ||
} | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
<StyledStepNodeLabel>{data.label}</StyledStepNodeLabel> | ||
</StyledStepNodeInnerContainer> | ||
|
||
<StyledSourceHandle type="source" position={Position.Bottom} /> | ||
</StyledStepNodeContainer> | ||
return ( | ||
<WorkflowDiagramBaseStepNode | ||
nodeType={data.nodeType} | ||
label={data.label} | ||
Icon={renderStepIcon()} | ||
/> | ||
); | ||
}; |
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
Oops, something went wrong.