mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Remove Form usage from notification policies (#81758)
* Chore: Replace Form component usage in EditDefaultPolicyForm.tsx * Chore: Replace Form component usage in EditNotificationPolicyForm.tsx * Remove ts-ignore
This commit is contained in:
parent
5460d75e74
commit
5132828a2b
@ -1,6 +1,7 @@
|
||||
import React, { ReactNode, useState } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
|
||||
import { Collapse, Field, Form, InputControl, Link, MultiSelect, Select, useStyles2 } from '@grafana/ui';
|
||||
import { Collapse, Field, Link, MultiSelect, Select, useStyles2 } from '@grafana/ui';
|
||||
import { RouteWithID } from 'app/plugins/datasource/alertmanager/types';
|
||||
|
||||
import { FormAmRoute } from '../../types/amroutes';
|
||||
@ -41,125 +42,131 @@ export const AmRootRouteForm = ({
|
||||
const [groupByOptions, setGroupByOptions] = useState(stringsToSelectableValues(route.group_by));
|
||||
|
||||
const defaultValues = amRouteToFormAmRoute(route);
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
register,
|
||||
control,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
getValues,
|
||||
} = useForm<FormAmRoute>({
|
||||
defaultValues: {
|
||||
...defaultValues,
|
||||
overrideTimings: true,
|
||||
overrideGrouping: true,
|
||||
},
|
||||
});
|
||||
return (
|
||||
<Form defaultValues={{ ...defaultValues, overrideTimings: true, overrideGrouping: true }} onSubmit={onSubmit}>
|
||||
{({ register, control, errors, setValue, getValues }) => (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Field label="Default contact point" invalid={!!errors.receiver} error={errors.receiver?.message}>
|
||||
<>
|
||||
<Field label="Default contact point" invalid={!!errors.receiver} error={errors.receiver?.message}>
|
||||
<>
|
||||
<div className={styles.container} data-testid="am-receiver-select">
|
||||
<InputControl
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<Select
|
||||
aria-label="Default contact point"
|
||||
{...field}
|
||||
className={styles.input}
|
||||
onChange={(value) => onChange(mapSelectValueToString(value))}
|
||||
options={receivers}
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="receiver"
|
||||
rules={{ required: { value: true, message: 'Required.' } }}
|
||||
/>
|
||||
<span>or</span>
|
||||
<Link
|
||||
className={styles.linkText}
|
||||
href={makeAMLink('/alerting/notifications/receivers/new', alertManagerSourceName)}
|
||||
>
|
||||
Create a contact point
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
</Field>
|
||||
<Field
|
||||
label="Group by"
|
||||
description="Group alerts when you receive a notification based on labels."
|
||||
data-testid="am-group-select"
|
||||
>
|
||||
{/* @ts-ignore-check: react-hook-form made me do this */}
|
||||
<InputControl
|
||||
<div className={styles.container} data-testid="am-receiver-select">
|
||||
<Controller
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<MultiSelect
|
||||
aria-label="Group by"
|
||||
<Select
|
||||
aria-label="Default contact point"
|
||||
{...field}
|
||||
allowCustomValue
|
||||
className={styles.input}
|
||||
onCreateOption={(opt: string) => {
|
||||
setGroupByOptions((opts) => [...opts, stringToSelectableValue(opt)]);
|
||||
|
||||
// @ts-ignore-check: react-hook-form made me do this
|
||||
setValue('groupBy', [...field.value, opt]);
|
||||
}}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={[...commonGroupByOptions, ...groupByOptions]}
|
||||
onChange={(value) => onChange(mapSelectValueToString(value))}
|
||||
options={receivers}
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="groupBy"
|
||||
name="receiver"
|
||||
rules={{ required: { value: true, message: 'Required.' } }}
|
||||
/>
|
||||
<span>or</span>
|
||||
<Link
|
||||
className={styles.linkText}
|
||||
href={makeAMLink('/alerting/notifications/receivers/new', alertManagerSourceName)}
|
||||
>
|
||||
Create a contact point
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
</Field>
|
||||
<Field
|
||||
label="Group by"
|
||||
description="Group alerts when you receive a notification based on labels."
|
||||
data-testid="am-group-select"
|
||||
>
|
||||
<Controller
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<MultiSelect
|
||||
aria-label="Group by"
|
||||
{...field}
|
||||
allowCustomValue
|
||||
className={styles.input}
|
||||
onCreateOption={(opt: string) => {
|
||||
setGroupByOptions((opts) => [...opts, stringToSelectableValue(opt)]);
|
||||
setValue('groupBy', [...(field.value || []), opt]);
|
||||
}}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={[...commonGroupByOptions, ...groupByOptions]}
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="groupBy"
|
||||
/>
|
||||
</Field>
|
||||
<Collapse
|
||||
collapsible
|
||||
className={styles.collapse}
|
||||
isOpen={isTimingOptionsExpanded}
|
||||
label="Timing options"
|
||||
onToggle={setIsTimingOptionsExpanded}
|
||||
>
|
||||
<div className={styles.timingFormContainer}>
|
||||
<Field
|
||||
label="Group wait"
|
||||
description="The waiting time until the initial notification is sent for a new group created by an incoming alert. Default 30 seconds."
|
||||
invalid={!!errors.groupWaitValue}
|
||||
error={errors.groupWaitValue?.message}
|
||||
data-testid="am-group-wait"
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupWaitValue', { validate: promDurationValidator })}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.group_wait}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Group wait"
|
||||
/>
|
||||
</Field>
|
||||
<Collapse
|
||||
collapsible
|
||||
className={styles.collapse}
|
||||
isOpen={isTimingOptionsExpanded}
|
||||
label="Timing options"
|
||||
onToggle={setIsTimingOptionsExpanded}
|
||||
<Field
|
||||
label="Group interval"
|
||||
description="The waiting time to send a batch of new alerts for that group after the first notification was sent. Default 5 minutes."
|
||||
invalid={!!errors.groupIntervalValue}
|
||||
error={errors.groupIntervalValue?.message}
|
||||
data-testid="am-group-interval"
|
||||
>
|
||||
<div className={styles.timingFormContainer}>
|
||||
<Field
|
||||
label="Group wait"
|
||||
description="The waiting time until the initial notification is sent for a new group created by an incoming alert. Default 30 seconds."
|
||||
invalid={!!errors.groupWaitValue}
|
||||
error={errors.groupWaitValue?.message}
|
||||
data-testid="am-group-wait"
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupWaitValue', { validate: promDurationValidator })}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.group_wait}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Group wait"
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Group interval"
|
||||
description="The waiting time to send a batch of new alerts for that group after the first notification was sent. Default 5 minutes."
|
||||
invalid={!!errors.groupIntervalValue}
|
||||
error={errors.groupIntervalValue?.message}
|
||||
data-testid="am-group-interval"
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupIntervalValue', { validate: promDurationValidator })}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.group_interval}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Group interval"
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Repeat interval"
|
||||
description="The waiting time to resend an alert after they have successfully been sent. Default 4 hours. Should be a multiple of Group interval."
|
||||
invalid={!!errors.repeatIntervalValue}
|
||||
error={errors.repeatIntervalValue?.message}
|
||||
data-testid="am-repeat-interval"
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('repeatIntervalValue', {
|
||||
validate: (value: string) => {
|
||||
const groupInterval = getValues('groupIntervalValue');
|
||||
return repeatIntervalValidator(value, groupInterval);
|
||||
},
|
||||
})}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.repeat_interval}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Repeat interval"
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</Collapse>
|
||||
<div className={styles.container}>{actionButtons}</div>
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
<PromDurationInput
|
||||
{...register('groupIntervalValue', { validate: promDurationValidator })}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.group_interval}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Group interval"
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Repeat interval"
|
||||
description="The waiting time to resend an alert after they have successfully been sent. Default 4 hours. Should be a multiple of Group interval."
|
||||
invalid={!!errors.repeatIntervalValue}
|
||||
error={errors.repeatIntervalValue?.message}
|
||||
data-testid="am-repeat-interval"
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('repeatIntervalValue', {
|
||||
validate: (value: string) => {
|
||||
const groupInterval = getValues('groupIntervalValue');
|
||||
return repeatIntervalValidator(value, groupInterval);
|
||||
},
|
||||
})}
|
||||
placeholder={TIMING_OPTIONS_DEFAULTS.repeat_interval}
|
||||
className={styles.promDurationInput}
|
||||
aria-label="Repeat interval"
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</Collapse>
|
||||
<div className={styles.container}>{actionButtons}</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { ReactNode, useState } from 'react';
|
||||
import { useForm, Controller, useFieldArray } from 'react-hook-form';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Field,
|
||||
FieldArray,
|
||||
FieldValidationMessage,
|
||||
Form,
|
||||
IconButton,
|
||||
Input,
|
||||
InputControl,
|
||||
MultiSelect,
|
||||
Select,
|
||||
Stack,
|
||||
@ -75,224 +73,228 @@ export const AmRoutesExpandedForm = ({
|
||||
object_matchers: route ? formAmRoute.object_matchers : emptyMatcher,
|
||||
};
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
register,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
watch,
|
||||
getValues,
|
||||
} = useForm<FormAmRoute>({
|
||||
defaultValues,
|
||||
});
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
name: 'object_matchers',
|
||||
});
|
||||
|
||||
return (
|
||||
<Form defaultValues={defaultValues} onSubmit={onSubmit} maxWidth="none">
|
||||
{({ control, register, errors, setValue, watch, getValues }) => (
|
||||
<>
|
||||
<input type="hidden" {...register('id')} />
|
||||
{/* @ts-ignore-check: react-hook-form made me do this */}
|
||||
<FieldArray name="object_matchers" control={control}>
|
||||
{({ fields, append, remove }) => (
|
||||
<>
|
||||
<Stack direction="column" alignItems="flex-start">
|
||||
<div>Matching labels</div>
|
||||
{fields.length === 0 && (
|
||||
<Badge
|
||||
color="orange"
|
||||
className={styles.noMatchersWarning}
|
||||
icon="exclamation-triangle"
|
||||
text="If no matchers are specified, this notification policy will handle all alert instances."
|
||||
/>
|
||||
)}
|
||||
{fields.length > 0 && (
|
||||
<div className={styles.matchersContainer}>
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<Stack direction="row" key={field.id} alignItems="center">
|
||||
<Field
|
||||
label="Label"
|
||||
invalid={!!errors.object_matchers?.[index]?.name}
|
||||
error={errors.object_matchers?.[index]?.name?.message}
|
||||
>
|
||||
<Input
|
||||
{...register(`object_matchers.${index}.name`, { required: 'Field is required' })}
|
||||
defaultValue={field.name}
|
||||
placeholder="label"
|
||||
autoFocus
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Operator'}>
|
||||
<InputControl
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<Select
|
||||
{...field}
|
||||
className={styles.matchersOperator}
|
||||
onChange={(value) => onChange(value?.value)}
|
||||
options={matcherFieldOptions}
|
||||
aria-label="Operator"
|
||||
/>
|
||||
)}
|
||||
defaultValue={field.operator}
|
||||
control={control}
|
||||
name={`object_matchers.${index}.operator`}
|
||||
rules={{ required: { value: true, message: 'Required.' } }}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Value"
|
||||
invalid={!!errors.object_matchers?.[index]?.value}
|
||||
error={errors.object_matchers?.[index]?.value?.message}
|
||||
>
|
||||
<Input
|
||||
{...register(`object_matchers.${index}.value`)}
|
||||
defaultValue={field.value}
|
||||
placeholder="value"
|
||||
/>
|
||||
</Field>
|
||||
<IconButton tooltip="Remove matcher" name={'trash-alt'} onClick={() => remove(index)}>
|
||||
Remove
|
||||
</IconButton>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
className={styles.addMatcherBtn}
|
||||
icon="plus"
|
||||
onClick={() => append(emptyArrayFieldMatcher)}
|
||||
variant="secondary"
|
||||
type="button"
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<input type="hidden" {...register('id')} />
|
||||
<Stack direction="column" alignItems="flex-start">
|
||||
<div>Matching labels</div>
|
||||
{fields.length === 0 && (
|
||||
<Badge
|
||||
color="orange"
|
||||
className={styles.noMatchersWarning}
|
||||
icon="exclamation-triangle"
|
||||
text="If no matchers are specified, this notification policy will handle all alert instances."
|
||||
/>
|
||||
)}
|
||||
{fields.length > 0 && (
|
||||
<div className={styles.matchersContainer}>
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<Stack direction="row" key={field.id} alignItems="center">
|
||||
<Field
|
||||
label="Label"
|
||||
invalid={!!errors.object_matchers?.[index]?.name}
|
||||
error={errors.object_matchers?.[index]?.name?.message}
|
||||
>
|
||||
Add matcher
|
||||
</Button>
|
||||
<Input
|
||||
{...register(`object_matchers.${index}.name`, { required: 'Field is required' })}
|
||||
defaultValue={field.name}
|
||||
placeholder="label"
|
||||
autoFocus
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Operator'}>
|
||||
<Controller
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<Select
|
||||
{...field}
|
||||
className={styles.matchersOperator}
|
||||
onChange={(value) => onChange(value?.value)}
|
||||
options={matcherFieldOptions}
|
||||
aria-label="Operator"
|
||||
/>
|
||||
)}
|
||||
defaultValue={field.operator}
|
||||
control={control}
|
||||
name={`object_matchers.${index}.operator`}
|
||||
rules={{ required: { value: true, message: 'Required.' } }}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Value"
|
||||
invalid={!!errors.object_matchers?.[index]?.value}
|
||||
error={errors.object_matchers?.[index]?.value?.message}
|
||||
>
|
||||
<Input
|
||||
{...register(`object_matchers.${index}.value`)}
|
||||
defaultValue={field.value}
|
||||
placeholder="value"
|
||||
/>
|
||||
</Field>
|
||||
<IconButton tooltip="Remove matcher" name={'trash-alt'} onClick={() => remove(index)}>
|
||||
Remove
|
||||
</IconButton>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
className={styles.addMatcherBtn}
|
||||
icon="plus"
|
||||
onClick={() => append(emptyArrayFieldMatcher)}
|
||||
variant="secondary"
|
||||
type="button"
|
||||
>
|
||||
Add matcher
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<Field label="Contact point">
|
||||
<Controller
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<Select
|
||||
aria-label="Contact point"
|
||||
{...field}
|
||||
className={formStyles.input}
|
||||
onChange={(value) => onChange(mapSelectValueToString(value))}
|
||||
options={receiversWithOnCallOnTop}
|
||||
isClearable
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="receiver"
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Continue matching subsequent sibling nodes">
|
||||
<Switch id="continue-toggle" {...register('continue')} />
|
||||
</Field>
|
||||
<Field label="Override grouping">
|
||||
<Switch id="override-grouping-toggle" {...register('overrideGrouping')} />
|
||||
</Field>
|
||||
{watch().overrideGrouping && (
|
||||
<Field
|
||||
label="Group by"
|
||||
description="Group alerts when you receive a notification based on labels. If empty it will be inherited from the parent policy."
|
||||
>
|
||||
<Controller
|
||||
rules={{
|
||||
validate: (value) => {
|
||||
if (!value || value.length === 0) {
|
||||
return 'At least one group by option is required.';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}}
|
||||
render={({ field: { onChange, ref, ...field }, fieldState: { error } }) => (
|
||||
<>
|
||||
<MultiSelect
|
||||
aria-label="Group by"
|
||||
{...field}
|
||||
invalid={Boolean(error)}
|
||||
allowCustomValue
|
||||
className={formStyles.input}
|
||||
onCreateOption={(opt: string) => {
|
||||
setGroupByOptions((opts) => [...opts, stringToSelectableValue(opt)]);
|
||||
setValue('groupBy', [...(field.value || []), opt]);
|
||||
}}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={[...commonGroupByOptions, ...groupByOptions]}
|
||||
/>
|
||||
{error && <FieldValidationMessage>{error.message}</FieldValidationMessage>}
|
||||
</>
|
||||
)}
|
||||
</FieldArray>
|
||||
<Field label="Contact point">
|
||||
<InputControl
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<Select
|
||||
aria-label="Contact point"
|
||||
{...field}
|
||||
className={formStyles.input}
|
||||
onChange={(value) => onChange(mapSelectValueToString(value))}
|
||||
options={receiversWithOnCallOnTop}
|
||||
isClearable
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="receiver"
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Continue matching subsequent sibling nodes">
|
||||
<Switch id="continue-toggle" {...register('continue')} />
|
||||
</Field>
|
||||
<Field label="Override grouping">
|
||||
<Switch id="override-grouping-toggle" {...register('overrideGrouping')} />
|
||||
</Field>
|
||||
{watch().overrideGrouping && (
|
||||
<Field
|
||||
label="Group by"
|
||||
description="Group alerts when you receive a notification based on labels. If empty it will be inherited from the parent policy."
|
||||
>
|
||||
<InputControl
|
||||
rules={{
|
||||
validate: (value) => {
|
||||
if (!value || value.length === 0) {
|
||||
return 'At least one group by option is required.';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}}
|
||||
render={({ field: { onChange, ref, ...field }, fieldState: { error } }) => (
|
||||
<>
|
||||
<MultiSelect
|
||||
aria-label="Group by"
|
||||
{...field}
|
||||
invalid={Boolean(error)}
|
||||
allowCustomValue
|
||||
className={formStyles.input}
|
||||
onCreateOption={(opt: string) => {
|
||||
setGroupByOptions((opts) => [...opts, stringToSelectableValue(opt)]);
|
||||
|
||||
// @ts-ignore-check: react-hook-form made me do this
|
||||
setValue('groupBy', [...field.value, opt]);
|
||||
}}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={[...commonGroupByOptions, ...groupByOptions]}
|
||||
/>
|
||||
{error && <FieldValidationMessage>{error.message}</FieldValidationMessage>}
|
||||
</>
|
||||
)}
|
||||
control={control}
|
||||
name="groupBy"
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
<Field label="Override general timings">
|
||||
<Switch id="override-timings-toggle" {...register('overrideTimings')} />
|
||||
</Field>
|
||||
{watch().overrideTimings && (
|
||||
<>
|
||||
<Field
|
||||
label={routeTimingsFields.groupWait.label}
|
||||
description={routeTimingsFields.groupWait.description}
|
||||
invalid={!!errors.groupWaitValue}
|
||||
error={errors.groupWaitValue?.message}
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupWaitValue', { validate: promDurationValidator })}
|
||||
aria-label={routeTimingsFields.groupWait.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={routeTimingsFields.groupInterval.label}
|
||||
description={routeTimingsFields.groupInterval.description}
|
||||
invalid={!!errors.groupIntervalValue}
|
||||
error={errors.groupIntervalValue?.message}
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupIntervalValue', { validate: promDurationValidator })}
|
||||
aria-label={routeTimingsFields.groupInterval.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={routeTimingsFields.repeatInterval.label}
|
||||
description={routeTimingsFields.repeatInterval.description}
|
||||
invalid={!!errors.repeatIntervalValue}
|
||||
error={errors.repeatIntervalValue?.message}
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('repeatIntervalValue', {
|
||||
validate: (value = '') => {
|
||||
const groupInterval = getValues('groupIntervalValue');
|
||||
return repeatIntervalValidator(value, groupInterval);
|
||||
},
|
||||
})}
|
||||
aria-label={routeTimingsFields.repeatInterval.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
control={control}
|
||||
name="groupBy"
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
<Field label="Override general timings">
|
||||
<Switch id="override-timings-toggle" {...register('overrideTimings')} />
|
||||
</Field>
|
||||
{watch().overrideTimings && (
|
||||
<>
|
||||
<Field
|
||||
label="Mute timings"
|
||||
data-testid="am-mute-timing-select"
|
||||
description="Add mute timing to policy"
|
||||
invalid={!!errors.muteTimeIntervals}
|
||||
label={routeTimingsFields.groupWait.label}
|
||||
description={routeTimingsFields.groupWait.description}
|
||||
invalid={!!errors.groupWaitValue}
|
||||
error={errors.groupWaitValue?.message}
|
||||
>
|
||||
<InputControl
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<MultiSelect
|
||||
aria-label="Mute timings"
|
||||
{...field}
|
||||
className={formStyles.input}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={muteTimingOptions}
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="muteTimeIntervals"
|
||||
<PromDurationInput
|
||||
{...register('groupWaitValue', { validate: promDurationValidator })}
|
||||
aria-label={routeTimingsFields.groupWait.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={routeTimingsFields.groupInterval.label}
|
||||
description={routeTimingsFields.groupInterval.description}
|
||||
invalid={!!errors.groupIntervalValue}
|
||||
error={errors.groupIntervalValue?.message}
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('groupIntervalValue', { validate: promDurationValidator })}
|
||||
aria-label={routeTimingsFields.groupInterval.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label={routeTimingsFields.repeatInterval.label}
|
||||
description={routeTimingsFields.repeatInterval.description}
|
||||
invalid={!!errors.repeatIntervalValue}
|
||||
error={errors.repeatIntervalValue?.message}
|
||||
>
|
||||
<PromDurationInput
|
||||
{...register('repeatIntervalValue', {
|
||||
validate: (value = '') => {
|
||||
const groupInterval = getValues('groupIntervalValue');
|
||||
return repeatIntervalValidator(value, groupInterval);
|
||||
},
|
||||
})}
|
||||
aria-label={routeTimingsFields.repeatInterval.ariaLabel}
|
||||
className={formStyles.promDurationInput}
|
||||
/>
|
||||
</Field>
|
||||
{actionButtons}
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
<Field
|
||||
label="Mute timings"
|
||||
data-testid="am-mute-timing-select"
|
||||
description="Add mute timing to policy"
|
||||
invalid={!!errors.muteTimeIntervals}
|
||||
>
|
||||
<Controller
|
||||
render={({ field: { onChange, ref, ...field } }) => (
|
||||
<MultiSelect
|
||||
aria-label="Mute timings"
|
||||
{...field}
|
||||
className={formStyles.input}
|
||||
onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
|
||||
options={muteTimingOptions}
|
||||
/>
|
||||
)}
|
||||
control={control}
|
||||
name="muteTimeIntervals"
|
||||
/>
|
||||
</Field>
|
||||
{actionButtons}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user