Pass additional_settings from the integration form to backend (#4047)
# What this PR does - Pass additional_settings from the integration form to backend --------- Co-authored-by: Dominik <dominik.broj@grafana.com>
This commit is contained in:
parent
9b7dce64cd
commit
017afaa1b7
4 changed files with 124 additions and 88 deletions
|
|
@ -7,5 +7,9 @@ export function prepareForEdit(item: ApiSchemas['AlertReceiveChannel']): Partial
|
|||
team: item.team,
|
||||
labels: item.labels,
|
||||
integration: item.integration,
|
||||
|
||||
additional_settings: {
|
||||
...item.additional_settings,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,39 +35,26 @@ import { AppFeature } from 'state/features';
|
|||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { PLUGIN_ROOT, URL_REGEX, generateAssignToTeamInputDescription } from 'utils/consts';
|
||||
import { OmitReadonlyMembers } from 'utils/types';
|
||||
|
||||
import { prepareForEdit } from './IntegrationForm.helpers';
|
||||
import { getIntegrationFormStyles } from './IntegrationForm.styles';
|
||||
|
||||
enum FormFieldKeys {
|
||||
Name = 'verbal_name',
|
||||
Description = 'description_short',
|
||||
Team = 'team',
|
||||
AlertManager = 'alert_manager',
|
||||
ContactPoint = 'contact_point',
|
||||
IsExisting = 'is_existing',
|
||||
Alerting = 'alerting',
|
||||
Integration = 'integration',
|
||||
|
||||
ServiceNowUrl = 'servicenow_url',
|
||||
AuthUsername = 'auth_username',
|
||||
AuthPassword = 'auth_password',
|
||||
DefaultWebhooks = 'default_webhooks',
|
||||
}
|
||||
|
||||
interface FormFields {
|
||||
[FormFieldKeys.Name]: string;
|
||||
[FormFieldKeys.Description]: string;
|
||||
[FormFieldKeys.Team]: string;
|
||||
[FormFieldKeys.IsExisting]: boolean;
|
||||
[FormFieldKeys.AlertManager]: string;
|
||||
[FormFieldKeys.ContactPoint]: string;
|
||||
[FormFieldKeys.Alerting]: string;
|
||||
[FormFieldKeys.ServiceNowUrl]: string;
|
||||
[FormFieldKeys.AuthUsername]: string;
|
||||
[FormFieldKeys.AuthPassword]: string;
|
||||
[FormFieldKeys.Integration]: string;
|
||||
[FormFieldKeys.DefaultWebhooks]: boolean;
|
||||
verbal_name?: string;
|
||||
description_short?: string;
|
||||
team?: string;
|
||||
is_existing?: boolean;
|
||||
alert_manager?: string;
|
||||
contact_point?: string;
|
||||
integration: ApiSchemas['AlertReceiveChannel']['integration'];
|
||||
|
||||
additional_settings: {
|
||||
instance_url: string;
|
||||
username: string;
|
||||
password: string;
|
||||
default_webhooks: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface IntegrationFormProps {
|
||||
|
|
@ -107,8 +94,17 @@ export const IntegrationForm = observer(
|
|||
const isNew = id === 'new';
|
||||
const { userStore, grafanaTeamStore, alertReceiveChannelStore } = store;
|
||||
|
||||
const data = isNew
|
||||
? { integration: selectedIntegration?.value, team: userStore.currentUser?.current_team, labels: [] }
|
||||
const data: Partial<ApiSchemas['AlertReceiveChannel']> = isNew
|
||||
? {
|
||||
integration: selectedIntegration?.value as ApiSchemas['AlertReceiveChannel']['integration'],
|
||||
team: userStore.currentUser?.current_team,
|
||||
labels: [],
|
||||
additional_settings: {
|
||||
instance_url: undefined,
|
||||
password: undefined,
|
||||
username: undefined,
|
||||
},
|
||||
}
|
||||
: prepareForEdit(alertReceiveChannelStore.items[id]);
|
||||
|
||||
const { integration } = data;
|
||||
|
|
@ -117,8 +113,10 @@ export const IntegrationForm = observer(
|
|||
defaultValues: isNew
|
||||
? {
|
||||
// these are the default values for creating an integration
|
||||
[FormFieldKeys.Integration]: integration,
|
||||
[FormFieldKeys.DefaultWebhooks]: true,
|
||||
integration,
|
||||
additional_settings: {
|
||||
default_webhooks: true,
|
||||
},
|
||||
}
|
||||
: {
|
||||
// existing values from existing integration (edit-mode)
|
||||
|
|
@ -126,6 +124,7 @@ export const IntegrationForm = observer(
|
|||
},
|
||||
mode: 'onChange',
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
|
|
@ -175,15 +174,15 @@ export const IntegrationForm = observer(
|
|||
<FormProvider {...formMethods}>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)} className={styles.form}>
|
||||
<Controller
|
||||
name={FormFieldKeys.Name}
|
||||
name={'verbal_name'}
|
||||
control={control}
|
||||
rules={{ required: 'Name is required' }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'Name'}
|
||||
label={'Integration Name'}
|
||||
invalid={!!errors[FormFieldKeys.Name]}
|
||||
error={errors[FormFieldKeys.Name]?.message}
|
||||
invalid={!!errors.verbal_name}
|
||||
error={errors.verbal_name?.message}
|
||||
>
|
||||
<Input {...field} placeholder={'Integration Name'} />
|
||||
</Field>
|
||||
|
|
@ -191,15 +190,15 @@ export const IntegrationForm = observer(
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.Description}
|
||||
name={'description_short'}
|
||||
control={control}
|
||||
rules={{ required: 'Description is required' }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'Description'}
|
||||
label={'Integration Description'}
|
||||
invalid={!!errors[FormFieldKeys.Description]}
|
||||
error={errors[FormFieldKeys.Description]?.message}
|
||||
invalid={!!errors.description_short}
|
||||
error={errors.description_short?.message}
|
||||
>
|
||||
<TextArea {...field} className={styles.textarea} placeholder={'Integration Description'} />
|
||||
</Field>
|
||||
|
|
@ -207,7 +206,7 @@ export const IntegrationForm = observer(
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.Team}
|
||||
name={'team'}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
|
|
@ -220,8 +219,8 @@ export const IntegrationForm = observer(
|
|||
</Tooltip>
|
||||
</Label>
|
||||
}
|
||||
invalid={!!errors[FormFieldKeys.Team]}
|
||||
error={errors[FormFieldKeys.Team]?.message}
|
||||
invalid={!!errors.team}
|
||||
error={errors.team?.message}
|
||||
>
|
||||
<GSelect<GrafanaTeam>
|
||||
placeholder="Assign to team"
|
||||
|
|
@ -288,15 +287,15 @@ export const IntegrationForm = observer(
|
|||
</div>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.ServiceNowUrl}
|
||||
name={'additional_settings.instance_url'}
|
||||
control={control}
|
||||
rules={{ required: 'Instance URL is required', validate: validateURL }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'InstanceURL'}
|
||||
label={'Instance URL'}
|
||||
invalid={!!errors[FormFieldKeys.ServiceNowUrl]}
|
||||
error={errors[FormFieldKeys.ServiceNowUrl]?.message}
|
||||
invalid={!!errors.additional_settings?.instance_url}
|
||||
error={errors.additional_settings?.instance_url?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</Field>
|
||||
|
|
@ -304,15 +303,15 @@ export const IntegrationForm = observer(
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.AuthUsername}
|
||||
name={'additional_settings.username'}
|
||||
control={control}
|
||||
rules={{ required: 'Username is required' }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'AuthUsername'}
|
||||
label={'Username'}
|
||||
invalid={!!errors[FormFieldKeys.AuthUsername]}
|
||||
error={errors[FormFieldKeys.AuthUsername]?.message}
|
||||
invalid={!!errors.additional_settings?.username}
|
||||
error={errors.additional_settings?.username?.message}
|
||||
>
|
||||
<Input {...field} />
|
||||
</Field>
|
||||
|
|
@ -320,15 +319,15 @@ export const IntegrationForm = observer(
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.AuthPassword}
|
||||
name={'additional_settings.password'}
|
||||
control={control}
|
||||
rules={{ required: 'Password is required' }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'AuthPassword'}
|
||||
label={'Password'}
|
||||
invalid={!!errors[FormFieldKeys.AuthPassword]}
|
||||
error={errors[FormFieldKeys.AuthPassword]?.message as string}
|
||||
invalid={!!errors.additional_settings?.password}
|
||||
error={errors.additional_settings?.password?.message}
|
||||
>
|
||||
<Input {...field} type="password" />
|
||||
</Field>
|
||||
|
|
@ -340,7 +339,7 @@ export const IntegrationForm = observer(
|
|||
</Button>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.DefaultWebhooks}
|
||||
name={'additional_settings.default_webhooks'}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className={styles.webhookSwitch}>
|
||||
|
|
@ -382,9 +381,18 @@ export const IntegrationForm = observer(
|
|||
|
||||
async function onWebhookTestClick(): Promise<void> {}
|
||||
|
||||
async function onFormSubmit(formData): Promise<void> {
|
||||
async function onFormSubmit(formData: FormFields): Promise<void> {
|
||||
const labels = labelsRef.current?.getValue();
|
||||
const data = { ...formData, labels };
|
||||
|
||||
const data: OmitReadonlyMembers<ApiSchemas['AlertReceiveChannel']> = {
|
||||
labels,
|
||||
...formData,
|
||||
};
|
||||
|
||||
if (formData.integration !== 'servicenow') {
|
||||
delete data.additional_settings;
|
||||
}
|
||||
|
||||
const isCreate = id === 'new';
|
||||
|
||||
try {
|
||||
|
|
@ -416,9 +424,9 @@ export const IntegrationForm = observer(
|
|||
pushHistory(response.id);
|
||||
}
|
||||
|
||||
await (data.is_existing
|
||||
await (formData.is_existing
|
||||
? AlertReceiveChannelHelper.connectContactPoint
|
||||
: AlertReceiveChannelHelper.createContactPoint)(response.id, data.alert_manager, data.contact_point);
|
||||
: AlertReceiveChannelHelper.createContactPoint)(response.id, formData.alert_manager, formData.contact_point);
|
||||
|
||||
pushHistory(response.id);
|
||||
}
|
||||
|
|
@ -473,6 +481,7 @@ const GrafanaContactPoint = observer(
|
|||
getValues,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
register,
|
||||
} = useFormContext<FormFields>();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -486,7 +495,7 @@ const GrafanaContactPoint = observer(
|
|||
});
|
||||
})();
|
||||
|
||||
setValue(FormFieldKeys.IsExisting, true);
|
||||
setValue('is_existing', true);
|
||||
}, []);
|
||||
|
||||
const styles = useStyles2(getIntegrationFormStyles);
|
||||
|
|
@ -503,11 +512,12 @@ const GrafanaContactPoint = observer(
|
|||
|
||||
<div className={styles.extraFieldsRadio}>
|
||||
<Controller
|
||||
name={FormFieldKeys.IsExisting}
|
||||
name={'is_existing'}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<RadioButtonGroup
|
||||
{...field}
|
||||
{...register('is_existing')}
|
||||
options={radioOptions}
|
||||
value={isExistingContactPoint ? 'existing' : 'new'}
|
||||
onChange={(radioValue) => {
|
||||
|
|
@ -518,9 +528,9 @@ const GrafanaContactPoint = observer(
|
|||
selectedContactPointOption: null,
|
||||
});
|
||||
|
||||
setValue(FormFieldKeys.IsExisting, radioValue === 'existing');
|
||||
setValue(FormFieldKeys.AlertManager, undefined);
|
||||
setValue(FormFieldKeys.ContactPoint, undefined);
|
||||
setValue('is_existing', radioValue === 'existing');
|
||||
setValue('alert_manager', undefined);
|
||||
setValue('contact_point', undefined);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -529,15 +539,11 @@ const GrafanaContactPoint = observer(
|
|||
|
||||
<div className={styles.selectorsContainer}>
|
||||
<Controller
|
||||
name={FormFieldKeys.AlertManager}
|
||||
name={'alert_manager'}
|
||||
control={control}
|
||||
rules={{ required: 'Alert Manager is required' }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={'AlertManager'}
|
||||
invalid={!!errors[FormFieldKeys.AlertManager]}
|
||||
error={errors[FormFieldKeys.AlertManager]?.message}
|
||||
>
|
||||
<Field key={'AlertManager'} invalid={!!errors.alert_manager} error={errors.alert_manager?.message}>
|
||||
<Select
|
||||
{...field}
|
||||
options={dataSources}
|
||||
|
|
@ -550,15 +556,11 @@ const GrafanaContactPoint = observer(
|
|||
/>
|
||||
|
||||
<Controller
|
||||
name={FormFieldKeys.ContactPoint}
|
||||
name={'contact_point'}
|
||||
control={control}
|
||||
rules={{ required: 'Contact Point is required', validate: contactPointValidator }}
|
||||
render={({ field }) => (
|
||||
<Field
|
||||
key={FormFieldKeys.ContactPoint}
|
||||
invalid={!!errors[FormFieldKeys.ContactPoint]}
|
||||
error={errors[FormFieldKeys.ContactPoint]?.message}
|
||||
>
|
||||
<Field key={'contact_point'} invalid={!!errors.contact_point} error={errors.contact_point?.message}>
|
||||
{isExistingContactPoint ? (
|
||||
<Select
|
||||
{...field}
|
||||
|
|
@ -574,7 +576,7 @@ const GrafanaContactPoint = observer(
|
|||
onChange={({ currentTarget }) => {
|
||||
const { value } = currentTarget;
|
||||
setState({ selectedContactPointOption: value });
|
||||
setValue(FormFieldKeys.ContactPoint, value, { shouldValidate: true });
|
||||
setValue('contact_point', value, { shouldValidate: true });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -587,8 +589,8 @@ const GrafanaContactPoint = observer(
|
|||
);
|
||||
|
||||
function contactPointValidator(contactPointInputValue: string) {
|
||||
const alertManager = getValues(FormFieldKeys.AlertManager);
|
||||
const isExisting = getValues(FormFieldKeys.IsExisting);
|
||||
const alertManager = getValues('alert_manager');
|
||||
const isExisting = getValues('is_existing');
|
||||
|
||||
const matchingAlertManager = allContactPoints.find((cp) => cp.uid === alertManager);
|
||||
const hasContactPointInput = alertManager && contactPointInputValue;
|
||||
|
|
@ -617,16 +619,16 @@ const GrafanaContactPoint = observer(
|
|||
|
||||
if (isExistingContactPoint) {
|
||||
newState.selectedContactPointOption = null;
|
||||
setValue(FormFieldKeys.ContactPoint, undefined);
|
||||
setValue('contact_point', undefined);
|
||||
}
|
||||
|
||||
setState(newState);
|
||||
setValue(FormFieldKeys.AlertManager, option.value, { shouldValidate: true });
|
||||
setValue('alert_manager', option.value, { shouldValidate: true });
|
||||
}
|
||||
|
||||
function onContactPointChange(option: SelectableValue<string>) {
|
||||
setState({ selectedContactPointOption: option.value });
|
||||
setValue(FormFieldKeys.ContactPoint, option.value, { shouldValidate: true });
|
||||
setValue('contact_point', option.value, { shouldValidate: true });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -44,10 +44,16 @@ export class AlertReceiveChannelStore {
|
|||
}
|
||||
|
||||
@WithGlobalNotification({ failure: 'There was an issue creating Integration. Please try again.' })
|
||||
async create({ data, skipErrorHandling }: { data: ApiSchemas['AlertReceiveChannel']; skipErrorHandling?: boolean }) {
|
||||
async create({
|
||||
data,
|
||||
skipErrorHandling,
|
||||
}: {
|
||||
data: OmitReadonlyMembers<ApiSchemas['AlertReceiveChannel']>;
|
||||
skipErrorHandling?: boolean;
|
||||
}) {
|
||||
const result = await onCallApi({ skipErrorHandling }).POST('/alert_receive_channels/', {
|
||||
params: {},
|
||||
body: data,
|
||||
body: data as ApiSchemas['AlertReceiveChannel'],
|
||||
});
|
||||
await this.rootStore.organizationStore.loadCurrentOrganization();
|
||||
return result.data;
|
||||
|
|
@ -60,12 +66,12 @@ export class AlertReceiveChannelStore {
|
|||
skipErrorHandling,
|
||||
}: {
|
||||
id: ApiSchemas['AlertReceiveChannelUpdate']['id'];
|
||||
data: ApiSchemas['AlertReceiveChannelUpdate'];
|
||||
data: OmitReadonlyMembers<ApiSchemas['AlertReceiveChannelUpdate']>;
|
||||
skipErrorHandling?: boolean;
|
||||
}) {
|
||||
const result = await onCallApi({ skipErrorHandling }).PUT('/alert_receive_channels/{id}/', {
|
||||
params: { path: { id } },
|
||||
body: data,
|
||||
body: data as ApiSchemas['AlertReceiveChannelUpdate'],
|
||||
});
|
||||
await this.rootStore.organizationStore.loadCurrentOrganization();
|
||||
return result.data;
|
||||
|
|
|
|||
|
|
@ -1446,8 +1446,16 @@ export interface components {
|
|||
/** Format: date-time */
|
||||
readonly alertmanager_v2_migrated_at: string | null;
|
||||
additional_settings?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
instance_url: string;
|
||||
username: string;
|
||||
password: string;
|
||||
state_mapping?: {
|
||||
firing: string;
|
||||
acknowledged: string;
|
||||
resolved: string;
|
||||
silenced: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
AlertReceiveChannelConnectContactPoint: {
|
||||
datasource_uid: string;
|
||||
|
|
@ -1557,8 +1565,16 @@ export interface components {
|
|||
/** Format: date-time */
|
||||
readonly alertmanager_v2_migrated_at: string | null;
|
||||
additional_settings?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
instance_url: string;
|
||||
username: string;
|
||||
password: string;
|
||||
state_mapping?: {
|
||||
firing: string;
|
||||
acknowledged: string;
|
||||
resolved: string;
|
||||
silenced: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @enum {integer} */
|
||||
CloudConnectionStatusEnum: 0 | 1 | 2 | 3;
|
||||
|
|
@ -1867,8 +1883,16 @@ export interface components {
|
|||
/** Format: date-time */
|
||||
readonly alertmanager_v2_migrated_at?: string | null;
|
||||
additional_settings?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
instance_url: 'string';
|
||||
username: 'string';
|
||||
password: 'string';
|
||||
state_mapping?: {
|
||||
firing: null;
|
||||
acknowledged: null;
|
||||
resolved: null;
|
||||
silenced: null;
|
||||
};
|
||||
};
|
||||
};
|
||||
PatchedUser: {
|
||||
readonly pk?: string;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue