Skip to content

Commit 2273d66

Browse files
cvxluoclaude
andcommitted
fix(settings): Surface slug validation errors on org settings form
When changing the org slug to one already in use, the backend returns a field-level error but the frontend was showing a generic 'Unable to save change' toast. This was a regression from the form migration to TanStack which landed after the backend fix. Use setFieldErrors to display the API validation message inline on the slug field instead of swallowing it. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8b28ee1 commit 2273d66

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

static/app/views/settings/organizationGeneralSettings/organizationSettingsForm.spec.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,28 @@ describe('OrganizationSettingsForm', () => {
156156
expect(screen.queryByRole('button', {name: 'Cancel'})).not.toBeInTheDocument();
157157
});
158158

159+
it('shows field error when slug is already taken', async () => {
160+
MockApiClient.addMockResponse({
161+
url: `/organizations/${organization.slug}/`,
162+
method: 'PUT',
163+
statusCode: 400,
164+
body: {slug: ['The slug "taken" is in use by another organization.']},
165+
});
166+
167+
render(
168+
<OrganizationSettingsForm initialData={OrganizationFixture()} onSave={onSave} />
169+
);
170+
171+
const input = screen.getByRole('textbox', {name: 'Organization Slug'});
172+
await userEvent.clear(input);
173+
await userEvent.type(input, 'taken');
174+
await userEvent.click(screen.getByRole('button', {name: 'Save'}));
175+
176+
expect(
177+
await screen.findByText('The slug "taken" is in use by another organization.')
178+
).toBeInTheDocument();
179+
});
180+
159181
it('can enable codecov', async () => {
160182
putMock = MockApiClient.addMockResponse({
161183
url: `/organizations/${organization.slug}/`,

static/app/views/settings/organizationGeneralSettings/organizationSettingsForm.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
defaultFormOptions,
1212
FieldGroup,
1313
FormSearch,
14+
setFieldErrors,
1415
useScrapsForm,
1516
} from '@sentry/scraps/form';
1617
import {Container, Flex} from '@sentry/scraps/layout';
@@ -29,6 +30,7 @@ import {ConfigStore} from 'sentry/stores/configStore';
2930
import type {MembershipSettingsProps} from 'sentry/types/hooks';
3031
import type {Organization} from 'sentry/types/organization';
3132
import {fetchMutation, useMutation} from 'sentry/utils/queryClient';
33+
import {RequestError} from 'sentry/utils/requestError/requestError';
3234
import {slugify} from 'sentry/utils/slugify';
3335
import {useMembers} from 'sentry/utils/useMembers';
3436
import {useOrganization} from 'sentry/utils/useOrganization';
@@ -437,10 +439,14 @@ export function OrganizationSettingsForm({initialData, onSave}: Props) {
437439
...defaultFormOptions,
438440
defaultValues: {slug: initialData.slug},
439441
validators: {onDynamic: slugSchema},
440-
onSubmit: ({value}) =>
442+
onSubmit: ({value, formApi}) =>
441443
updateSlug({slug: value.slug})
442444
.then(() => slugForm.reset())
443-
.catch(() => {}),
445+
.catch(error => {
446+
if (error instanceof RequestError) {
447+
setFieldErrors(formApi, error);
448+
}
449+
}),
444450
});
445451

446452
return (

0 commit comments

Comments
 (0)