Throw proper error on duplicate emailing domain (#22790)

Adding an emailing domain that already exists blew up with a raw
QueryFailedError and the client just saw a generic "An error occurred".
The unique index on domain is global, so the workspace-scoped existence
check never caught rows owned by another workspace.

Now the check is unscoped and throws an EmailingDomainException mapped
to CONFLICT with a proper user-facing message, in both the
createEmailingDomain mutation and the email group channel flow. Also
dropped the hardcoded catch-all snackbar on the new channel page so
server messages actually reach the user.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22790?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:
neo773
2026-07-10 23:58:34 +05:30
committed by GitHub
parent cb95410a51
commit b0dc637dbd
8 changed files with 113 additions and 26 deletions
@@ -10,7 +10,6 @@ import { Section } from 'twenty-ui/layout';
import { useCreateEmailGroupChannel } from '@/settings/accounts/hooks/useCreateEmailGroupChannel';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { SettingsPageLayout } from '@/settings/components/layout/SettingsPageLayout';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
@@ -18,7 +17,6 @@ import { useNavigateSettings } from '~/hooks/useNavigateSettings';
export const SettingsAccountsNewEmailGroupChannel = () => {
const { t } = useLingui();
const navigate = useNavigateSettings();
const { enqueueErrorSnackBar } = useSnackBar();
const { createEmailGroupChannel, loading } = useCreateEmailGroupChannel();
const [handle, setHandle] = useState('');
@@ -27,22 +25,16 @@ export const SettingsAccountsNewEmailGroupChannel = () => {
const canSave = isHandleValidEmail && !loading;
const handleSave = useCallback(async () => {
try {
const result = await createEmailGroupChannel(handle);
const messageChannelId =
result.data?.createEmailGroupChannel.messageChannel.id;
const result = await createEmailGroupChannel(handle);
const messageChannelId =
result.data?.createEmailGroupChannel.messageChannel.id;
if (messageChannelId) {
navigate(SettingsPath.EmailGroupChannelDetail, {
messageChannelId,
});
}
} catch {
enqueueErrorSnackBar({
message: t`Failed to create email channel. Email channels may not be configured on this server.`,
if (messageChannelId) {
navigate(SettingsPath.EmailGroupChannelDetail, {
messageChannelId,
});
}
}, [createEmailGroupChannel, handle, navigate, enqueueErrorSnackBar, t]);
}, [createEmailGroupChannel, handle, navigate]);
return (
<SettingsPageLayout
@@ -10,6 +10,7 @@ import { CREATE_EMAIL_GROUP_CHANNEL } from '@/settings/accounts/graphql/mutation
import { GET_MY_CONNECTED_ACCOUNTS } from '@/settings/accounts/graphql/queries/getMyConnectedAccounts';
import { GET_MY_MESSAGE_CHANNELS } from '@/settings/accounts/graphql/queries/getMyMessageChannels';
import { GET_ALL_EMAILING_DOMAINS } from '@/settings/emailing-domains/graphql/queries/getAllEmailingDomains';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
type CreateEmailGroupChannelResult = {
createEmailGroupChannel: {
@@ -33,6 +34,8 @@ type CreateEmailGroupChannelVariables = {
};
export const useCreateEmailGroupChannel = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const [mutate, { loading, error }] = useMutation<
CreateEmailGroupChannelResult,
CreateEmailGroupChannelVariables
@@ -45,7 +48,12 @@ export const useCreateEmailGroupChannel = () => {
});
const createEmailGroupChannel = (handle: string) =>
mutate({ variables: { input: { handle } } });
mutate({
variables: { input: { handle } },
onError: (mutationError) => {
enqueueErrorSnackBar({ apolloError: mutationError });
},
});
return { createEmailGroupChannel, loading, error };
};