fix(workflow): show account select in Send Email node when no account is connected (#23066)
# Why In the workflow **Send Email** (and Draft Email) node, when the workspace has no eligible connected account, the **Account** field disappears entirely — only the variable picker icon remains. The "Add account" call-to-action is unreachable, so there is no way to connect an account from the node. ## Root cause Regression from #21075. `FormSelectFieldInput` used to always pass a default empty option ("No Account") to `<Select>`; since #21075 it only prepends it when `isNullable` is set, and the email account field doesn't set it. With zero connected accounts, `<Select>` then has no option to resolve a selected option from and bails out rendering an empty fragment — even though a `callToActionButton` is configured: ```tsx // Select.tsx if (!isDefined(controlSelectedOption)) { return <></>; } ``` # What changed `FormSelectFieldInput` now prepends the empty option whenever the field is nullable **or there are no options at all**. A populated non-nullable select still offers no clearing choice (the #21075 behavior is preserved); an empty one renders its "No X" state so the control — and its call-to-action — stay visible and clickable. # Test plan - New story `FormSelectFieldInput > NoOptionsWithCallToAction`: zero options + CTA renders the "No Work Policy" control, the dropdown opens, and the CTA is clickable. - New story `WorkflowEditActionEmailBase > NoConnectedAccounts`: with `MyConnectedAccounts` mocked to `[]`, the Account field renders "No Account" instead of vanishing. The meta's msw handlers move to the keyed-object form so the story can override a single query (story-level handler arrays get concatenated after the meta's, and msw's first match wins), and the story evicts the module-singleton Apollo client's cached accounts so it actually hits the empty mock. - `npx nx typecheck twenty-front` and `npx nx lint:diff-with-main twenty-front` pass; both story files pass under the storybook vitest project (13 stories total). <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23066?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+2
-3
@@ -102,9 +102,8 @@ export const FormSelectFieldInput = ({
|
||||
Icon: IconCircleOff,
|
||||
};
|
||||
|
||||
const optionsWithEmptyOption = isNullable
|
||||
? [emptyOption, ...options]
|
||||
: options;
|
||||
const optionsWithEmptyOption =
|
||||
isNullable || options.length === 0 ? [emptyOption, ...options] : options;
|
||||
|
||||
const selectedOption = optionsWithEmptyOption.find(
|
||||
(option) => option.value === draftValue.value,
|
||||
|
||||
+31
@@ -126,6 +126,37 @@ export const NonNullable: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const NoOptionsWithCallToAction: Story = {
|
||||
args: {
|
||||
label: 'Work Policy',
|
||||
defaultValue: undefined,
|
||||
options: [],
|
||||
onChange: fn(),
|
||||
callToActionButton: {
|
||||
text: 'Add work policy',
|
||||
onClick: fn(),
|
||||
},
|
||||
},
|
||||
play: async ({ args, canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const selectControl = await canvas.findByText('No Work Policy');
|
||||
expect(selectControl).toBeVisible();
|
||||
|
||||
await userEvent.click(selectControl);
|
||||
|
||||
const dropdown = within(canvasElement.ownerDocument.body);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(dropdown.getByText('Add work policy')).toBeVisible();
|
||||
});
|
||||
|
||||
await userEvent.click(dropdown.getByText('Add work policy'));
|
||||
|
||||
expect(args.callToActionButton?.onClick).toHaveBeenCalled();
|
||||
},
|
||||
};
|
||||
|
||||
export const WithVariablePicker: Story = {
|
||||
args: {
|
||||
label: 'Work Policy',
|
||||
|
||||
Reference in New Issue
Block a user