Skip to content

Commit

Permalink
[Monitoring] Enable out of the box alerts modal (#101565)
Browse files Browse the repository at this point in the history
* Remove api call to create alerts

* Add enable alerts modal

* Update modal title

* Add simple alerts dropdown

* change alerts modal design

* refactor alerts modal provider

* Add alerts dropdown

* Show toast after alert creation and add error handling

* Do not show alerts modal if alerts already exist

* Fix stack monitoring test

* Fix more stack monitoring tests and types

* Fix tests after merge

* Attempt to fix stack monitoring tests

* remove console.log

* Change text

* Remove commented comment

* Update docs for stack monitoring alerts

* Fix docs

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
estermv and kibanamachine authored Jun 29, 2021
1 parent e387d3d commit 4640253
Show file tree
Hide file tree
Showing 39 changed files with 389 additions and 18 deletions.
12 changes: 10 additions & 2 deletions docs/user/monitoring/kibana-alerts.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ specific needs.
[role="screenshot"]
image::user/monitoring/images/monitoring-kibana-alerting-notification.png["{kib} alerting notifications in {stack-monitor-app}"]

When you open *{stack-monitor-app}*, the preconfigured rules are created
automatically. They are initially configured to detect and notify on various
When you open *{stack-monitor-app}*, you will be ask to create these rules
They are initially configured to detect and notify on various
conditions across your monitored clusters. You can view notifications for: *Cluster health*, *Resource utilization*, and *Errors and exceptions* for {es}
in real time.

Expand Down Expand Up @@ -131,6 +131,14 @@ soon the expiration date is:
The 60-day and 30-day thresholds are skipped for Trial licenses, which are only
valid for 30 days.

[discrete]
== Alerts and rules
[discrete]
=== Create default rules
This option can be used to create default rules in this kibana spaces. This is
useful for scenarios when you didn't choose to create these default rules initially
or anytime later if the rules were accidentally deleted.

NOTE: Some action types are subscription features, while others are free.
For a comparison of the Elastic subscription levels, see the alerting section of
the {subscriptions}[Subscriptions page].
77 changes: 77 additions & 0 deletions x-pack/plugins/monitoring/public/alerts/alerts_dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import {
EuiButtonEmpty,
EuiContextMenu,
EuiContextMenuPanelDescriptor,
EuiPopover,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { Legacy } from '../legacy_shims';

export const AlertsDropdown: React.FC<{}> = () => {
const $injector = Legacy.shims.getAngularInjector();
const alertsEnableModalProvider: any = $injector.get('enableAlertsModal');

const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const closePopover = () => {
alertsEnableModalProvider.enableAlerts();
setIsPopoverOpen(false);
};

const togglePopoverVisibility = () => {
setIsPopoverOpen(!isPopoverOpen);
};

const createDefaultRules = () => {
closePopover();
};

const button = (
<EuiButtonEmpty iconSide={'right'} iconType={'arrowDown'} onClick={togglePopoverVisibility}>
<FormattedMessage
id="xpack.monitoring.alerts.dropdown.button"
defaultMessage="Alerts and rules"
/>
</EuiButtonEmpty>
);

const items = [
{
name: i18n.translate('xpack.monitoring.alerts.dropdown.createAlerts', {
defaultMessage: 'Create default rules',
}),
onClick: createDefaultRules,
},
];

const panels: EuiContextMenuPanelDescriptor[] = [
{
id: 0,
title: i18n.translate('xpack.monitoring.alerts.dropdown.title', {
defaultMessage: 'Alerts and rules',
}),
items,
},
];

return (
<EuiPopover
panelPaddingSize="none"
anchorPosition="downLeft"
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
>
<EuiContextMenu initialPanelId={0} panels={panels} />
</EuiPopover>
);
};
148 changes: 148 additions & 0 deletions x-pack/plugins/monitoring/public/alerts/enable_alerts_modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { useEffect, useState, useContext } from 'react';

import {
EuiButton,
EuiModal,
EuiModalBody,
EuiModalFooter,
EuiModalHeader,
EuiModalHeaderTitle,
EuiButtonEmpty,
EuiText,
EuiLink,
EuiRadioGroup,
EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { AlertsContext } from './context';
import { Legacy } from '../legacy_shims';

export const EnableAlertsModal: React.FC<{}> = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const $injector = Legacy.shims.getAngularInjector();
const alertsEnableModalProvider: any = $injector.get('enableAlertsModal');
const alertsContext = useContext(AlertsContext);

const closeModal = () => {
setIsModalVisible(false);
alertsEnableModalProvider.hideModalForSession();
};

const radios = [
{
id: 'create-alerts',
label: i18n.translate('xpack.monitoring.alerts.modal.yesOption', {
defaultMessage: 'Yes (Recommended - create default rules in this kibana spaces)',
}),
},
{
id: 'not-create-alerts',
label: i18n.translate('xpack.monitoring.alerts.modal.noOption', {
defaultMessage: 'No',
}),
},
];

const [radioIdSelected, setRadioIdSelected] = useState('create-alerts');

const onChange = (optionId: string) => {
setRadioIdSelected(optionId);
};

useEffect(() => {
if (alertsEnableModalProvider.shouldShowAlertsModal(alertsContext)) {
setIsModalVisible(true);
}
}, [alertsEnableModalProvider, alertsContext]);

const confirmButtonClick = () => {
if (radioIdSelected === 'create-alerts') {
alertsEnableModalProvider.enableAlerts();
} else {
alertsEnableModalProvider.notAskAgain();
}

closeModal();
};

const remindLaterClick = () => {
alertsEnableModalProvider.hideModalForSession();
closeModal();
};

return isModalVisible ? (
<EuiModal onClose={closeModal}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<h1>
<FormattedMessage
id="xpack.monitoring.alerts.modal.title"
defaultMessage="Create rules"
/>
</h1>
</EuiModalHeaderTitle>
</EuiModalHeader>

<EuiModalBody>
<EuiText>
<p>
<FormattedMessage
id="xpack.monitoring.alerts.modal.description"
defaultMessage="Stack monitoring comes with many out-of-the box rules to notify you of common issues
around cluster health, resource utilization and errors or exceptions. {learnMoreLink}"
values={{
learnMoreLink: (
<EuiLink
href={Legacy.shims.docLinks.links.monitoring.alertsKibana}
target="_blank"
>
<FormattedMessage
id="xpack.monitoring.alerts.modal.description.link"
defaultMessage="Learn more..."
/>
</EuiLink>
),
}}
/>
</p>
<div>
<FormattedMessage
id="xpack.monitoring.alerts.modal.createDescription"
defaultMessage="Create these out-of-the box rules?"
/>

<EuiSpacer size="xs" />

<EuiRadioGroup
options={radios}
idSelected={radioIdSelected}
onChange={(id) => onChange(id)}
name="radio group"
/>
</div>
</EuiText>
</EuiModalBody>

<EuiModalFooter>
<EuiButtonEmpty onClick={remindLaterClick}>
<FormattedMessage
id="xpack.monitoring.alerts.modal.remindLater"
defaultMessage="Remind me later"
/>
</EuiButtonEmpty>

<EuiButton onClick={confirmButtonClick} fill data-test-subj="alerts-modal-button">
<FormattedMessage id="xpack.monitoring.alerts.modal.confirm" defaultMessage="Ok" />
</EuiButton>
</EuiModalFooter>
</EuiModal>
) : null;
};
5 changes: 5 additions & 0 deletions x-pack/plugins/monitoring/public/angular/app_modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import { licenseProvider } from '../services/license';
// @ts-ignore
import { titleProvider } from '../services/title';
// @ts-ignore
import { enableAlertsModalProvider } from '../services/enable_alerts_modal';
// @ts-ignore
import { monitoringMlListingProvider } from '../directives/elasticsearch/ml_job_listing';
// @ts-ignore
import { monitoringMainProvider } from '../directives/main';
Expand Down Expand Up @@ -142,6 +144,9 @@ function createMonitoringAppServices() {
.service('features', function (Private: IPrivate) {
return Private(featuresProvider);
})
.service('enableAlertsModal', function (Private: IPrivate) {
return Private(enableAlertsModalProvider);
})
.service('license', function (Private: IPrivate) {
return Private(licenseProvider);
})
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/monitoring/public/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class AngularApp {
triggersActionsUi,
usageCollection,
kibanaLegacy,
appMountParameters,
} = deps;
const app: IModule = localAppModule(deps);
app.run(($injector: angular.auto.IInjectorService) => {
Expand All @@ -45,6 +46,7 @@ export class AngularApp {
kibanaLegacy,
triggersActionsUi,
usageCollection,
appMountParameters,
},
this.injector
);
Expand Down
13 changes: 11 additions & 2 deletions x-pack/plugins/monitoring/public/legacy_shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { CoreStart, HttpSetup, IUiSettingsClient } from 'kibana/public';
import { CoreStart, HttpSetup, IUiSettingsClient, AppMountParameters } from 'kibana/public';
import { Observable } from 'rxjs';
import { HttpRequestInit } from '../../../../src/core/public';
import { MonitoringStartPluginDependencies } from './types';
Expand Down Expand Up @@ -63,13 +63,21 @@ export interface IShims {
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
usageCollection: UsageCollectionSetup;
kibanaServices: CoreStart & { usageCollection: UsageCollectionSetup };
appMountParameters: AppMountParameters;
}

export class Legacy {
private static _shims: IShims;

public static init(
{ core, data, isCloud, triggersActionsUi, usageCollection }: MonitoringStartPluginDependencies,
{
core,
data,
isCloud,
triggersActionsUi,
usageCollection,
appMountParameters,
}: MonitoringStartPluginDependencies,
ngInjector: angular.auto.IInjectorService
) {
this._shims = {
Expand Down Expand Up @@ -129,6 +137,7 @@ export class Legacy {
...core,
usageCollection,
},
appMountParameters,
};
}

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/monitoring/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export class MonitoringPlugin
externalConfig: this.getExternalConfig(),
triggersActionsUi: pluginsStart.triggersActionsUi,
usageCollection: plugins.usageCollection,
appMountParameters: params,
};

const monitoringApp = new AngularApp(deps);
Expand Down
14 changes: 1 addition & 13 deletions x-pack/plugins/monitoring/public/services/clusters.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ajaxErrorHandlersProvider } from '../lib/ajax_error_handler';
import { Legacy } from '../legacy_shims';
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../common/constants';
import { showInternalMonitoringToast } from '../lib/internal_monitoring_toasts';
import { showAlertsToast } from '../alerts/lib/alerts_toast';

function formatClusters(clusters) {
return clusters.map(formatCluster);
Expand Down Expand Up @@ -58,16 +57,6 @@ export function monitoringClustersProvider($injector) {
}
}

async function ensureAlertsEnabled() {
try {
return $http.post('../api/monitoring/v1/alerts/enable', {});
} catch (err) {
const Private = $injector.get('Private');
const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider);
return ajaxErrorHandlers(err);
}
}

async function ensureMetricbeatEnabled() {
if (Legacy.shims.isCloud) {
return;
Expand Down Expand Up @@ -97,8 +86,7 @@ export function monitoringClustersProvider($injector) {
const clusters = await getClusters();
if (clusters.length) {
try {
const [{ data }] = await Promise.all([ensureAlertsEnabled(), ensureMetricbeatEnabled()]);
showAlertsToast(data);
await ensureMetricbeatEnabled();
} catch (_err) {
// Intentionally swallow the error as this will retry the next page load
}
Expand Down
Loading

0 comments on commit 4640253

Please sign in to comment.