-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add workflow email action #7279
Conversation
…ve properties like selected
efb505d
to
b0b39f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This pull request introduces significant enhancements to the workflow system, particularly focusing on adding a new 'SEND_EMAIL' action type. Here's a concise summary of the major changes:
- Implemented a new 'SEND_EMAIL' action type with dedicated components for editing email actions
- Enhanced the TextArea component with label support, improving accessibility
- Refactored the workflow diagram generation and merging process to preserve UI state
- Updated the WorkflowDiagramStepNode to visually distinguish between different action types
- Introduced a reusable WorkflowEditActionFormBase component for consistent action form layouts
- Added unit tests for the new mergeWorkflowDiagrams function to ensure correct functionality
These changes significantly expand the capabilities of the workflow system while improving code modularity and maintainability.
17 file(s) reviewed, 7 comment(s)
Edit PR Review Bot Settings
value={value} | ||
onChange={(event) => | ||
onChange?.(turnIntoEmptyStringIfWhitespacesOnly(event.target.value)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider memoizing this onChange callback to prevent unnecessary re-renders
packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowEditStepContent.tsx
Outdated
Show resolved
Hide resolved
onChange={(email) => { | ||
field.onChange(email); | ||
|
||
handleSave(); | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: onChange prop receives 'email' but it's actually the subject. Rename for clarity
onChange={(email) => { | ||
field.onChange(email); | ||
|
||
handleSave(); | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: onChange prop receives 'email' but it's actually the body. Rename for clarity
subject: 'hello', | ||
title: 'hello', | ||
template: '{{title}}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider using more descriptive placeholder values for subject, title, and template
settings: { | ||
subject: 'hello', | ||
title: 'hello', | ||
template: '{{title}}', | ||
errorHandlingOptions: { | ||
continueOnFailure: { | ||
value: false, | ||
}, | ||
retryOnFailure: { | ||
value: false, | ||
}, | ||
}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Email recipient information is missing from the default settings
const nodeWithPreservedProperties = nodePropertiesToPreserve.reduce( | ||
(nodeToSet, propertyToPreserve) => { | ||
return Object.assign(nodeToSet, { | ||
[propertyToPreserve]: previousNode?.[propertyToPreserve], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: This may overwrite nextNode properties if they exist in nodePropertiesToPreserve. Ensure this is the intended behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work 🔥
Just a couple of comments. Also, to avoid spreading switch
everywhere, could you put those into utils. So you can put all utils into the workflow folder
@@ -57,6 +73,8 @@ export const TextArea = ({ | |||
}: TextAreaProps) => { | |||
const computedMinRows = Math.min(minRows, MAX_ROWS); | |||
|
|||
const inputId = useId(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we usually use v4()
. Do we need an id that is not an uuid
maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I documented this change in my issue about using real <label>
HTML elements for inputs. (#7281)
I saw that a UUID v4 was generated in a render function to serve as an input id:
const checkboxId = 'checkbox' + v4(); |
UUIDs are expensive to compute as cryptographically secure identifiers with low collision probabilities. However, these properties aren't necessary for an input's ID.
It's also better to have a consistent identifier that doesn't change every time. Assistive technologies like screen readers will behave better with a consistent identifier.
Furthermore, generating a UUID in a render function will re-compute it every time the component is rendered. As generating a UUID comes with a cost, it's better to either memoize it or not use an UUID.
The new useId()
React hook returns a short and memoized ID with no collision probability. It also works well with server-side rendering, as the ID will be the same whether the component is rendered client-side or server-side.
It's important to mention that I only recommend using the useId()
hook to generate DOM identifiers, like an input id. The useId()
hook is not meant to generate other kinds of identifiers best served with a UUID v4.
/> | ||
); | ||
if (stepDefinition.type === 'action') { | ||
if (stepDefinition.definition.type === 'CODE') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use a switch, we will add more types soon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use the type from packages/twenty-front/src/modules/workflow/constants/Actions.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will work on that tomorrow. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed 👍
@@ -26,6 +26,27 @@ export const getStepDefaultDefinition = ( | |||
}, | |||
}; | |||
} | |||
case 'SEND_EMAIL': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/twenty-front/src/modules/workflow/utils/getStepDefaultDefinition.ts should be suffixed with .util.ts
@@ -33,11 +33,25 @@ export const WorkflowDiagramStepNode = ({ | |||
); | |||
} | |||
case 'action': { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be moved into an util next to the others
onTriggerUpdate={updateTrigger} | ||
/> | ||
); | ||
switch (stepDefinition.type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
… type or an action type
@@ -0,0 +1,3 @@ | |||
export const assertUnreachable = (x: never, errorMessage?: string): never => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is inspired by https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-switch-block-is-exhaustive-in-typescript.
Thanks @Devessier for your contribution! |
- Add the SAVE_EMAIL action. This action requires more setting parameters than the Serverless Function action. - Changed the way we computed the workflow diagram. It now preserves some properties, like the `selected` property. That's necessary to not close the right drawer when the workflow back-end data change. - Added the possibility to set a label to a TextArea. This uses a `<label>` HTML element and the `useId()` hook to create an id linking the label with the input.
selected
property. That's necessary to not close the right drawer when the workflow back-end data change.<label>
HTML element and theuseId()
hook to create an id linking the label with the input.