Address misc PR feedback

This commit is contained in:
Tom Ratcliffe 2024-04-26 15:45:34 +01:00 committed by Tom Ratcliffe
parent 9860117399
commit a34c02fcf2
3 changed files with 44 additions and 26 deletions

View File

@ -28,7 +28,7 @@ const renderSilences = (location = '/alerting/silences/') => {
<Silences />
</AlertmanagerProvider>,
{
routerOptions: {
historyOptions: {
initialEntries: [location],
},
}
@ -156,10 +156,11 @@ describe('Silences', () => {
it(
'filters silences by matchers',
async () => {
const user = userEvent.setup();
renderSilences();
const queryBar = await ui.queryBar.find();
await userEvent.type(queryBar, 'foo=bar');
await user.type(queryBar, 'foo=bar');
await waitFor(() => expect(ui.silenceRow.getAll()).toHaveLength(2));
},
@ -238,6 +239,7 @@ describe('Silence create/edit', () => {
it(
'creates a new silence',
async () => {
const user = userEvent.setup();
renderSilences(baseUrlPath);
expect(await ui.editor.durationField.find()).toBeInTheDocument();
@ -249,8 +251,8 @@ describe('Silence create/edit', () => {
const startDateString = dateTime(start).format('YYYY-MM-DD');
const endDateString = dateTime(end).format('YYYY-MM-DD');
await userEvent.clear(ui.editor.durationInput.get());
await userEvent.type(ui.editor.durationInput.get(), '1d');
await user.clear(ui.editor.durationInput.get());
await user.type(ui.editor.durationInput.get(), '1d');
await waitFor(() => expect(ui.editor.durationInput.query()).toHaveValue('1d'));
await waitFor(() => expect(ui.editor.timeRange.get()).toHaveTextContent(startDateString));
@ -267,7 +269,7 @@ describe('Silence create/edit', () => {
await addAdditionalMatcher();
await enterSilenceLabel(3, 'env', MatcherOperator.notRegex, 'dev|staging');
await userEvent.click(ui.editor.submit.get());
await user.click(ui.editor.submit.get());
expect(await ui.notExpiredTable.find()).toBeInTheDocument();

View File

@ -2,7 +2,6 @@ import { css, cx } from '@emotion/css';
import { isEqual, pickBy } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useHistory } from 'react-router';
import { useDebounce } from 'react-use';
import {
@ -14,8 +13,18 @@ import {
isValidDate,
parseDuration,
} from '@grafana/data';
import { config } from '@grafana/runtime';
import { Button, Field, FieldSet, Input, LinkButton, TextArea, useStyles2 } from '@grafana/ui';
import { config, isFetchError, locationService } from '@grafana/runtime';
import {
Alert,
Button,
Field,
FieldSet,
Input,
LinkButton,
LoadingPlaceholder,
TextArea,
useStyles2,
} from '@grafana/ui';
import { alertSilencesApi } from 'app/features/alerting/unified/api/alertSilencesApi';
import { getDatasourceAPIUid } from 'app/features/alerting/unified/utils/datasource';
import { Matcher, MatcherOperator, Silence, SilenceCreatePayload } from 'app/plugins/datasource/alertmanager/types';
@ -96,8 +105,9 @@ const getDefaultFormValues = (searchParams: URLSearchParams, silence?: Silence):
};
export const SilencesEditor = ({ silenceId, alertManagerSourceName }: Props) => {
const history = useHistory();
const [getSilence, { data: silence, isLoading: getSilenceIsLoading }] =
// Use a lazy query to fetch the Silence info, as we may not always require this
// (e.g. if creating a new one from scratch, we don't need to fetch anything)
const [getSilence, { data: silence, isLoading: getSilenceIsLoading, error: errorGettingExistingSilence }] =
alertSilencesApi.endpoints.getSilence.useLazyQuery();
const [createSilence, { isLoading }] = alertSilencesApi.endpoints.createSilence.useMutation();
const [urlSearchParams] = useURLSearchParams();
@ -129,7 +139,7 @@ export const SilencesEditor = ({ silenceId, alertManagerSourceName }: Props) =>
await createSilence({ datasourceUid: getDatasourceAPIUid(alertManagerSourceName), payload })
.unwrap()
.then(() => {
history.push(makeAMLink('/alerting/silences', alertManagerSourceName));
locationService.push(makeAMLink('/alerting/silences', alertManagerSourceName));
});
};
@ -139,8 +149,10 @@ export const SilencesEditor = ({ silenceId, alertManagerSourceName }: Props) =>
const matcherFields = watch('matchers');
useEffect(() => {
// Allows the form to correctly initialise when an existing silence is fetch from the backend
reset(getDefaultFormValues(urlSearchParams, silence));
if (silence) {
// Allows the form to correctly initialise when an existing silence is fetch from the backend
reset(getDefaultFormValues(urlSearchParams, silence));
}
}, [reset, silence, urlSearchParams]);
useEffect(() => {
@ -190,13 +202,20 @@ export const SilencesEditor = ({ silenceId, alertManagerSourceName }: Props) =>
const userLogged = Boolean(config.bootData.user.isSignedIn && config.bootData.user.name);
if (getSilenceIsLoading) {
return null;
return <LoadingPlaceholder text="Loading existing silence information..." />;
}
const existingSilenceNotFound =
isFetchError(errorGettingExistingSilence) && errorGettingExistingSilence.status === 404;
if (existingSilenceNotFound) {
return <Alert title={`Existing silence "${silenceId}" not found`} severity="warning" />;
}
return (
<FormProvider {...formAPI}>
<form onSubmit={handleSubmit(onSubmit)}>
<FieldSet label={silenceId ? 'Recreate silence' : 'Create silence'}>
<FieldSet>
<div className={cx(styles.flexRow, styles.silencePeriod)}>
<SilencePeriod />
<Field

View File

@ -3,7 +3,7 @@ import React, { useMemo } from 'react';
import { dateMath, GrafanaTheme2 } from '@grafana/data';
import { isFetchError } from '@grafana/runtime';
import { CollapsableSection, Icon, Link, LinkButton, useStyles2, Stack, Alert } from '@grafana/ui';
import { CollapsableSection, Icon, Link, LinkButton, useStyles2, Stack, Alert, LoadingPlaceholder } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { alertSilencesApi } from 'app/features/alerting/unified/api/alertSilencesApi';
import { alertmanagerApi } from 'app/features/alerting/unified/api/alertmanagerApi';
@ -14,7 +14,7 @@ import { AlertmanagerAlert, Silence, SilenceState } from 'app/plugins/datasource
import { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities';
import { parseMatchers } from '../../utils/alertmanager';
import { getSilenceFiltersFromUrlParams, makeAMLink } from '../../utils/misc';
import { getSilenceFiltersFromUrlParams, makeAMLink, stringifyErrorLike } from '../../utils/misc';
import { Authorize } from '../Authorize';
import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable';
import { ActionButton } from '../rules/ActionButton';
@ -36,11 +36,13 @@ interface Props {
alertManagerSourceName: string;
}
const API_QUERY_OPTIONS = { pollingInterval: SILENCES_POLL_INTERVAL_MS, refetchOnFocus: true };
const SilencesTable = ({ alertManagerSourceName }: Props) => {
const { data: alertManagerAlerts = [], isLoading: amAlertsIsLoading } =
alertmanagerApi.endpoints.getAlertmanagerAlerts.useQuery(
{ amSourceName: alertManagerSourceName, filter: { silenced: true, active: true, inhibited: true } },
{ pollingInterval: SILENCES_POLL_INTERVAL_MS }
API_QUERY_OPTIONS
);
const {
@ -49,9 +51,7 @@ const SilencesTable = ({ alertManagerSourceName }: Props) => {
error,
} = alertSilencesApi.endpoints.getSilences.useQuery(
{ datasourceUid: getDatasourceAPIUid(alertManagerSourceName) },
{
pollingInterval: SILENCES_POLL_INTERVAL_MS,
}
API_QUERY_OPTIONS
);
const { currentData: amFeatures } = featureDiscoveryApi.useDiscoverAmFeaturesQuery(
@ -60,7 +60,7 @@ const SilencesTable = ({ alertManagerSourceName }: Props) => {
);
const mimirLazyInitError =
isFetchError(error) && error?.message?.includes('the Alertmanager is not configured') && amFeatures?.lazyConfigInit;
stringifyErrorLike(error).includes('the Alertmanager is not configured') && amFeatures?.lazyConfigInit;
const styles = useStyles2(getStyles);
const [queryParams] = useQueryParams();
@ -97,7 +97,7 @@ const SilencesTable = ({ alertManagerSourceName }: Props) => {
}, [filteredSilencesExpired, alertManagerAlerts]);
if (isLoading || amAlertsIsLoading) {
return null;
return <LoadingPlaceholder text="Loading silences..." />;
}
if (mimirLazyInitError) {
@ -218,9 +218,6 @@ const useFilteredSilences = (silences: Silence[], expired = false) => {
};
const getStyles = (theme: GrafanaTheme2) => ({
addNewSilence: css({
margin: theme.spacing(2, 0),
}),
callout: css({
backgroundColor: theme.colors.background.secondary,
borderTop: `3px solid ${theme.colors.info.border}`,