mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Replace notify.warning with toastNotifications in region map, vega, index_pattern, redirect_when_missing, graph, monitoring, and ML * Link to index patterns from Graph toast. * Delete RouteBasedNotifier. * Remove courierNotifier and SearchTimeout and ShardFailure errors. * Remove warning and custom notifier types.
This commit is contained in:
parent
54d4c5332c
commit
b003d29751
24 changed files with 129 additions and 564 deletions
|
@ -18,15 +18,13 @@
|
|||
*/
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import regionMapVisParamsTemplate from './region_map_vis_params.html';
|
||||
import { mapToLayerWithId } from './util';
|
||||
import '../../tile_map/public/editors/wms_options';
|
||||
|
||||
uiModules.get('kibana/region_map')
|
||||
.directive('regionMapVisParams', function (serviceSettings, regionmapsConfig, Notifier) {
|
||||
|
||||
const notify = new Notifier({ location: 'Region map' });
|
||||
|
||||
.directive('regionMapVisParams', function (serviceSettings, regionmapsConfig) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: regionMapVisParamsTemplate,
|
||||
|
@ -84,7 +82,7 @@ uiModules.get('kibana/region_map')
|
|||
|
||||
})
|
||||
.catch(function (error) {
|
||||
notify.warning(error.message);
|
||||
toastNotifications.addWarning(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ import ChoroplethLayer from './choropleth_layer';
|
|||
import { truncatedColorMaps } from 'ui/vislib/components/color/truncated_colormaps';
|
||||
import AggResponsePointSeriesTooltipFormatterProvider from './tooltip_formatter';
|
||||
import 'ui/vis/map/service_settings';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
export function RegionMapsVisualizationProvider(Private, Notifier, config) {
|
||||
export function RegionMapsVisualizationProvider(Private, config) {
|
||||
|
||||
const tooltipFormatter = Private(AggResponsePointSeriesTooltipFormatterProvider);
|
||||
const BaseMapsVisualization = Private(BaseMapsVisualizationProvider);
|
||||
|
@ -36,10 +37,8 @@ export function RegionMapsVisualizationProvider(Private, Notifier, config) {
|
|||
super(container, vis);
|
||||
this._vis = this.vis;
|
||||
this._choroplethLayer = null;
|
||||
this._notify = new Notifier({ location: 'Region map' });
|
||||
}
|
||||
|
||||
|
||||
async render(esResponse, status) {
|
||||
await super.render(esResponse, status);
|
||||
if (this._choroplethLayer) {
|
||||
|
@ -47,7 +46,6 @@ export function RegionMapsVisualizationProvider(Private, Notifier, config) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
async _updateData(tableGroup) {
|
||||
this._chartData = tableGroup;
|
||||
let results;
|
||||
|
@ -81,7 +79,6 @@ export function RegionMapsVisualizationProvider(Private, Notifier, config) {
|
|||
this._kibanaMap.useUiStateFromVisualization(this._vis);
|
||||
}
|
||||
|
||||
|
||||
async _updateParams() {
|
||||
|
||||
await super._updateParams();
|
||||
|
@ -156,13 +153,14 @@ export function RegionMapsVisualizationProvider(Private, Notifier, config) {
|
|||
const rowIndex = this._chartData.tables[0].rows.findIndex(row => row[0] === event);
|
||||
this._vis.API.events.addFilter(this._chartData.tables[0], 0, rowIndex, event);
|
||||
});
|
||||
|
||||
this._choroplethLayer.on('styleChanged', (event) => {
|
||||
const shouldShowWarning = this._vis.params.isDisplayWarning && config.get('visualization:regionmap:showWarnings');
|
||||
if (event.mismatches.length > 0 && shouldShowWarning) {
|
||||
this._notify.warning(`Could not show ${event.mismatches.length} ${event.mismatches.length > 1 ? 'results' : 'result'} on the map.`
|
||||
+ ` To avoid this, ensure that each term can be matched to a corresponding shape on that shape's join field.`
|
||||
+ ` Could not match following terms: ${event.mismatches.join(',')}`
|
||||
);
|
||||
toastNotifications.addWarning({
|
||||
title: `Unable to show ${event.mismatches.length} ${event.mismatches.length > 1 ? 'results' : 'result'} on map`,
|
||||
text: `Ensure that each of these term matches a shape on that shape's join field: ${event.mismatches.join(', ')}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { KibanaMap } from 'ui/vis/map/kibana_map';
|
|||
import * as Rx from 'rxjs';
|
||||
import { filter, first } from 'rxjs/operators';
|
||||
import 'ui/vis/map/service_settings';
|
||||
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
const MINZOOM = 0;
|
||||
const MAXZOOM = 22;//increase this to 22. Better for WMS
|
||||
|
@ -142,7 +142,7 @@ export function BaseMapsVisualizationProvider(serviceSettings) {
|
|||
this._setTmsLayer(firstRoadMapLayer);
|
||||
}
|
||||
} catch (e) {
|
||||
this._notify.warning(e.message);
|
||||
toastNotifications.addWarning(e.message);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
@ -174,7 +174,7 @@ export function BaseMapsVisualizationProvider(serviceSettings) {
|
|||
|
||||
}
|
||||
} catch (tmsLoadingError) {
|
||||
this._notify.warning(tmsLoadingError.message);
|
||||
toastNotifications.addWarning(tmsLoadingError.message);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Notifier } from 'ui/notify';
|
||||
import { toastNotifications, Notifier } from 'ui/notify';
|
||||
import { VegaView } from './vega_view/vega_view';
|
||||
import { VegaMapView } from './vega_view/vega_map_view';
|
||||
import { SavedObjectsClientProvider, findObjectByTitle } from 'ui/saved_objects';
|
||||
|
@ -59,7 +59,7 @@ export function VegaVisualizationProvider(Private, vegaConfig, serviceSettings,
|
|||
*/
|
||||
async render(visData, status) {
|
||||
if (!visData && !this._vegaView) {
|
||||
notify.warning('Unable to render without data');
|
||||
toastNotifications.addWarning('Unable to render without data');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,8 @@
|
|||
|
||||
import expect from 'expect.js';
|
||||
import {
|
||||
SearchTimeout,
|
||||
RequestFailure,
|
||||
FetchFailure,
|
||||
ShardFailure,
|
||||
VersionConflict,
|
||||
MappingConflict,
|
||||
RestrictedMapping,
|
||||
|
@ -46,10 +44,8 @@ import {
|
|||
|
||||
describe('ui/errors', () => {
|
||||
const errors = [
|
||||
new SearchTimeout(),
|
||||
new RequestFailure('an error', { }),
|
||||
new FetchFailure({ }),
|
||||
new ShardFailure({ '_shards': 5 }),
|
||||
new VersionConflict({ }),
|
||||
new MappingConflict({ }),
|
||||
new RestrictedMapping('field', 'indexPattern'),
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { RequestFailure, SearchTimeout, ShardFailure } from '../../errors';
|
||||
|
||||
import { toastNotifications } from '../../notify';
|
||||
import { RequestFailure } from '../../errors';
|
||||
import { RequestStatus } from './req_status';
|
||||
import { courierNotifier } from './notifier';
|
||||
|
||||
export function CallResponseHandlersProvider(Private, Promise) {
|
||||
const ABORTED = RequestStatus.ABORTED;
|
||||
|
@ -35,11 +34,15 @@ export function CallResponseHandlersProvider(Private, Promise) {
|
|||
const response = responses[index];
|
||||
|
||||
if (response.timed_out) {
|
||||
courierNotifier.warning(new SearchTimeout());
|
||||
toastNotifications.addWarning({
|
||||
title: 'Data might be incomplete because your request timed out',
|
||||
});
|
||||
}
|
||||
|
||||
if (response._shards && response._shards.failed) {
|
||||
courierNotifier.warning(new ShardFailure(response));
|
||||
toastNotifications.addWarning({
|
||||
title: '${response._shards.failed} of ${response._shards.total} shards failed',
|
||||
});
|
||||
}
|
||||
|
||||
function progress() {
|
||||
|
|
|
@ -22,7 +22,6 @@ import { CallClientProvider } from './call_client';
|
|||
import { CallResponseHandlersProvider } from './call_response_handlers';
|
||||
import { ContinueIncompleteProvider } from './continue_incomplete';
|
||||
import { RequestStatus } from './req_status';
|
||||
import { location } from './notifier';
|
||||
|
||||
/**
|
||||
* Fetch now provider should be used if you want the results searched and returned immediately.
|
||||
|
@ -53,7 +52,7 @@ export function FetchNowProvider(Private, Promise) {
|
|||
|
||||
return searchRequest.retry();
|
||||
}))
|
||||
.catch(error => fatalError(error, location));
|
||||
.catch(error => fatalError(error, 'Courier fetch'));
|
||||
}
|
||||
|
||||
function fetchSearchResults(searchRequests) {
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Notifier } from '../../notify';
|
||||
|
||||
export const location = 'Courier fetch';
|
||||
|
||||
export const courierNotifier = new Notifier({
|
||||
location,
|
||||
});
|
|
@ -51,16 +51,6 @@ export class KbnError {
|
|||
// instanceof checks.
|
||||
createLegacyClass(KbnError).inherits(Error);
|
||||
|
||||
/**
|
||||
* SearchTimeout error class
|
||||
*/
|
||||
export class SearchTimeout extends KbnError {
|
||||
constructor() {
|
||||
super('All or part of your request has timed out. The data shown may be incomplete.',
|
||||
SearchTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Failure - When an entire multi request fails
|
||||
* @param {Error} err - the Error that came back
|
||||
|
@ -92,20 +82,6 @@ export class FetchFailure extends KbnError {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ShardFailure Error - when one or more shards fail
|
||||
* @param {Object} resp - The response from es.
|
||||
*/
|
||||
export class ShardFailure extends KbnError {
|
||||
constructor(resp) {
|
||||
super(
|
||||
`${resp._shards.failed} of ${resp._shards.total} shards failed.`,
|
||||
ShardFailure);
|
||||
|
||||
this.resp = resp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A doc was re-indexed but it was out of date.
|
||||
* @param {Object} resp - The response from es (one of the multi-response responses).
|
||||
|
|
|
@ -29,7 +29,7 @@ import { FixturesStubbedSavedObjectIndexPatternProvider } from 'fixtures/stubbed
|
|||
import { IndexPatternsIntervalsProvider } from '../_intervals';
|
||||
import { IndexPatternProvider } from '../_index_pattern';
|
||||
import NoDigestPromises from 'test_utils/no_digest_promises';
|
||||
import { Notifier } from '../../notify';
|
||||
import { toastNotifications } from '../../notify';
|
||||
|
||||
import { FieldsFetcherProvider } from '../fields_fetcher_provider';
|
||||
import { StubIndexPatternsApiClientModule } from './stub_index_patterns_api_client';
|
||||
|
@ -37,8 +37,6 @@ import { IndexPatternsApiClientProvider } from '../index_patterns_api_client_pro
|
|||
import { IsUserAwareOfUnsupportedTimePatternProvider } from '../unsupported_time_patterns';
|
||||
import { SavedObjectsClientProvider } from '../../saved_objects';
|
||||
|
||||
const MARKDOWN_LINK_RE = /\[(.+?)\]\((.+?)\)/;
|
||||
|
||||
describe('index pattern', function () {
|
||||
NoDigestPromises.activateForSuite();
|
||||
|
||||
|
@ -468,23 +466,22 @@ describe('index pattern', function () {
|
|||
}
|
||||
|
||||
it('logs a warning when the index pattern source includes `intervalName`', async () => {
|
||||
const indexPattern = await createUnsupportedTimePattern();
|
||||
expect(Notifier.prototype._notifs).to.have.length(1);
|
||||
|
||||
const notif = Notifier.prototype._notifs.shift();
|
||||
expect(notif).to.have.property('type', 'warning');
|
||||
expect(notif.content).to.match(MARKDOWN_LINK_RE);
|
||||
|
||||
const [, text, url] = notif.content.match(MARKDOWN_LINK_RE);
|
||||
expect(text).to.contain(indexPattern.title);
|
||||
expect(url).to.contain(indexPattern.id);
|
||||
expect(url).to.contain('management/kibana/indices');
|
||||
await createUnsupportedTimePattern();
|
||||
expect(toastNotifications.list).to.have.length(1);
|
||||
});
|
||||
|
||||
it('does not notify if isUserAwareOfUnsupportedTimePattern() returns true', async () => {
|
||||
// Ideally, _index_pattern.js shouldn't be tightly coupled to toastNotifications. Instead, it
|
||||
// should notify its consumer of this state and the consumer should be responsible for
|
||||
// notifying the user. This test verifies the side effect of the state until we can remove
|
||||
// this coupling.
|
||||
|
||||
// Clear existing toasts.
|
||||
toastNotifications.list.splice(0);
|
||||
|
||||
isUserAwareOfUnsupportedTimePattern.returns(true);
|
||||
await createUnsupportedTimePattern();
|
||||
expect(Notifier.prototype._notifs).to.have.length(0);
|
||||
expect(toastNotifications.list).to.have.length(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { SavedObjectNotFound, DuplicateField, IndexPatternMissingIndices } from '../errors';
|
||||
import angular from 'angular';
|
||||
|
@ -119,13 +120,15 @@ export function IndexPatternProvider(Private, config, Promise, confirmModalPromi
|
|||
|
||||
if (indexPattern.isUnsupportedTimePattern()) {
|
||||
if (!isUserAwareOfUnsupportedTimePattern(indexPattern)) {
|
||||
const warning = (
|
||||
'Support for time-intervals has been removed. ' +
|
||||
`View the ["${indexPattern.title}" index pattern in management](` +
|
||||
kbnUrl.getRouteHref(indexPattern, 'edit') +
|
||||
') for more information.'
|
||||
);
|
||||
notify.warning(warning, { lifetime: Infinity });
|
||||
toastNotifications.addWarning({
|
||||
title: 'Support for time intervals was removed',
|
||||
text: (
|
||||
<Fragment>
|
||||
For more information, view the {' '}
|
||||
<a href={kbnUrl.getRouteHref(indexPattern, 'edit')}>{indexPattern.title} index pattern</a>
|
||||
</Fragment>
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,17 +29,6 @@ describe('Notifier', function () {
|
|||
let notifier;
|
||||
let params;
|
||||
const message = 'Oh, the humanity!';
|
||||
const customText = 'fooMarkup';
|
||||
const customParams = {
|
||||
title: 'fooTitle',
|
||||
actions: [{
|
||||
text: 'Cancel',
|
||||
callback: sinon.spy()
|
||||
}, {
|
||||
text: 'OK',
|
||||
callback: sinon.spy()
|
||||
}]
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
ngMock.module('kibana');
|
||||
|
@ -150,176 +139,6 @@ describe('Notifier', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#warning', function () {
|
||||
testVersionInfo('warning');
|
||||
|
||||
it('prepends location to message for content', function () {
|
||||
expect(notify('warning').content).to.equal(params.location + ': ' + message);
|
||||
});
|
||||
|
||||
it('sets type to "warning"', function () {
|
||||
expect(notify('warning').type).to.equal('warning');
|
||||
});
|
||||
|
||||
it('sets icon to "warning"', function () {
|
||||
expect(notify('warning').icon).to.equal('warning');
|
||||
});
|
||||
|
||||
it('sets title to "Warning"', function () {
|
||||
expect(notify('warning').title).to.equal('Warning');
|
||||
});
|
||||
|
||||
it('sets lifetime to 10000', function () {
|
||||
expect(notify('warning').lifetime).to.equal(10000);
|
||||
});
|
||||
|
||||
it('does not allow reporting', function () {
|
||||
const includesReport = _.includes(notify('warning').actions, 'report');
|
||||
expect(includesReport).to.false;
|
||||
});
|
||||
|
||||
it('allows accepting', function () {
|
||||
const includesAccept = _.includes(notify('warning').actions, 'accept');
|
||||
expect(includesAccept).to.true;
|
||||
});
|
||||
|
||||
it('does not include stack', function () {
|
||||
expect(notify('warning').stack).not.to.be.defined;
|
||||
});
|
||||
|
||||
it('has css class helper functions', function () {
|
||||
expect(notify('warning').getIconClass()).to.equal('fa fa-warning');
|
||||
expect(notify('warning').getButtonClass()).to.equal('kuiButton--warning');
|
||||
expect(notify('warning').getAlertClassStack()).to.equal('toast-stack alert alert-warning');
|
||||
expect(notify('warning').getAlertClass()).to.equal('toast alert alert-warning');
|
||||
expect(notify('warning').getButtonGroupClass()).to.equal('toast-controls');
|
||||
expect(notify('warning').getToastMessageClass()).to.equal('toast-message');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#custom', function () {
|
||||
let customNotification;
|
||||
|
||||
beforeEach(() => {
|
||||
customNotification = notifier.custom(customText, customParams);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
customNotification.clear();
|
||||
});
|
||||
|
||||
it('throws if second param is not an object', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
function callCustomIncorrectly() {
|
||||
const badParam = null;
|
||||
customNotification = notifier.custom(customText, badParam);
|
||||
}
|
||||
expect(callCustomIncorrectly).to.throwException(function (e) {
|
||||
expect(e.message).to.be('Config param is required, and must be an object');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('has a custom function to make notifications', function () {
|
||||
expect(notifier.custom).to.be.a('function');
|
||||
});
|
||||
|
||||
it('properly merges options', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
const overrideParams = _.defaults({ lifetime: 20000 }, customParams);
|
||||
customNotification = notifier.custom(customText, overrideParams);
|
||||
|
||||
expect(customNotification).to.have.property('type', 'info'); // default
|
||||
expect(customNotification).to.have.property('title', overrideParams.title); // passed in thru customParams
|
||||
expect(customNotification).to.have.property('lifetime', overrideParams.lifetime); // passed in thru overrideParams
|
||||
|
||||
expect(overrideParams.type).to.be(undefined);
|
||||
expect(overrideParams.title).to.be.a('string');
|
||||
expect(overrideParams.lifetime).to.be.a('number');
|
||||
});
|
||||
|
||||
it('sets the content', function () {
|
||||
expect(customNotification).to.have.property('content', `${params.location}: ${customText}`);
|
||||
expect(customNotification.content).to.be.a('string');
|
||||
});
|
||||
|
||||
it('uses custom actions', function () {
|
||||
expect(customNotification).to.have.property('customActions');
|
||||
expect(customNotification.customActions).to.have.length(customParams.actions.length);
|
||||
});
|
||||
|
||||
it('custom actions have getButtonClass method', function () {
|
||||
customNotification.customActions.forEach((action, idx) => {
|
||||
expect(action).to.have.property('getButtonClass');
|
||||
expect(action.getButtonClass).to.be.a('function');
|
||||
if (idx === 0) {
|
||||
expect(action.getButtonClass()).to.be('kuiButton--primary kuiButton--primary');
|
||||
} else {
|
||||
expect(action.getButtonClass()).to.be('kuiButton--basic kuiButton--primary');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('gives a default action if none are provided', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
const noActionParams = _.defaults({ actions: [] }, customParams);
|
||||
customNotification = notifier.custom(customText, noActionParams);
|
||||
expect(customNotification).to.have.property('actions');
|
||||
expect(customNotification.actions).to.have.length(1);
|
||||
});
|
||||
|
||||
it('defaults type and lifetime for "info" config', function () {
|
||||
expect(customNotification.type).to.be('info');
|
||||
expect(customNotification.lifetime).to.be(5000);
|
||||
});
|
||||
|
||||
it('dynamic lifetime for "warning" config', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
const errorTypeParams = _.defaults({ type: 'warning' }, customParams);
|
||||
customNotification = notifier.custom(customText, errorTypeParams);
|
||||
expect(customNotification.type).to.be('warning');
|
||||
expect(customNotification.lifetime).to.be(10000);
|
||||
});
|
||||
|
||||
it('dynamic type and lifetime for "error" config', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
const errorTypeParams = _.defaults({ type: 'error' }, customParams);
|
||||
customNotification = notifier.custom(customText, errorTypeParams);
|
||||
expect(customNotification.type).to.be('danger');
|
||||
expect(customNotification.lifetime).to.be(300000);
|
||||
});
|
||||
|
||||
it('dynamic type and lifetime for "danger" config', function () {
|
||||
// destroy the default custom notification, avoid duplicate handling
|
||||
customNotification.clear();
|
||||
|
||||
const errorTypeParams = _.defaults({ type: 'danger' }, customParams);
|
||||
customNotification = notifier.custom(customText, errorTypeParams);
|
||||
expect(customNotification.type).to.be('danger');
|
||||
expect(customNotification.lifetime).to.be(300000);
|
||||
});
|
||||
|
||||
it('should wrap the callback functions in a close function', function () {
|
||||
customNotification.customActions.forEach((action, idx) => {
|
||||
expect(action.callback).not.to.equal(customParams.actions[idx]);
|
||||
action.callback();
|
||||
});
|
||||
customParams.actions.forEach(action => {
|
||||
expect(action.callback.called).to.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function notify(fnName, opts) {
|
||||
notifier[fnName](message, opts);
|
||||
return latestNotification();
|
||||
|
|
|
@ -95,7 +95,6 @@ function restartNotifTimer(notif, cb) {
|
|||
|
||||
const typeToButtonClassMap = {
|
||||
danger: 'kuiButton--danger', // NOTE: `error` type is internally named as `danger`
|
||||
warning: 'kuiButton--warning',
|
||||
info: 'kuiButton--primary',
|
||||
};
|
||||
const buttonHierarchyClass = (index) => {
|
||||
|
@ -108,7 +107,6 @@ const buttonHierarchyClass = (index) => {
|
|||
};
|
||||
const typeToAlertClassMap = {
|
||||
danger: `alert-danger`,
|
||||
warning: `alert-warning`,
|
||||
info: `alert-info`,
|
||||
};
|
||||
|
||||
|
@ -188,7 +186,6 @@ export function Notifier(opts) {
|
|||
|
||||
const notificationLevels = [
|
||||
'error',
|
||||
'warning',
|
||||
];
|
||||
|
||||
notificationLevels.forEach(function (m) {
|
||||
|
@ -199,7 +196,6 @@ export function Notifier(opts) {
|
|||
Notifier.config = {
|
||||
bannerLifetime: 3000000,
|
||||
errorLifetime: 300000,
|
||||
warningLifetime: 10000,
|
||||
infoLifetime: 5000,
|
||||
setInterval: window.setInterval,
|
||||
clearInterval: window.clearInterval
|
||||
|
@ -264,28 +260,6 @@ Notifier.prototype.error = function (err, opts, cb) {
|
|||
return add(config, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Warn the user abort something
|
||||
* @param {String} msg
|
||||
* @param {Function} cb
|
||||
*/
|
||||
Notifier.prototype.warning = function (msg, opts, cb) {
|
||||
if (_.isFunction(opts)) {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
const config = _.assign({
|
||||
type: 'warning',
|
||||
content: formatMsg(msg, this.from),
|
||||
icon: 'warning',
|
||||
title: 'Warning',
|
||||
lifetime: Notifier.config.warningLifetime,
|
||||
actions: ['accept']
|
||||
}, _.pick(opts, overridableOptions));
|
||||
return add(config, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Display a banner message
|
||||
* @param {String} content
|
||||
|
@ -357,8 +331,6 @@ function getDecoratedCustomConfig(config) {
|
|||
|
||||
const getLifetime = (type) => {
|
||||
switch (type) {
|
||||
case 'warning':
|
||||
return Notifier.config.warningLifetime;
|
||||
case 'danger':
|
||||
return Notifier.config.errorLifetime;
|
||||
default: // info
|
||||
|
@ -383,30 +355,6 @@ function getDecoratedCustomConfig(config) {
|
|||
return customConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a custom message
|
||||
* @param {String} msg - required
|
||||
* @param {Object} config - required
|
||||
* @param {Function} cb - optional
|
||||
*
|
||||
* config = {
|
||||
* title: 'Some Title here',
|
||||
* type: 'info',
|
||||
* actions: [{
|
||||
* text: 'next',
|
||||
* callback: function() { next(); }
|
||||
* }, {
|
||||
* text: 'prev',
|
||||
* callback: function() { prev(); }
|
||||
* }]
|
||||
* }
|
||||
*/
|
||||
Notifier.prototype.custom = function (msg, config, cb) {
|
||||
const customConfig = getDecoratedCustomConfig(config);
|
||||
customConfig.content = formatMsg(msg, this.from);
|
||||
return add(customConfig, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Display a scope-bound directive using template rendering in the message area
|
||||
* @param {Object} directive - required
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { find } from 'lodash';
|
||||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import { Notifier } from '../../notify/notifier';
|
||||
import { RouteBasedNotifierProvider } from '../index';
|
||||
|
||||
describe('ui/route_based_notifier', function () {
|
||||
let $rootScope;
|
||||
let routeBasedNotifier;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(($injector) => {
|
||||
const Private = $injector.get('Private');
|
||||
routeBasedNotifier = Private(RouteBasedNotifierProvider);
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
Notifier.prototype._notifs.length = 0;
|
||||
});
|
||||
|
||||
describe('#warning()', () => {
|
||||
it('adds a warning notification', () => {
|
||||
routeBasedNotifier.warning('wat');
|
||||
const notification = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'wat'
|
||||
});
|
||||
expect(notification).not.to.be(undefined);
|
||||
});
|
||||
|
||||
it('can be used more than once for different notifications', () => {
|
||||
routeBasedNotifier.warning('wat');
|
||||
routeBasedNotifier.warning('nowai');
|
||||
|
||||
const notification1 = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'wat'
|
||||
});
|
||||
const notification2 = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'nowai'
|
||||
});
|
||||
|
||||
expect(notification1).not.to.be(undefined);
|
||||
expect(notification2).not.to.be(undefined);
|
||||
});
|
||||
|
||||
it('only adds a notification if it was not previously added in the current route', () => {
|
||||
routeBasedNotifier.warning('wat');
|
||||
routeBasedNotifier.warning('wat');
|
||||
|
||||
const notification = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'wat'
|
||||
});
|
||||
|
||||
expect(notification.count).to.equal(1);
|
||||
});
|
||||
|
||||
it('can add a previously added notification so long as the route changes', () => {
|
||||
routeBasedNotifier.warning('wat');
|
||||
const notification1 = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'wat'
|
||||
});
|
||||
expect(notification1.count).to.equal(1);
|
||||
|
||||
$rootScope.$broadcast('$routeChangeSuccess');
|
||||
|
||||
routeBasedNotifier.warning('wat');
|
||||
const notification2 = find(Notifier.prototype._notifs, {
|
||||
type: 'warning',
|
||||
content: 'wat'
|
||||
});
|
||||
expect(notification2.count).to.equal(2);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { includes, mapValues } from 'lodash';
|
||||
import { Notifier } from '../notify';
|
||||
|
||||
/*
|
||||
* Caches notification attempts so each one is only actually sent to the
|
||||
* notifier service once per route.
|
||||
*/
|
||||
export function RouteBasedNotifierProvider($rootScope) {
|
||||
const notifier = new Notifier();
|
||||
|
||||
let notifications = {
|
||||
warnings: []
|
||||
};
|
||||
|
||||
// empty the tracked notifications whenever the route changes so we can start
|
||||
// fresh for the next route cycle
|
||||
$rootScope.$on('$routeChangeSuccess', () => {
|
||||
notifications = mapValues(notifications, () => []);
|
||||
});
|
||||
|
||||
// Executes the given notify function if the message has not been seen in
|
||||
// this route cycle
|
||||
function executeIfNew(messages, message, notifyFn) {
|
||||
if (includes(messages, message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
messages.push(message);
|
||||
notifyFn.call(notifier, message);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Notify a given warning once in this route cycle
|
||||
* @param {string} message
|
||||
*/
|
||||
warning(message) {
|
||||
executeIfNew(
|
||||
notifications.warnings,
|
||||
message,
|
||||
notifier.warning
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -20,13 +20,12 @@
|
|||
|
||||
import { SavedObjectNotFound } from '../errors';
|
||||
import { uiModules } from '../modules';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
uiModules.get('kibana/url')
|
||||
.service('redirectWhenMissing', function (Private) { return Private(RedirectWhenMissingProvider); });
|
||||
|
||||
export function RedirectWhenMissingProvider($location, kbnUrl, Notifier, Promise) {
|
||||
const notify = new Notifier();
|
||||
|
||||
export function RedirectWhenMissingProvider($location, kbnUrl, Promise) {
|
||||
/**
|
||||
* Creates an error handler that will redirect to a url when a SavedObjectNotFound
|
||||
* error is thrown
|
||||
|
@ -55,7 +54,7 @@ export function RedirectWhenMissingProvider($location, kbnUrl, Notifier, Promise
|
|||
|
||||
url += (url.indexOf('?') >= 0 ? '&' : '?') + `notFound=${err.savedObjectType}`;
|
||||
|
||||
notify.warning(err);
|
||||
toastNotifications.addWarning(err.message);
|
||||
kbnUrl.redirect(url);
|
||||
return Promise.halt();
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import d3 from 'd3';
|
||||
import 'ace';
|
||||
import rison from 'rison-node';
|
||||
import React from 'react';
|
||||
|
||||
// import the uiExports that we want to "use"
|
||||
import 'uiExports/fieldFormats';
|
||||
|
@ -390,7 +391,7 @@ app.controller('graphuiPlugin', function ($scope, $route, $interval, $http, kbnU
|
|||
return $http.post('../api/graph/graphExplore', request)
|
||||
.then(function (resp) {
|
||||
if (resp.data.resp.timed_out) {
|
||||
notify.warning('Exploration timed out');
|
||||
toastNotifications.addWarning('Exploration timed out');
|
||||
}
|
||||
responseHandler(resp.data.resp);
|
||||
})
|
||||
|
@ -538,7 +539,10 @@ app.controller('graphuiPlugin', function ($scope, $route, $interval, $http, kbnU
|
|||
$scope.saveUrlTemplate = function () {
|
||||
const found = $scope.newUrlTemplate.url.search(drillDownRegex) > -1;
|
||||
if (!found) {
|
||||
notify.warning('Invalid URL - the url must contain a {{gquery}} string');
|
||||
toastNotifications.addWarning({
|
||||
title: 'Invalid URL',
|
||||
text: 'The URL must contain a {{gquery}} string',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if ($scope.newUrlTemplate.templateBeingEdited) {
|
||||
|
@ -715,9 +719,14 @@ app.controller('graphuiPlugin', function ($scope, $route, $interval, $http, kbnU
|
|||
.on('zoom', redraw));
|
||||
|
||||
|
||||
const managementUrl = chrome.getNavLinkById('kibana:management').url;
|
||||
const url = `${managementUrl}/kibana/indices`;
|
||||
|
||||
if ($scope.indices.length === 0) {
|
||||
notify.warning('Oops, no data sources. First head over to Kibana settings and define a choice of index pattern');
|
||||
toastNotifications.addWarning({
|
||||
title: 'No data source',
|
||||
text: <p>Go to <a href={url}>Management > Index Patterns</a> and create an index pattern</p>,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -941,7 +950,7 @@ app.controller('graphuiPlugin', function ($scope, $route, $interval, $http, kbnU
|
|||
if ($scope.allSavingDisabled) {
|
||||
// It should not be possible to navigate to this function if allSavingDisabled is set
|
||||
// but adding check here as a safeguard.
|
||||
notify.warning('Saving is disabled');
|
||||
toastNotifications.addWarning('Saving is disabled');
|
||||
return;
|
||||
}
|
||||
initWorkspaceIfRequired();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// Service with functions used for broadcasting job picker changes
|
||||
|
||||
import _ from 'lodash';
|
||||
import { notify } from 'ui/notify';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
import { mlJobService } from 'plugins/ml/services/job_service';
|
||||
|
||||
|
@ -43,7 +43,7 @@ export function JobSelectServiceProvider($rootScope, globalState) {
|
|||
// if there are no valid ids, warn and then select the first job
|
||||
if (validIds.length === 0) {
|
||||
const warningText = `No jobs selected, auto selecting first job`;
|
||||
notify.warning(warningText, { lifetime: 30000 });
|
||||
toastNotifications.addWarning(warningText);
|
||||
|
||||
if (mlJobService.jobs.length) {
|
||||
validIds = [mlJobService.jobs[0].job_id];
|
||||
|
@ -91,7 +91,7 @@ export function JobSelectServiceProvider($rootScope, globalState) {
|
|||
if (invalidIds.length > 0) {
|
||||
const warningText = (invalidIds.length === 1) ? `Requested job ${invalidIds} does not exist` :
|
||||
`Requested jobs ${invalidIds} do not exist`;
|
||||
notify.warning(warningText, { lifetime: 30000 });
|
||||
toastNotifications.addWarning(warningText);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
import React from 'react';
|
||||
import { XPackInfoProvider } from 'plugins/xpack_main/services/xpack_info';
|
||||
import { notify, Notifier } from 'ui/notify';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Notifier, banners } from 'ui/notify';
|
||||
import chrome from 'ui/chrome';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
|
||||
let licenseHasExpired = true;
|
||||
let expiredLicenseBannerId;
|
||||
|
||||
export function checkLicense(Private, kbnBaseUrl) {
|
||||
const xpackInfo = Private(XPackInfoProvider);
|
||||
|
@ -36,10 +36,17 @@ export function checkLicense(Private, kbnBaseUrl) {
|
|||
// Therefore we need to keep the app enabled but show an info banner to the user.
|
||||
if(licenseHasExpired) {
|
||||
const message = features.message;
|
||||
const exists = _.find(notify._notifs, (item) => item.content === message);
|
||||
if (!exists) {
|
||||
// Only show the banner once with no countdown
|
||||
notify.warning(message, { lifetime: 0 });
|
||||
if (expiredLicenseBannerId === undefined) {
|
||||
// Only show the banner once with no way to dismiss it
|
||||
expiredLicenseBannerId = banners.add({
|
||||
component: (
|
||||
<EuiCallOut
|
||||
iconType="iInCircle"
|
||||
color="warning"
|
||||
title={message}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import moment from 'moment';
|
|||
import 'plugins/ml/components/anomalies_table';
|
||||
import 'plugins/ml/components/controls';
|
||||
|
||||
import { notify } from 'ui/notify';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { parseInterval } from 'ui/utils/parse_interval';
|
||||
|
@ -129,24 +129,24 @@ module.controller('MlTimeSeriesExplorerController', function (
|
|||
selectedJobIds = _.without(selectedJobIds, ...invalidIds);
|
||||
if (invalidIds.length > 0) {
|
||||
const s = invalidIds.length === 1 ? '' : 's';
|
||||
let warningText = `Requested job${s} ${invalidIds} cannot be viewed in this dashboard`;
|
||||
let warningText = `You can't view requested job${s} ${invalidIds} in this dashboard`;
|
||||
if (selectedJobIds.length === 0 && timeSeriesJobIds.length > 0) {
|
||||
warningText += ', auto selecting first job';
|
||||
}
|
||||
notify.warning(warningText, { lifetime: 30000 });
|
||||
toastNotifications.addWarning(warningText);
|
||||
}
|
||||
|
||||
if (selectedJobIds.length > 1 || mlJobSelectService.groupIds.length) {
|
||||
// if more than one job or a group has been loaded from the URL
|
||||
if (selectedJobIds.length > 1) {
|
||||
// if more than one job, select the first job from the selection.
|
||||
notify.warning('Only one job may be viewed at a time in this dashboard', { lifetime: 30000 });
|
||||
toastNotifications.addWarning('You can only view one job at a time in this dashboard');
|
||||
mlJobSelectService.setJobIds([selectedJobIds[0]]);
|
||||
} else {
|
||||
// if a group has been loaded
|
||||
if (selectedJobIds.length > 0) {
|
||||
// if the group contains valid jobs, select the first
|
||||
notify.warning('Only one job may be viewed at a time in this dashboard', { lifetime: 30000 });
|
||||
toastNotifications.addWarning('You can only view one job at a time in this dashboard');
|
||||
mlJobSelectService.setJobIds([selectedJobIds[0]]);
|
||||
} else if ($scope.jobs.length > 0) {
|
||||
// if there are no valid jobs in the group but there are valid jobs
|
||||
|
@ -660,7 +660,7 @@ module.controller('MlTimeSeriesExplorerController', function (
|
|||
let detectorIndex = appStateDtrIdx !== undefined ? appStateDtrIdx : +(viewableDetectors[0].index);
|
||||
if (_.find(viewableDetectors, { 'index': '' + detectorIndex }) === undefined) {
|
||||
const warningText = `Requested detector index ${detectorIndex} is not valid for job ${$scope.selectedJob.job_id}`;
|
||||
notify.warning(warningText, { lifetime: 30000 });
|
||||
toastNotifications.addWarning(warningText);
|
||||
detectorIndex = +(viewableDetectors[0].index);
|
||||
$scope.appState.mlTimeSeriesExplorer.detectorIndex = detectorIndex;
|
||||
$scope.appState.save();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
|
||||
|
||||
import { notify } from 'ui/notify';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { SavedObjectsClientProvider } from 'ui/saved_objects';
|
||||
|
||||
let indexPatternCache = [];
|
||||
|
@ -69,9 +69,10 @@ export function getCurrentSavedSearch() {
|
|||
export function timeBasedIndexCheck(indexPattern, showNotification = false) {
|
||||
if (indexPattern.isTimeBased() === false) {
|
||||
if (showNotification) {
|
||||
const message = `The index pattern ${indexPattern.title} is not time series based. \
|
||||
Anomaly detection can only be run over indices which are time based.`;
|
||||
notify.warning(message, { lifetime: 0 });
|
||||
toastNotifications.addWarning({
|
||||
title: `The index pattern ${indexPattern.title} is not based on a time series`,
|
||||
text: 'Anomaly detection only runs over time-based indices',
|
||||
});
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { capitalize, get } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import numeral from '@elastic/numeral';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import chrome from 'ui/chrome';
|
||||
import {
|
||||
KuiTableRowCell,
|
||||
KuiTableRow
|
||||
|
@ -18,7 +19,7 @@ import {
|
|||
EuiHealth,
|
||||
EuiLink,
|
||||
} from '@elastic/eui';
|
||||
import { Notifier } from 'ui/notify';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { MonitoringTable } from 'plugins/monitoring/components/table';
|
||||
import { Tooltip } from 'plugins/monitoring/components/tooltip';
|
||||
import { AlertsIndicator } from 'plugins/monitoring/components/cluster/listing/alerts_indicator';
|
||||
|
@ -35,11 +36,11 @@ const columns = [
|
|||
{ title: 'Kibana', sortKey: 'kibana.count' },
|
||||
{ title: 'License', sortKey: 'license.type' }
|
||||
];
|
||||
|
||||
const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) => {
|
||||
return class ClusterRow extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.notify = new Notifier();
|
||||
}
|
||||
|
||||
changeCluster() {
|
||||
|
@ -51,33 +52,45 @@ const clusterRowFactory = (scope, globalState, kbnUrl, showLicenseExpiration) =>
|
|||
});
|
||||
}
|
||||
|
||||
licenseWarning(message) {
|
||||
licenseWarning({ title, text }) {
|
||||
scope.$evalAsync(() => {
|
||||
this.notify.warning(message, {
|
||||
lifetime: 60000
|
||||
});
|
||||
toastNotifications.addWarning({ title, text, 'data-test-subj': 'monitoringLicenseWarning' });
|
||||
});
|
||||
}
|
||||
|
||||
handleClickIncompatibleLicense() {
|
||||
this.licenseWarning(
|
||||
`You can't view the "${this.props.cluster_name}" cluster because the
|
||||
Basic license does not support multi-cluster monitoring.
|
||||
|
||||
Need to monitor multiple clusters? [Get a license with full functionality](https://www.elastic.co/subscriptions/xpack)
|
||||
to enjoy multi-cluster monitoring.`
|
||||
);
|
||||
this.licenseWarning({
|
||||
title: `You can't view the "${this.props.cluster_name}" cluster`,
|
||||
text: (
|
||||
<Fragment>
|
||||
<p>The Basic license does not support multi-cluster monitoring.</p>
|
||||
<p>
|
||||
Need to monitor multiple clusters?{' '}
|
||||
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">Get a license with full functionality</a>{' '}
|
||||
to enjoy multi-cluster monitoring.
|
||||
</p>
|
||||
</Fragment>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
handleClickInvalidLicense() {
|
||||
this.licenseWarning(
|
||||
`You can't view the "${this.props.cluster_name}" cluster because the
|
||||
license information is invalid.
|
||||
const licensingPath = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`;
|
||||
|
||||
Need a license? [Get a free Basic license](https://register.elastic.co/xpack_register)
|
||||
or get a license with [full functionality](https://www.elastic.co/subscriptions/xpack)
|
||||
to enjoy multi-cluster monitoring.`
|
||||
);
|
||||
this.licenseWarning({
|
||||
title: `You can't view the "${this.props.cluster_name}" cluster`,
|
||||
text: (
|
||||
<Fragment>
|
||||
<p>The license information is invalid.</p>
|
||||
<p>
|
||||
Need a license?{' '}
|
||||
<a href={licensingPath}>Get a free Basic license</a> or{' '}
|
||||
<a href="https://www.elastic.co/subscriptions/xpack" target="_blank">get a license with full functionality</a>{' '}
|
||||
to enjoy multi-cluster monitoring.
|
||||
</p>
|
||||
</Fragment>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
getClusterAction() {
|
||||
|
|
|
@ -26,7 +26,7 @@ uiRoutes.when('/home', {
|
|||
return Promise.reject();
|
||||
}
|
||||
if (clusters.length === 1) {
|
||||
// Bypass the cluster listing if there is just 1 cluster
|
||||
// Bypass the cluster listing if there is just 1 cluster
|
||||
kbnUrl.changePath('/overview');
|
||||
return Promise.reject();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import { getLifecycleMethods } from '../_get_lifecycle_methods';
|
|||
export default function ({ getService, getPageObjects }) {
|
||||
const clusterList = getService('monitoringClusterList');
|
||||
const clusterOverview = getService('monitoringClusterOverview');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['monitoring', 'header']);
|
||||
|
||||
describe('Cluster listing', () => {
|
||||
|
@ -57,14 +58,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('clicking the basic cluster shows a toast message', async () => {
|
||||
const basicClusterLink = await clusterList.getClusterLink(UNSUPPORTED_CLUSTER_UUID);
|
||||
await basicClusterLink.click();
|
||||
|
||||
const actualMessage = await PageObjects.header.getToastMessage();
|
||||
const expectedMessage = (
|
||||
`You can't view the "clustertwo" cluster because the Basic license does not support multi-cluster monitoring.
|
||||
Need to monitor multiple clusters? Get a license with full functionality to enjoy multi-cluster monitoring.`
|
||||
);
|
||||
expect(actualMessage).to.be(expectedMessage);
|
||||
await PageObjects.header.clickToastOK();
|
||||
expect(await testSubjects.exists('monitoringLicenseWarning', 2000)).to.be(true);
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -121,14 +115,7 @@ Need to monitor multiple clusters? Get a license with full functionality to enjo
|
|||
it('clicking the non-primary basic cluster shows a toast message', async () => {
|
||||
const basicClusterLink = await clusterList.getClusterLink(UNSUPPORTED_CLUSTER_UUID);
|
||||
await basicClusterLink.click();
|
||||
|
||||
const actualMessage = await PageObjects.header.getToastMessage();
|
||||
const expectedMessage = (
|
||||
`You can't view the "staging" cluster because the Basic license does not support multi-cluster monitoring.
|
||||
Need to monitor multiple clusters? Get a license with full functionality to enjoy multi-cluster monitoring.`
|
||||
);
|
||||
expect(actualMessage).to.be(expectedMessage);
|
||||
await PageObjects.header.clickToastOK();
|
||||
expect(await testSubjects.exists('monitoringLicenseWarning', 2000)).to.be(true);
|
||||
});
|
||||
|
||||
it('clicking the primary basic cluster goes to overview', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue