Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Monitoring] Enable out of the box alerts modal #101565

Merged
merged 21 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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