forked from grafana.jool/grafana-jool
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
6.7 KiB
163 lines
6.7 KiB
import React from 'react';
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { Button, Input, Field, FieldSet, useStyles2 } from '@grafana/ui';
|
|
import { css } from '@emotion/css';
|
|
import { useFormContext, useFieldArray } from 'react-hook-form';
|
|
import { DAYS_OF_THE_WEEK, MONTHS, validateArrayField, defaultTimeInterval } from '../../utils/mute-timings';
|
|
import { MuteTimingFields } from '../../types/mute-timing-form';
|
|
import { MuteTimingTimeRange } from './MuteTimingTimeRange';
|
|
|
|
export const MuteTimingTimeInterval = () => {
|
|
const styles = useStyles2(getStyles);
|
|
const { formState, register } = useFormContext();
|
|
const {
|
|
fields: timeIntervals,
|
|
append: addTimeInterval,
|
|
remove: removeTimeInterval,
|
|
} = useFieldArray<MuteTimingFields>({
|
|
name: 'time_intervals',
|
|
});
|
|
|
|
return (
|
|
<FieldSet className={styles.timeIntervalLegend} label="Time intervals">
|
|
<>
|
|
<p>
|
|
A time interval is a definition for a moment in time. All fields are lists, and at least one list element must
|
|
be satisfied to match the field. If a field is left blank, any moment of time will match the field. For an
|
|
instant of time to match a complete time interval, all fields must match. A mute timing can contain multiple
|
|
time intervals.
|
|
</p>
|
|
{timeIntervals.map((timeInterval, timeIntervalIndex) => {
|
|
const errors = formState.errors;
|
|
return (
|
|
<div key={timeInterval.id} className={styles.timeIntervalSection}>
|
|
<MuteTimingTimeRange intervalIndex={timeIntervalIndex} />
|
|
<Field
|
|
label="Days of the week"
|
|
error={errors.time_intervals?.[timeIntervalIndex]?.weekdays?.message ?? ''}
|
|
invalid={!!errors.time_intervals?.[timeIntervalIndex]?.weekdays}
|
|
>
|
|
<Input
|
|
{...register(`time_intervals.${timeIntervalIndex}.weekdays`, {
|
|
validate: (value) =>
|
|
validateArrayField(
|
|
value,
|
|
(day) => DAYS_OF_THE_WEEK.includes(day.toLowerCase()),
|
|
'Invalid day of the week'
|
|
),
|
|
})}
|
|
className={styles.input}
|
|
data-testid="mute-timing-weekdays"
|
|
// @ts-ignore react-hook-form doesn't handle nested field arrays well
|
|
defaultValue={timeInterval.weekdays}
|
|
placeholder="Example: monday, tuesday:thursday"
|
|
/>
|
|
</Field>
|
|
<Field
|
|
label="Days of the month"
|
|
description="The days of the month, 1-31, of a month. Negative values can be used to represent days which begin at the end of the month"
|
|
invalid={!!errors.time_intervals?.[timeIntervalIndex]?.days_of_month}
|
|
error={errors.time_intervals?.[timeIntervalIndex]?.days_of_month?.message}
|
|
>
|
|
<Input
|
|
{...register(`time_intervals.${timeIntervalIndex}.days_of_month`, {
|
|
validate: (value) =>
|
|
validateArrayField(
|
|
value,
|
|
(day) => {
|
|
const parsedDay = parseInt(day, 10);
|
|
return (parsedDay > -31 && parsedDay < 0) || (parsedDay > 0 && parsedDay < 32);
|
|
},
|
|
'Invalid day'
|
|
),
|
|
})}
|
|
className={styles.input}
|
|
// @ts-ignore react-hook-form doesn't handle nested field arrays well
|
|
defaultValue={timeInterval.days_of_month}
|
|
placeholder="Example: 1, 14:16, -1"
|
|
data-testid="mute-timing-days"
|
|
/>
|
|
</Field>
|
|
<Field
|
|
label="Months"
|
|
description="The months of the year in either numerical or the full calendar month"
|
|
invalid={!!errors.time_intervals?.[timeIntervalIndex]?.months}
|
|
error={errors.time_intervals?.[timeIntervalIndex]?.months?.message}
|
|
>
|
|
<Input
|
|
{...register(`time_intervals.${timeIntervalIndex}.months`, {
|
|
validate: (value) =>
|
|
validateArrayField(
|
|
value,
|
|
(month) => MONTHS.includes(month) || (parseInt(month, 10) < 13 && parseInt(month, 10) > 0),
|
|
'Invalid month'
|
|
),
|
|
})}
|
|
className={styles.input}
|
|
placeholder="Example: 1:3, may:august, december"
|
|
// @ts-ignore react-hook-form doesn't handle nested field arrays well
|
|
defaultValue={timeInterval.months}
|
|
data-testid="mute-timing-months"
|
|
/>
|
|
</Field>
|
|
<Field
|
|
label="Years"
|
|
invalid={!!errors.time_intervals?.[timeIntervalIndex]?.years}
|
|
error={errors.time_intervals?.[timeIntervalIndex]?.years?.message ?? ''}
|
|
>
|
|
<Input
|
|
{...register(`time_intervals.${timeIntervalIndex}.years`, {
|
|
validate: (value) => validateArrayField(value, (year) => /^\d{4}$/.test(year), 'Invalid year'),
|
|
})}
|
|
className={styles.input}
|
|
placeholder="Example: 2021:2022, 2030"
|
|
// @ts-ignore react-hook-form doesn't handle nested field arrays well
|
|
defaultValue={timeInterval.years}
|
|
data-testid="mute-timing-years"
|
|
/>
|
|
</Field>
|
|
<Button
|
|
type="button"
|
|
variant="destructive"
|
|
icon="trash-alt"
|
|
onClick={() => removeTimeInterval(timeIntervalIndex)}
|
|
>
|
|
Remove time interval
|
|
</Button>
|
|
</div>
|
|
);
|
|
})}
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
className={styles.removeTimeIntervalButton}
|
|
onClick={() => {
|
|
addTimeInterval(defaultTimeInterval);
|
|
}}
|
|
icon="plus"
|
|
>
|
|
Add another time interval
|
|
</Button>
|
|
</>
|
|
</FieldSet>
|
|
);
|
|
};
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => ({
|
|
input: css`
|
|
width: 400px;
|
|
`,
|
|
timeIntervalLegend: css`
|
|
legend {
|
|
font-size: 1.25rem;
|
|
}
|
|
`,
|
|
timeIntervalSection: css`
|
|
background-color: ${theme.colors.background.secondary};
|
|
padding: ${theme.spacing(1)};
|
|
margin-bottom: ${theme.spacing(1)};
|
|
`,
|
|
removeTimeIntervalButton: css`
|
|
margin-top: ${theme.spacing(1)};
|
|
`,
|
|
});
|
|
|