diff --git a/lerna.json b/lerna.json
index 18ae4a15842..828194eeac9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,8 +1,6 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
- "packages": [
- "packages/*"
- ],
+ "packages": ["packages/*"],
"version": "7.5.0-pre.0"
}
diff --git a/public/app/features/alerting/AlertRuleItem.tsx b/public/app/features/alerting/AlertRuleItem.tsx
index e4ea70ed7ac..cd170062b05 100644
--- a/public/app/features/alerting/AlertRuleItem.tsx
+++ b/public/app/features/alerting/AlertRuleItem.tsx
@@ -1,7 +1,6 @@
import React, { useCallback } from 'react';
// @ts-ignore
import Highlighter from 'react-highlight-words';
-import { css } from 'emotion';
import { Icon, IconName, Button, LinkButton, Card } from '@grafana/ui';
import { AlertRule } from '../../types';
@@ -26,39 +25,33 @@ const AlertRuleItem = ({ rule, search, onTogglePause }: Props) => {
);
return (
-
- {renderText(rule.name)}}>
-
-
-
-
-
-
- {renderText(rule.stateText)}{' '}
-
- for {rule.stateAge}
+ {renderText(rule.name)}}>
+
+
+
+
+
+
+ {renderText(rule.stateText)}{' '}
- {rule.info ? renderText(rule.info) : null}
-
-
-
-
- Edit alert
-
-
-
-
+ for {rule.stateAge}
+
+ {rule.info ? renderText(rule.info) : null}
+
+
+
+
+ Edit alert
+
+
+
);
};
diff --git a/public/app/features/alerting/AlertRuleList.tsx b/public/app/features/alerting/AlertRuleList.tsx
index 8ccc1408d51..6515d13befe 100644
--- a/public/app/features/alerting/AlertRuleList.tsx
+++ b/public/app/features/alerting/AlertRuleList.tsx
@@ -6,17 +6,18 @@ import AlertRuleItem from './AlertRuleItem';
import appEvents from 'app/core/app_events';
import { updateLocation } from 'app/core/actions';
import { getNavModel } from 'app/core/selectors/navModel';
-import { AlertRule, CoreEvents, StoreState } from 'app/types';
+import { AlertDefinition, AlertRule, CoreEvents, StoreState } from 'app/types';
import { getAlertRulesAsync, togglePauseAlertRule } from './state/actions';
import { getAlertRuleItems, getSearchQuery } from './state/selectors';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { NavModel, SelectableValue } from '@grafana/data';
import { setSearchQuery } from './state/reducers';
-import { Button, Select } from '@grafana/ui';
+import { Button, Select, VerticalGroup } from '@grafana/ui';
+import { AlertDefinitionItem } from './components/AlertDefinitionItem';
export interface Props {
navModel: NavModel;
- alertRules: AlertRule[];
+ alertRules: Array;
updateLocation: typeof updateLocation;
getAlertRulesAsync: typeof getAlertRulesAsync;
setSearchQuery: typeof setSearchQuery;
@@ -121,18 +122,28 @@ export class AlertRuleList extends PureComponent {
How to add an alert
-
-
- {alertRules.map((rule) => (
-
+ {alertRules.map((rule, index) => {
+ // Alert definition has "title" as name property.
+ if (rule.hasOwnProperty('name')) {
+ return (
+ this.onTogglePause(rule as AlertRule)}
+ />
+ );
+ }
+ return (
+ this.onTogglePause(rule)}
/>
- ))}
-
-
+ );
+ })}
+
);
@@ -141,10 +152,11 @@ export class AlertRuleList extends PureComponent {
const mapStateToProps = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'alert-list'),
- alertRules: getAlertRuleItems(state.alertRules),
+ alertRules: getAlertRuleItems(state),
stateFilter: state.location.query.state,
search: getSearchQuery(state.alertRules),
isLoading: state.alertRules.isLoading,
+ ngAlertDefinitions: state.alertDefinition.alertDefinitions,
});
const mapDispatchToProps = {
diff --git a/public/app/features/alerting/NextGenAlertingPage.tsx b/public/app/features/alerting/NextGenAlertingPage.tsx
index 089ed5d01d5..59352247da8 100644
--- a/public/app/features/alerting/NextGenAlertingPage.tsx
+++ b/public/app/features/alerting/NextGenAlertingPage.tsx
@@ -162,13 +162,10 @@ export default hot(module)(
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
wrapper: css`
- width: 100%;
+ width: calc(100% - 55px);
height: 100%;
position: fixed;
- z-index: ${theme.zIndex.sidemenu};
top: 0;
- left: 0;
- right: 0;
bottom: 0;
background: ${theme.colors.dashboardBg};
display: flex;
diff --git a/public/app/features/alerting/__snapshots__/AlertRuleList.test.tsx.snap b/public/app/features/alerting/__snapshots__/AlertRuleList.test.tsx.snap
index 1417adbade2..bb9a2e3fabb 100644
--- a/public/app/features/alerting/__snapshots__/AlertRuleList.test.tsx.snap
+++ b/public/app/features/alerting/__snapshots__/AlertRuleList.test.tsx.snap
@@ -80,54 +80,52 @@ exports[`Render should render alert rules 1`] = `
How to add an alert
-
+ }
+ search=""
+ />
+
`;
@@ -212,11 +210,9 @@ exports[`Render should render component 1`] = `
How to add an alert
-
+
`;
diff --git a/public/app/features/alerting/components/AlertDefinitionItem.tsx b/public/app/features/alerting/components/AlertDefinitionItem.tsx
new file mode 100644
index 00000000000..4d52a5a5c56
--- /dev/null
+++ b/public/app/features/alerting/components/AlertDefinitionItem.tsx
@@ -0,0 +1,38 @@
+import React, { FC } from 'react';
+// @ts-ignore
+import Highlighter from 'react-highlight-words';
+import { Card, FeatureBadge, Icon } from '@grafana/ui';
+import { AlertDefinition } from 'app/types';
+import { FeatureState } from '@grafana/data';
+
+interface Props {
+ alertDefinition: AlertDefinition;
+ search: string;
+}
+
+export const AlertDefinitionItem: FC = ({ alertDefinition, search }) => {
+ return (
+
+
+
+
+
+
+ {alertDefinition.description}
+
+
+
+ );
+};
+
+const CardTitle = (title: string, search: string) => (
+
+
+
+
+);
diff --git a/public/app/features/alerting/state/actions.ts b/public/app/features/alerting/state/actions.ts
index a323034e823..fe1362d126e 100644
--- a/public/app/features/alerting/state/actions.ts
+++ b/public/app/features/alerting/state/actions.ts
@@ -1,5 +1,5 @@
import { AppEvents, dateMath } from '@grafana/data';
-import { getBackendSrv, getDataSourceSrv } from '@grafana/runtime';
+import { config, getBackendSrv, getDataSourceSrv } from '@grafana/runtime';
import { appEvents } from 'app/core/core';
import { updateLocation } from 'app/core/actions';
import store from 'app/core/store';
@@ -12,6 +12,7 @@ import {
ALERT_DEFINITION_UI_STATE_STORAGE_KEY,
updateAlertDefinition,
setQueryOptions,
+ setAlertDefinitions,
} from './reducers';
import {
AlertDefinition,
@@ -29,6 +30,12 @@ export function getAlertRulesAsync(options: { state: string }): ThunkResult {
dispatch(loadAlertRules());
const rules: AlertRuleDTO[] = await getBackendSrv().get('/api/alerts', options);
+
+ if (config.featureToggles.ngalert) {
+ const ngAlertDefinitions = await getBackendSrv().get('/api/alert-definitions');
+ dispatch(setAlertDefinitions(ngAlertDefinitions.results));
+ }
+
dispatch(loadedAlertRules(rules));
};
}
diff --git a/public/app/features/alerting/state/reducers.ts b/public/app/features/alerting/state/reducers.ts
index 603c8064c2e..4cc051f0ed9 100644
--- a/public/app/features/alerting/state/reducers.ts
+++ b/public/app/features/alerting/state/reducers.ts
@@ -63,6 +63,7 @@ export const initialAlertDefinitionState: AlertDefinitionState = {
queryRunner: new PanelQueryRunner(dataConfig),
uiState: { ...store.getObject(ALERT_DEFINITION_UI_STATE_STORAGE_KEY, DEFAULT_ALERT_DEFINITION_UI_STATE) },
data: [],
+ alertDefinitions: [] as AlertDefinition[],
};
function convertToAlertRule(dto: AlertRuleDTO, state: string): AlertRule {
@@ -170,6 +171,9 @@ const alertDefinitionSlice = createSlice({
queryOptions: action.payload,
};
},
+ setAlertDefinitions: (state: AlertDefinitionState, action: PayloadAction) => {
+ return { ...state, alertDefinitions: action.payload };
+ },
},
});
@@ -181,7 +185,7 @@ export const {
resetSecureField,
} = notificationChannelSlice.actions;
-export const { setUiState, updateAlertDefinition, setQueryOptions } = alertDefinitionSlice.actions;
+export const { setUiState, updateAlertDefinition, setQueryOptions, setAlertDefinitions } = alertDefinitionSlice.actions;
export const alertRulesReducer = alertRulesSlice.reducer;
export const notificationChannelReducer = notificationChannelSlice.reducer;
diff --git a/public/app/features/alerting/state/selectors.test.ts b/public/app/features/alerting/state/selectors.test.ts
index 8ee3f01a167..a38bb798b86 100644
--- a/public/app/features/alerting/state/selectors.test.ts
+++ b/public/app/features/alerting/state/selectors.test.ts
@@ -12,21 +12,23 @@ describe('Get search query', () => {
describe('Get alert rule items', () => {
it('should get alert rule items', () => {
const state = {
- items: [
- {
- id: 1,
- dashboardId: 1,
- panelId: 1,
- name: '',
- state: '',
- stateText: '',
- stateIcon: '',
- stateClass: '',
- stateAge: '',
- url: '',
- },
- ],
- searchQuery: '',
+ alertRules: {
+ items: [
+ {
+ id: 1,
+ dashboardId: 1,
+ panelId: 1,
+ name: '',
+ state: '',
+ stateText: '',
+ stateIcon: '',
+ stateClass: '',
+ stateAge: '',
+ url: '',
+ },
+ ],
+ searchQuery: '',
+ },
};
const result = getAlertRuleItems(state as any);
@@ -35,57 +37,59 @@ describe('Get alert rule items', () => {
it('should filter rule items based on search query', () => {
const state = {
- items: [
- {
- id: 1,
- dashboardId: 1,
- panelId: 1,
- name: 'dashboard',
- state: '',
- stateText: '',
- stateIcon: '',
- stateClass: '',
- stateAge: '',
- url: '',
- },
- {
- id: 2,
- dashboardId: 3,
- panelId: 1,
- name: 'dashboard2',
- state: '',
- stateText: '',
- stateIcon: '',
- stateClass: '',
- stateAge: '',
- url: '',
- },
- {
- id: 3,
- dashboardId: 5,
- panelId: 1,
- name: 'hello',
- state: '',
- stateText: '',
- stateIcon: '',
- stateClass: '',
- stateAge: '',
- url: '',
- },
- {
- id: 4,
- dashboardId: 7,
- panelId: 1,
- name: 'test',
- state: '',
- stateText: 'dashboard',
- stateIcon: '',
- stateClass: '',
- stateAge: '',
- url: '',
- },
- ],
- searchQuery: 'dashboard',
+ alertRules: {
+ items: [
+ {
+ id: 1,
+ dashboardId: 1,
+ panelId: 1,
+ name: 'dashboard',
+ state: '',
+ stateText: '',
+ stateIcon: '',
+ stateClass: '',
+ stateAge: '',
+ url: '',
+ },
+ {
+ id: 2,
+ dashboardId: 3,
+ panelId: 1,
+ name: 'dashboard2',
+ state: '',
+ stateText: '',
+ stateIcon: '',
+ stateClass: '',
+ stateAge: '',
+ url: '',
+ },
+ {
+ id: 3,
+ dashboardId: 5,
+ panelId: 1,
+ name: 'hello',
+ state: '',
+ stateText: '',
+ stateIcon: '',
+ stateClass: '',
+ stateAge: '',
+ url: '',
+ },
+ {
+ id: 4,
+ dashboardId: 7,
+ panelId: 1,
+ name: 'test',
+ state: '',
+ stateText: 'dashboard',
+ stateIcon: '',
+ stateClass: '',
+ stateAge: '',
+ url: '',
+ },
+ ],
+ searchQuery: 'dashboard',
+ },
};
const result = getAlertRuleItems(state as any);
diff --git a/public/app/features/alerting/state/selectors.ts b/public/app/features/alerting/state/selectors.ts
index 83c8f7adf02..3db0c20e2da 100644
--- a/public/app/features/alerting/state/selectors.ts
+++ b/public/app/features/alerting/state/selectors.ts
@@ -1,13 +1,27 @@
-import { AlertRulesState, NotificationChannelState } from 'app/types';
+import { AlertDefinition, AlertRule, AlertRulesState, NotificationChannelState, StoreState } from 'app/types';
+import { config } from '@grafana/runtime';
export const getSearchQuery = (state: AlertRulesState) => state.searchQuery;
-export const getAlertRuleItems = (state: AlertRulesState) => {
- const regex = new RegExp(state.searchQuery, 'i');
+export const getAlertRuleItems = (state: StoreState) => {
+ const regex = new RegExp(state.alertRules.searchQuery, 'i');
+ const result: Array = [];
- return state.items.filter((item) => {
- return regex.test(item.name) || regex.test(item.stateText) || regex.test(item.info!);
- });
+ result.push(
+ ...state.alertRules.items.filter((item) => {
+ return regex.test(item.name) || regex.test(item.stateText) || regex.test(item.info!);
+ })
+ );
+
+ if (config.featureToggles.ngalert) {
+ result.push(
+ ...state.alertDefinition.alertDefinitions.filter((item) => {
+ return regex.test(item.title);
+ })
+ );
+ }
+
+ return result;
};
export const getNotificationChannel = (state: NotificationChannelState, channelId: number) => {
diff --git a/public/app/types/alerting.ts b/public/app/types/alerting.ts
index 8c3ab5f49d2..fe040e54e73 100644
--- a/public/app/types/alerting.ts
+++ b/public/app/types/alerting.ts
@@ -142,6 +142,7 @@ export interface AlertDefinitionState {
queryOptions: QueryGroupOptions;
queryRunner: PanelQueryRunner;
data: PanelData[];
+ alertDefinitions: AlertDefinition[];
}
export interface AlertDefinition {