mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
Alerting: Hoist routes for mute timings (#94201)
This commit is contained in:
parent
87fd36aecf
commit
4224d05934
@ -48,7 +48,10 @@ export function getAlertingRoutes(cfg = config): RouteDescriptor[] {
|
||||
AccessControlAction.AlertingNotificationsExternalWrite,
|
||||
]),
|
||||
component: importAlertingComponent(
|
||||
() => import(/* webpackChunkName: "MuteTimings" */ 'app/features/alerting/unified/MuteTimings')
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "NewMuteTiming" */ 'app/features/alerting/unified/components/mute-timings/NewMuteTiming'
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -58,7 +61,10 @@ export function getAlertingRoutes(cfg = config): RouteDescriptor[] {
|
||||
AccessControlAction.AlertingNotificationsExternalWrite,
|
||||
]),
|
||||
component: importAlertingComponent(
|
||||
() => import(/* webpackChunkName: "MuteTimings" */ 'app/features/alerting/unified/MuteTimings')
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "EditMuteTiming" */ 'app/features/alerting/unified/components/mute-timings/EditMuteTiming'
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { InitialEntry } from 'history';
|
||||
import { last } from 'lodash';
|
||||
import { ReactNode } from 'react';
|
||||
import { Route } from 'react-router';
|
||||
import { render, within, userEvent, screen } from 'test/test-utils';
|
||||
import { render, screen, userEvent, within } from 'test/test-utils';
|
||||
import { byRole, byTestId, byText } from 'testing-library-selector';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
@ -13,27 +14,28 @@ import {
|
||||
import { captureRequests } from 'app/features/alerting/unified/mocks/server/events';
|
||||
import { MOCK_DATASOURCE_EXTERNAL_VANILLA_ALERTMANAGER_UID } from 'app/features/alerting/unified/mocks/server/handlers/datasources';
|
||||
import {
|
||||
TIME_INTERVAL_NAME_HAPPY_PATH,
|
||||
TIME_INTERVAL_NAME_FILE_PROVISIONED,
|
||||
TIME_INTERVAL_NAME_HAPPY_PATH,
|
||||
} from 'app/features/alerting/unified/mocks/server/handlers/k8s/timeIntervals.k8s';
|
||||
import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources';
|
||||
import { AlertManagerCortexConfig, MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
|
||||
import MuteTimings from './MuteTimings';
|
||||
import EditMuteTimingPage from './components/mute-timings/EditMuteTiming';
|
||||
import NewMuteTimingPage from './components/mute-timings/NewMuteTiming';
|
||||
import { grantUserPermissions, mockDataSource } from './mocks';
|
||||
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
|
||||
|
||||
const indexPageText = 'redirected routes page';
|
||||
const renderMuteTimings = (location: InitialEntry = '/alerting/routes/mute-timing/new') => {
|
||||
const renderMuteTimings = (component: ReactNode, location?: InitialEntry) => {
|
||||
render(
|
||||
<>
|
||||
<Route path="/alerting/routes" exact>
|
||||
{indexPageText}
|
||||
</Route>
|
||||
<MuteTimings />
|
||||
{component}
|
||||
</>,
|
||||
{ historyOptions: { initialEntries: [location] } }
|
||||
{ historyOptions: location ? { initialEntries: [location] } : undefined }
|
||||
);
|
||||
};
|
||||
|
||||
@ -210,9 +212,9 @@ describe('Mute timings', () => {
|
||||
|
||||
it('creates a new mute timing, with mute_time_intervals in config', async () => {
|
||||
const capture = captureRequests();
|
||||
renderMuteTimings();
|
||||
renderMuteTimings(<NewMuteTimingPage />);
|
||||
|
||||
await screen.findByText(/create mute timing/i);
|
||||
await screen.findByText(/add mute timing/i);
|
||||
|
||||
await fillOutForm({
|
||||
name: 'maintenance period',
|
||||
@ -237,8 +239,7 @@ describe('Mute timings', () => {
|
||||
it('creates a new mute timing, with time_intervals in config', async () => {
|
||||
const capture = captureRequests();
|
||||
setAlertmanagerConfig(defaultConfigWithNewTimeIntervalsField);
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/new',
|
||||
renderMuteTimings(<NewMuteTimingPage />, {
|
||||
search: `?alertmanager=${alertmanagerName}`,
|
||||
});
|
||||
|
||||
@ -262,8 +263,7 @@ describe('Mute timings', () => {
|
||||
|
||||
it('creates a new mute timing, with time_intervals and mute_time_intervals in config', async () => {
|
||||
setGrafanaAlertmanagerConfig(defaultConfigWithBothTimeIntervalsField);
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/new',
|
||||
renderMuteTimings(<NewMuteTimingPage />, {
|
||||
search: `?alertmanager=${alertmanagerName}`,
|
||||
});
|
||||
|
||||
@ -284,8 +284,7 @@ describe('Mute timings', () => {
|
||||
it('prepopulates the form when editing a mute timing', async () => {
|
||||
const capture = captureRequests();
|
||||
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?muteName=${encodeURIComponent(muteTimeInterval.name)}`,
|
||||
});
|
||||
|
||||
@ -325,7 +324,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('form is invalid with duplicate mute timing name', async () => {
|
||||
renderMuteTimings();
|
||||
renderMuteTimings(<NewMuteTimingPage />);
|
||||
|
||||
await fillOutForm({ name: muteTimeInterval.name, days: '1' });
|
||||
|
||||
@ -335,8 +334,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('replaces mute timings in routes when the mute timing name is changed', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?muteName=${encodeURIComponent(muteTimeInterval.name)}`,
|
||||
});
|
||||
|
||||
@ -351,8 +349,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('shows error when mute timing does not exist', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${'does not exist'}`,
|
||||
});
|
||||
|
||||
@ -365,9 +362,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('allows creation of new mute timings', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/new',
|
||||
});
|
||||
renderMuteTimings(<NewMuteTimingPage />);
|
||||
|
||||
await fillOutForm({ name: 'a new mute timing' });
|
||||
|
||||
@ -376,8 +371,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('shows error when mute timing does not exist', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${TIME_INTERVAL_NAME_HAPPY_PATH + '_force_breakage'}`,
|
||||
});
|
||||
|
||||
@ -385,8 +379,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('loads edit form correctly and allows saving', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${TIME_INTERVAL_NAME_HAPPY_PATH}`,
|
||||
});
|
||||
|
||||
@ -395,8 +388,7 @@ describe('Mute timings', () => {
|
||||
});
|
||||
|
||||
it('loads view form for provisioned interval', async () => {
|
||||
renderMuteTimings({
|
||||
pathname: '/alerting/routes/mute-timing/edit',
|
||||
renderMuteTimings(<EditMuteTimingPage />, {
|
||||
search: `?muteName=${TIME_INTERVAL_NAME_FILE_PROVISIONED}`,
|
||||
});
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
||||
import { Navigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { useGetMuteTiming } from 'app/features/alerting/unified/components/mute-timings/useMuteTimings';
|
||||
import { useURLSearchParams } from 'app/features/alerting/unified/hooks/useURLSearchParams';
|
||||
|
||||
import { AlertmanagerPageWrapper } from './components/AlertingPageWrapper';
|
||||
import MuteTimingForm from './components/mute-timings/MuteTimingForm';
|
||||
import { useAlertmanager } from './state/AlertmanagerContext';
|
||||
|
||||
const EditTimingRoute = () => {
|
||||
const [queryParams] = useURLSearchParams();
|
||||
const { selectedAlertmanager } = useAlertmanager();
|
||||
const name = queryParams.get('muteName')!;
|
||||
const {
|
||||
isLoading,
|
||||
data: timeInterval,
|
||||
isError,
|
||||
} = useGetMuteTiming({
|
||||
alertmanager: selectedAlertmanager!,
|
||||
name,
|
||||
});
|
||||
|
||||
if (!name) {
|
||||
return <Navigate replace to="/alerting/routes" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MuteTimingForm
|
||||
editMode
|
||||
loading={isLoading}
|
||||
showError={isError}
|
||||
muteTiming={timeInterval}
|
||||
provisioned={timeInterval?.provisioned}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const MuteTimings = () => {
|
||||
return (
|
||||
<>
|
||||
<Switch>
|
||||
<Route exact path="/alerting/routes/mute-timing/new">
|
||||
<MuteTimingForm />
|
||||
</Route>
|
||||
<Route exact path="/alerting/routes/mute-timing/edit">
|
||||
<EditTimingRoute />
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MuteTimingsPage = () => {
|
||||
const pageNav = useMuteTimingNavData();
|
||||
|
||||
return (
|
||||
<AlertmanagerPageWrapper navId="am-routes" pageNav={pageNav} accessType="notification">
|
||||
<MuteTimings />
|
||||
</AlertmanagerPageWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export function useMuteTimingNavData() {
|
||||
const { isExact, path } = useRouteMatch();
|
||||
const [pageNav, setPageNav] = useState<Pick<NavModelItem, 'id' | 'text' | 'icon'> | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (path === '/alerting/routes/mute-timing/new') {
|
||||
setPageNav({
|
||||
id: 'alert-policy-new',
|
||||
text: 'Add mute timing',
|
||||
});
|
||||
} else if (path === '/alerting/routes/mute-timing/edit') {
|
||||
setPageNav({
|
||||
id: 'alert-policy-edit',
|
||||
text: 'Edit mute timing',
|
||||
});
|
||||
}
|
||||
}, [path, isExact]);
|
||||
|
||||
return pageNav;
|
||||
}
|
||||
|
||||
export default MuteTimingsPage;
|
@ -0,0 +1,54 @@
|
||||
import { Navigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import { withErrorBoundary } from '@grafana/ui';
|
||||
import { useGetMuteTiming } from 'app/features/alerting/unified/components/mute-timings/useMuteTimings';
|
||||
import { useURLSearchParams } from 'app/features/alerting/unified/hooks/useURLSearchParams';
|
||||
|
||||
import { useAlertmanager } from '../../state/AlertmanagerContext';
|
||||
import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
|
||||
|
||||
import MuteTimingForm from './MuteTimingForm';
|
||||
|
||||
const EditTimingRoute = () => {
|
||||
const [queryParams] = useURLSearchParams();
|
||||
const { selectedAlertmanager } = useAlertmanager();
|
||||
const name = queryParams.get('muteName')!;
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
data: timeInterval,
|
||||
isError,
|
||||
} = useGetMuteTiming({
|
||||
alertmanager: selectedAlertmanager!,
|
||||
name,
|
||||
});
|
||||
|
||||
if (!name) {
|
||||
return <Navigate replace to="/alerting/routes" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MuteTimingForm
|
||||
editMode
|
||||
loading={isLoading}
|
||||
showError={isError}
|
||||
muteTiming={timeInterval}
|
||||
provisioned={timeInterval?.provisioned}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const EditMuteTimingPage = () => (
|
||||
<AlertmanagerPageWrapper
|
||||
navId="am-routes"
|
||||
pageNav={{
|
||||
id: 'alert-policy-edit',
|
||||
text: 'Edit mute timing',
|
||||
}}
|
||||
accessType="notification"
|
||||
>
|
||||
<EditTimingRoute />
|
||||
</AlertmanagerPageWrapper>
|
||||
);
|
||||
|
||||
export default withErrorBoundary(EditMuteTimingPage, { style: 'page' });
|
@ -100,7 +100,7 @@ const MuteTimingForm = ({ muteTiming, showError, loading, provisioned, editMode
|
||||
{provisioned && <ProvisioningAlert resource={ProvisionedResource.MuteTiming} />}
|
||||
<FormProvider {...formApi}>
|
||||
<form onSubmit={formApi.handleSubmit(onSubmit)} data-testid="mute-timing-form">
|
||||
<FieldSet label={'Create mute timing'} disabled={provisioned || updating}>
|
||||
<FieldSet disabled={provisioned || updating}>
|
||||
<Field
|
||||
required
|
||||
label="Name"
|
||||
|
@ -0,0 +1,20 @@
|
||||
import { withErrorBoundary } from '@grafana/ui';
|
||||
|
||||
import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
|
||||
|
||||
import MuteTimingForm from './MuteTimingForm';
|
||||
|
||||
const NewMuteTimingPage = () => (
|
||||
<AlertmanagerPageWrapper
|
||||
navId="am-routes"
|
||||
pageNav={{
|
||||
id: 'alert-policy-new',
|
||||
text: 'Add mute timing',
|
||||
}}
|
||||
accessType="notification"
|
||||
>
|
||||
<MuteTimingForm />
|
||||
</AlertmanagerPageWrapper>
|
||||
);
|
||||
|
||||
export default withErrorBoundary(NewMuteTimingPage, { style: 'page' });
|
Loading…
Reference in New Issue
Block a user