fix: unregister the fullpath to clear out validation

This commit is contained in:
Konstantin Morozov
2026-07-31 15:38:04 +02:00
parent 1b95d97bdb
commit 1d55d4e2cd
2 changed files with 70 additions and 2 deletions
@@ -65,7 +65,7 @@ export function ChannelSubForm<R extends ChannelValues>({
customValidators = {},
}: Props<R>): JSX.Element {
const styles = useStyles2(getStyles);
const { control, watch, register, trigger, formState, setValue, getValues } =
const { control, watch, register, trigger, formState, setValue, getValues, unregister } =
useFormContext<ReceiverFormValues<CloudChannelValues | GrafanaChannelValues>>();
const channelFieldPath = `items.${integrationIndex}` as const;
@@ -174,7 +174,9 @@ export function ChannelSubForm<R extends ChannelValues>({
const fieldPath = settingsPath.startsWith(`${channelFieldPath}.settings.`)
? settingsPath.slice(`${channelFieldPath}.settings.`.length)
: settingsPath;
setValue(`${settingsFieldPath}.${fieldPath}`, undefined);
const fullPath = `${settingsFieldPath}.${fieldPath}` as const;
unregister(fullPath);
setValue(fullPath, undefined);
};
const typeOptions = useMemo((): SelectableValue[] => {
@@ -104,7 +104,34 @@ const ui = {
},
},
optionalSettings: byRole('button', { name: /optional webhook settings/i }),
payload: {
container: byTestId('items.0.settings.payload.container'),
template: byRole('textbox', { name: /^Payload Template/ }),
deleteButton: byTestId('items.0.settings.payload.delete-button'),
},
},
invalidFormToast: byRole('alert', { name: /there are errors in the form/i }),
};
const webhookContactPointWithPayload = (payloadTemplate: string) => {
const contactPointName = 'webhook-payload-test';
return alertingFactory.alertmanager.grafana.contactPoint
.withIntegrations((integrationFactory) => [
integrationFactory
.webhook()
.params({
settings: {
url: 'http://example.com',
payload: {
template: payloadTemplate,
vars: { severity: 'critical' },
},
},
})
.build(),
])
.build({ id: 'webhook-id', name: contactPointName, metadata: { name: contactPointName } });
};
describe('GrafanaReceiverForm', () => {
@@ -614,6 +641,45 @@ describe('GrafanaReceiverForm', () => {
expect(postRequestBody).toMatchSnapshot();
});
it('should remove the custom payload when deleted and the template is a single template reference', async () => {
const contactPoint = webhookContactPointWithPayload('{{ template "webhook.default.payload" . }}');
const savedIntegrations: Array<{ settings: Record<string, unknown> }> = [];
server.use(
http.put(
'/apis/notifications.alerting.grafana.app/v0alpha1/namespaces/:namespace/receivers/:name',
async ({ request }) => {
const body = await request.clone().json();
savedIntegrations.push(...body.spec.integrations);
// returning no response lets the default handler respond as usual
}
)
);
const { user } = renderWithProvider(
<>
<AppNotificationList />
<GrafanaReceiverForm contactPoint={contactPoint} editMode={true} />
</>
);
await waitFor(() => expect(ui.loadingIndicator.query()).not.toBeInTheDocument());
await user.click(ui.webhook.optionalSettings.get());
// A single template reference renders the template picker only, so the registered textarea never mounts
expect(await ui.webhook.payload.container.find()).toBeInTheDocument();
expect(ui.webhook.payload.template.query()).not.toBeInTheDocument();
await user.click(await ui.webhook.payload.deleteButton.find());
await user.click(ui.saveButton.get());
expect(ui.invalidFormToast.query()).not.toBeInTheDocument();
await waitFor(() => expect(savedIntegrations).toHaveLength(1));
expect(savedIntegrations[0].settings).not.toHaveProperty('payload');
expect(savedIntegrations[0].settings).toHaveProperty('url', 'http://example.com');
});
});
describe('Test contact point', () => {