Alerting: Allow testing provisioned contact points (#52824)

This commit is contained in:
Gilles De Mey
2022-07-28 10:03:28 +02:00
committed by GitHub
parent 44cc9132e3
commit 9332fb65a9
4 changed files with 63 additions and 46 deletions
@@ -23,7 +23,8 @@ interface Props<R> {
secureFields?: Record<string, boolean>;
errors?: FieldErrors<R>;
onDelete?: () => void;
readOnly?: boolean;
isEditable?: boolean;
isTestable?: boolean;
}
export function ChannelSubForm<R extends ChannelValues>({
@@ -36,7 +37,8 @@ export function ChannelSubForm<R extends ChannelValues>({
errors,
secureFields,
commonSettingsComponent: CommonSettingsComponent,
readOnly = false,
isEditable = true,
isTestable,
}: Props<R>): JSX.Element {
const styles = useStyles2(getStyles);
const name = (fieldName: string) => `${pathPrefix}${fieldName}`;
@@ -89,6 +91,7 @@ export function ChannelSubForm<R extends ChannelValues>({
const optionalOptions = notifier?.options.filter((o) => !o.required);
const contactPointTypeInputId = `contact-point-type-${pathPrefix}`;
return (
<div className={styles.wrapper} data-testid="item-container">
<div className={styles.topRow}>
@@ -99,7 +102,7 @@ export function ChannelSubForm<R extends ChannelValues>({
defaultValue={defaultValues.type}
render={({ field: { ref, onChange, ...field } }) => (
<Select
disabled={readOnly}
disabled={!isEditable}
inputId={contactPointTypeInputId}
{...field}
width={37}
@@ -112,37 +115,39 @@ export function ChannelSubForm<R extends ChannelValues>({
/>
</Field>
</div>
{!readOnly && (
<div className={styles.buttons}>
{onTest && (
<Button
disabled={testingReceiver}
size="xs"
variant="secondary"
type="button"
onClick={() => handleTest()}
icon={testingReceiver ? 'fa fa-spinner' : 'message'}
>
Test
</Button>
)}
<Button size="xs" variant="secondary" type="button" onClick={() => onDuplicate()} icon="copy">
Duplicate
<div className={styles.buttons}>
{isTestable && onTest && (
<Button
disabled={testingReceiver}
size="xs"
variant="secondary"
type="button"
onClick={() => handleTest()}
icon={testingReceiver ? 'fa fa-spinner' : 'message'}
>
Test
</Button>
{onDelete && (
<Button
data-testid={`${pathPrefix}delete-button`}
size="xs"
variant="secondary"
type="button"
onClick={() => onDelete()}
icon="trash-alt"
>
Delete
)}
{isEditable && (
<>
<Button size="xs" variant="secondary" type="button" onClick={() => onDuplicate()} icon="copy">
Duplicate
</Button>
)}
</div>
)}
{onDelete && (
<Button
data-testid={`${pathPrefix}delete-button`}
size="xs"
variant="secondary"
type="button"
onClick={() => onDelete()}
icon="trash-alt"
>
Delete
</Button>
)}
</>
)}
</div>
</div>
{notifier && (
<div className={styles.innerContent}>
@@ -153,7 +158,7 @@ export function ChannelSubForm<R extends ChannelValues>({
errors={errors}
onResetSecureField={onResetSecureField}
pathPrefix={pathPrefix}
readOnly={readOnly}
readOnly={!isEditable}
/>
{!!(mandatoryOptions?.length && optionalOptions?.length) && (
<CollapsibleSection label={`Optional ${notifier.name} settings`}>
@@ -169,12 +174,12 @@ export function ChannelSubForm<R extends ChannelValues>({
onResetSecureField={onResetSecureField}
errors={errors}
pathPrefix={pathPrefix}
readOnly={readOnly}
readOnly={!isEditable}
/>
</CollapsibleSection>
)}
<CollapsibleSection label="Notification settings">
<CommonSettingsComponent pathPrefix={pathPrefix} readOnly={readOnly} />
<CommonSettingsComponent pathPrefix={pathPrefix} readOnly={!isEditable} />
</CollapsibleSection>
</div>
)}
@@ -62,7 +62,9 @@ export const CloudReceiverForm: FC<Props> = ({ existing, alertManagerSourceName,
[config, existing]
);
const readOnly = isVanillaPrometheusAlertManagerDataSource(alertManagerSourceName);
// this basically checks if we can manage the selected alert manager data source, either because it's a Grafana Managed one
// or a Mimir-based AlertManager
const isManageableAlertManagerDataSource = !isVanillaPrometheusAlertManagerDataSource(alertManagerSourceName);
return (
<>
@@ -72,7 +74,8 @@ export const CloudReceiverForm: FC<Props> = ({ existing, alertManagerSourceName,
</Alert>
)}
<ReceiverForm<CloudChannelValues>
readOnly={readOnly}
isEditable={isManageableAlertManagerDataSource}
isTestable={isManageableAlertManagerDataSource}
config={config}
onSubmit={onSubmit}
initialValues={existingValue}
@@ -114,7 +114,12 @@ export const GrafanaReceiverForm: FC<Props> = ({ existing, alertManagerSourceNam
? (existing.grafana_managed_receiver_configs ?? []).some((item) => Boolean(item.provenance))
: false;
const readOnly = isVanillaPrometheusAlertManagerDataSource(alertManagerSourceName) || hasProvisionedItems;
// this basically checks if we can manage the selected alert manager data source, either because it's a Grafana Managed one
// or a Mimir-based AlertManager
const isManageableAlertManagerDataSource = !isVanillaPrometheusAlertManagerDataSource(alertManagerSourceName);
const isEditable = isManageableAlertManagerDataSource && !hasProvisionedItems;
const isTestable = isManageableAlertManagerDataSource || hasProvisionedItems;
if (grafanaNotifiers.result) {
return (
@@ -122,7 +127,8 @@ export const GrafanaReceiverForm: FC<Props> = ({ existing, alertManagerSourceNam
{hasProvisionedItems && <ProvisioningAlert resource={ProvisionedResource.ContactPoint} />}
<ReceiverForm<GrafanaChannelValues>
readOnly={readOnly}
isEditable={isEditable}
isTestable={isTestable}
config={config}
onSubmit={onSubmit}
initialValues={existingValue}
@@ -27,7 +27,8 @@ interface Props<R extends ChannelValues> {
takenReceiverNames: string[]; // will validate that user entered receiver name is not one of these
commonSettingsComponent: CommonSettingsComponentType;
initialValues?: ReceiverFormValues<R>;
readOnly: boolean;
isEditable: boolean;
isTestable?: boolean;
}
export function ReceiverForm<R extends ChannelValues>({
@@ -40,7 +41,8 @@ export function ReceiverForm<R extends ChannelValues>({
onTestChannel,
takenReceiverNames,
commonSettingsComponent,
readOnly,
isEditable,
isTestable,
}: Props<R>): JSX.Element {
const notifyApp = useAppNotification();
const styles = useStyles2(getStyles);
@@ -101,11 +103,11 @@ export function ReceiverForm<R extends ChannelValues>({
)}
<form onSubmit={handleSubmit(submitCallback, onInvalid)}>
<h4 className={styles.heading}>
{readOnly ? 'Contact point' : initialValues ? 'Update contact point' : 'Create contact point'}
{!isEditable ? 'Contact point' : initialValues ? 'Update contact point' : 'Create contact point'}
</h4>
<Field label="Name" invalid={!!errors.name} error={errors.name && errors.name.message} required>
<Input
readOnly={readOnly}
readOnly={!isEditable}
id="name"
{...register('name', {
required: 'Name is required',
@@ -143,12 +145,13 @@ export function ReceiverForm<R extends ChannelValues>({
secureFields={initialItem?.secureFields}
errors={errors?.items?.[index] as FieldErrors<R>}
commonSettingsComponent={commonSettingsComponent}
readOnly={readOnly}
isEditable={isEditable}
isTestable={isTestable}
/>
);
})}
<>
{!readOnly && (
{isEditable && (
<Button
type="button"
icon="plus"
@@ -159,7 +162,7 @@ export function ReceiverForm<R extends ChannelValues>({
</Button>
)}
<div className={styles.buttons}>
{!readOnly && (
{isEditable && (
<>
{loading && (
<Button disabled={true} icon="fa fa-spinner" variant="primary">