Skip to content

Commit

Permalink
Extract fatal notification into fatalError service, add support for E…
Browse files Browse the repository at this point in the history
…uiToast notifications (elastic#15749)

* Reorganize notify/lib files. Extract fatal notification into a fatalError service.
* Convert notify/lib tests to use Jest.
* Add ToastNotifications, GlobalToastList, and documentation.
* Remove notify.info method.
* Add createFirstIndexPatternPrompt.
* Update testSubjects.exists to accept a timeout argument.
* Skip some flaky tests.
  • Loading branch information
cjcenizal committed Jan 27, 2018
1 parent f99bef5 commit a137be0
Show file tree
Hide file tree
Showing 96 changed files with 1,059 additions and 464 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ out an open PR:

- [CONTRIBUTING.md](CONTRIBUTING.md) will help you get Kibana up and running.
- If you would like to contribute code, please follow our [STYLEGUIDE.md](STYLEGUIDE.md).
- Learn more about our UI code with [UI_SYSTEMS.md](src/ui/public/UI_SYSTEMS.md).
- For all other questions, check out the [FAQ.md](FAQ.md) and
[wiki](https://github.com/elastic/kibana/wiki).

Expand Down
15 changes: 12 additions & 3 deletions src/core_plugins/kibana/public/dashboard/dashboard_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import angular from 'angular';
import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
import { applyTheme } from 'ui/theme';
import { toastNotifications } from 'ui/notify';

import 'ui/query_bar';

Expand Down Expand Up @@ -183,14 +184,18 @@ app.directive('dashboardApp', function ($injector) {
$scope.addVis = function (hit, showToast = true) {
dashboardStateManager.addNewPanel(hit.id, 'visualization');
if (showToast) {
notify.info(`Visualization successfully added to your dashboard`);
toastNotifications.addSuccess('Added visualization to your dashboard');
}
};

$scope.addSearch = function (hit) {
dashboardStateManager.addNewPanel(hit.id, 'search');
notify.info(`Search successfully added to your dashboard`);
toastNotifications.addSuccess({
title: 'Added saved search to your dashboard',
'data-test-subj': 'addSavedSearchToDashboardSuccess',
});
};

$scope.$watch('model.hidePanelTitles', () => {
dashboardStateManager.setHidePanelTitles($scope.model.hidePanelTitles);
});
Expand Down Expand Up @@ -268,7 +273,11 @@ app.directive('dashboardApp', function ($injector) {
.then(function (id) {
$scope.kbnTopNav.close('save');
if (id) {
notify.info(`Saved Dashboard as "${dash.title}"`);
toastNotifications.addSuccess({
title: `Saved '${dash.title}'`,
'data-test-subj': 'saveDashboardSuccess',
});

if (dash.id !== $routeParams.id) {
kbnUrl.change(createDashboardEditUrl(dash.id));
} else {
Expand Down
5 changes: 2 additions & 3 deletions src/core_plugins/kibana/public/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'plugins/kibana/dashboard/saved_dashboard/saved_dashboards';
import 'plugins/kibana/dashboard/styles/index.less';
import 'plugins/kibana/dashboard/dashboard_config';
import uiRoutes from 'ui/routes';
import { notify } from 'ui/notify';
import { toastNotifications } from 'ui/notify';

import dashboardTemplate from 'plugins/kibana/dashboard/dashboard_app.html';
import dashboardListingTemplate from './listing/dashboard_listing.html';
Expand Down Expand Up @@ -71,8 +71,7 @@ uiRoutes
if (error instanceof SavedObjectNotFound && id === 'create') {
// Note "new AppState" is neccessary so the state in the url is preserved through the redirect.
kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {}, new AppState());
notify.error(
'The url "dashboard/create" is deprecated and will be removed in 6.0. Please update your bookmarks.');
toastNotifications.addWarning('The url "dashboard/create" was removed in 6.0. Please update your bookmarks.');
} else {
throw error;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as filterActions from 'ui/doc_table/actions/filter';
import dateMath from '@elastic/datemath';
import 'ui/doc_table';
import 'ui/visualize';
import 'ui/notify';
import 'ui/fixed_scroll';
import 'ui/directives/validate_json';
import 'ui/filters/moment';
Expand All @@ -16,6 +15,7 @@ import 'ui/state_management/app_state';
import 'ui/timefilter';
import 'ui/share';
import 'ui/query_bar';
import { toastNotifications } from 'ui/notify';
import { VisProvider } from 'ui/vis';
import { BasicResponseHandlerProvider } from 'ui/vis/response_handlers/basic';
import { DocTitleProvider } from 'ui/doc_title';
Expand Down Expand Up @@ -416,7 +416,11 @@ function discoverController(
$scope.kbnTopNav.close('save');

if (id) {
notify.info('Saved Data Source "' + savedSearch.title + '"');
toastNotifications.addSuccess({
title: `Saved '${savedSearch.title}'`,
'data-test-subj': 'saveSearchSuccess',
});

if (savedSearch.id !== $route.current.params.id) {
kbnUrl.change('/discover/{{id}}', { id: savedSearch.id });
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/core_plugins/kibana/public/kibana.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import 'ui/vislib';
import 'ui/agg_response';
import 'ui/agg_types';
import 'ui/timepicker';
import { Notifier } from 'ui/notify/notifier';
import { Notifier } from 'ui/notify';
import 'leaflet';
import { KibanaRootController } from './kibana_root_controller';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import _ from 'lodash';
import { fatalError } from 'ui/notify';
import { IndexPatternMissingIndices } from 'ui/errors';
import 'ui/directives/validate_index_pattern';
import 'ui/directives/auto_select_if_only_one';
Expand Down Expand Up @@ -288,7 +289,7 @@ uiModules.get('apps/management')
return notify.error(`Couldn't locate any indices matching that pattern. Please add the index to Elasticsearch`);
}

notify.fatal(err);
fatalError(err);
}).finally(() => {
this.isCreatingIndexPattern = false;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import './scripted_field_editor';
import './source_filters_table';
import { KbnUrlProvider } from 'ui/url';
import { IndicesEditSectionsProvider } from './edit_sections';
import { fatalError } from 'ui/notify';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import template from './edit_index_pattern.html';
Expand Down Expand Up @@ -116,7 +117,7 @@ uiModules.get('apps/management')
.then(function () {
$location.url('/management/kibana/index');
})
.catch(notify.fatal);
.catch(fatalError);
}

const confirmModalOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'ui/field_editor';
import { IndexPatternsFieldProvider } from 'ui/index_patterns/_field';
import { KbnUrlProvider } from 'ui/url';
import uiRoutes from 'ui/routes';
import { toastNotifications } from 'ui/notify';
import template from './scripted_field_editor.html';

uiRoutes
Expand Down Expand Up @@ -29,9 +30,8 @@ uiRoutes
}
},
controllerAs: 'fieldSettings',
controller: function FieldEditorPageController($route, Private, Notifier, docTitle) {
controller: function FieldEditorPageController($route, Private, docTitle) {
const Field = Private(IndexPatternsFieldProvider);
const notify = new Notifier({ location: 'Field Editor' });
const kbnUrl = Private(KbnUrlProvider);

this.mode = $route.current.mode;
Expand All @@ -43,7 +43,8 @@ uiRoutes
this.field = this.indexPattern.fields.byName[fieldName];

if (!this.field) {
notify.error(this.indexPattern + ' does not have a "' + fieldName + '" field.');
toastNotifications.add(`'${this.indexPattern.title}' index pattern doesn't have a scripted field called '${fieldName}'`);

kbnUrl.redirectToRoute(this.indexPattern, 'edit');
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import 'ui/paginated_table';
import fieldControlsHtml from '../field_controls.html';
import { dateScripts } from './date_scripts';
import { uiModules } from 'ui/modules';
import { toastNotifications } from 'ui/notify';
import template from './scripted_fields_table.html';
import { getSupportedScriptingLanguages, getDeprecatedScriptingLanguages } from 'ui/scripting_languages';
import { documentationLinks } from 'ui/documentation_links/documentation_links';

uiModules.get('apps/management')
.directive('scriptedFieldsTable', function (kbnUrl, Notifier, $filter, confirmModal) {
.directive('scriptedFieldsTable', function (kbnUrl, $filter, confirmModal) {
const rowScopes = []; // track row scopes, so they can be destroyed as needed
const filter = $filter('filter');

const notify = new Notifier();

return {
restrict: 'E',
template,
Expand Down Expand Up @@ -82,11 +81,17 @@ uiModules.get('apps/management')
});

if (fieldsAdded > 0) {
notify.info(fieldsAdded + ' script fields created');
toastNotifications.addSuccess({
title: 'Created script fields',
text: `Created ${fieldsAdded}`,
});
}

if (conflictFields.length > 0) {
notify.info('Not adding ' + conflictFields.length + ' duplicate fields: ' + conflictFields.join(', '));
toastNotifications.addWarning({
title: `Didn't add duplicate fields`,
text: `${conflictFields.length} fields: ${conflictFields.join(', ')}`,
});
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { find, each, escape, invoke, size, without } from 'lodash';

import { uiModules } from 'ui/modules';
import { Notifier } from 'ui/notify/notifier';
import { Notifier } from 'ui/notify';
import { FieldWildcardProvider } from 'ui/field_wildcard';

import controlsHtml from './controls.html';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ import { savedObjectManagementRegistry } from 'plugins/kibana/management/saved_o
import objectViewHTML from 'plugins/kibana/management/sections/objects/_view.html';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import { fatalError, toastNotifications } from 'ui/notify';
import 'ui/accessibility/kbn_ui_ace_keyboard_mode';
import { castEsToKbnFieldTypeName } from '../../../../../../utils';
import { SavedObjectsClientProvider } from 'ui/saved_objects';

const location = 'SavedObject view';

uiRoutes
.when('/management/kibana/objects/:service/:id', {
template: objectViewHTML
});

uiModules.get('apps/management')
.directive('kbnManagementObjectsView', function (kbnIndex, Notifier, confirmModal) {
.directive('kbnManagementObjectsView', function (kbnIndex, confirmModal) {
return {
restrict: 'E',
controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, Private) {
const notify = new Notifier({ location: 'SavedObject view' });
const serviceObj = savedObjectManagementRegistry.get($routeParams.service);
const service = $injector.get(serviceObj.service);
const savedObjectsClient = Private(SavedObjectsClientProvider);
Expand Down Expand Up @@ -122,7 +124,7 @@ uiModules.get('apps/management')
return (orderIndex > -1) ? orderIndex : Infinity;
});
})
.catch(notify.fatal);
.catch(error => fatalError(error, location));

// This handles the validation of the Ace Editor. Since we don't have any
// other hooks into the editors to tell us if the content is valid or not
Expand Down Expand Up @@ -173,7 +175,7 @@ uiModules.get('apps/management')
.then(function () {
return redirectHandler('deleted');
})
.catch(notify.fatal);
.catch(error => fatalError(error, location));
}
const confirmModalOptions = {
onConfirm: doDelete,
Expand Down Expand Up @@ -207,18 +209,17 @@ uiModules.get('apps/management')
.then(function () {
return redirectHandler('updated');
})
.catch(notify.fatal);
.catch(error => fatalError(error, location));
};

function redirectHandler(action) {
const msg = 'You successfully ' + action + ' the "' + $scope.obj.attributes.title + '" ' + $scope.title.toLowerCase() + ' object';

$location.path('/management/kibana/objects').search({
_a: rison.encode({
tab: serviceObj.title
})
});
notify.info(msg);

toastNotifications.addSuccess(`${_.capitalize(action)} '${$scope.obj.attributes.title}' ${$scope.title.toLowerCase()} object`);
}
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import 'ui/elastic_textarea';
import 'ui/filters/markdown';
import { uiModules } from 'ui/modules';
import { fatalError } from 'ui/notify';
import { keyCodes } from '@elastic/eui';
import advancedRowTemplate from 'plugins/kibana/management/sections/settings/advanced_row.html';

uiModules.get('apps/management')
.directive('advancedRow', function (config, Notifier) {
.directive('advancedRow', function (config) {
return {
restrict: 'A',
replace: true,
Expand All @@ -15,8 +16,6 @@ uiModules.get('apps/management')
configs: '='
},
link: function ($scope) {
const notify = new Notifier();

// To allow passing form validation state back
$scope.forms = {};

Expand All @@ -27,7 +26,7 @@ uiModules.get('apps/management')
.then(function () {
conf.loading = conf.editing = false;
})
.catch(notify.fatal);
.catch(fatalError);
};

$scope.maybeCancel = function ($event, conf) {
Expand Down
10 changes: 7 additions & 3 deletions src/core_plugins/kibana/public/visualize/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'ui/share';
import 'ui/query_bar';
import chrome from 'ui/chrome';
import angular from 'angular';
import { Notifier } from 'ui/notify/notifier';
import { Notifier, toastNotifications } from 'ui/notify';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { DocTitleProvider } from 'ui/doc_title';
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
Expand Down Expand Up @@ -251,7 +251,11 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
$scope.kbnTopNav.close('save');

if (id) {
notify.info('Saved Visualization "' + savedVis.title + '"');
toastNotifications.addSuccess({
title: `Saved '${savedVis.title}'`,
'data-test-subj': 'saveVisualizationSuccess',
});

if ($scope.isAddToDashMode()) {
const savedVisualizationParsedUrl = new KibanaParsedUrl({
basePath: chrome.getBasePath(),
Expand Down Expand Up @@ -281,7 +285,7 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
$scope.unlink = function () {
if (!$state.linked) return;

notify.info(`Unlinked Visualization "${savedVis.title}" from Saved Search "${savedVis.savedSearch.title}"`);
toastNotifications.addSuccess(`Unlinked from saved search '${savedVis.savedSearch.title}'`);

$state.linked = false;
const parent = searchSource.getParent(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import labDisabledTemplate from './visualize_lab_disabled.html';
import chrome from 'ui/chrome';

export class VisualizeEmbeddableFactory extends EmbeddableFactory {
constructor(savedVisualizations, timefilter, Notifier, Promise, Private, config) {
constructor(savedVisualizations, timefilter, Promise, Private, config) {
super();
this._config = config;
this.savedVisualizations = savedVisualizations;
this.name = 'visualization';
this.Promise = Promise;
this.brushEvent = utilsBrushEventProvider(timefilter);
this.filterBarClickHandler = filterBarClickHandlerProvider(Notifier, Private);
this.filterBarClickHandler = filterBarClickHandlerProvider(Private);
}

getEditPath(panelId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ export function visualizeEmbeddableFactoryProvider(Private) {
const VisualizeEmbeddableFactoryProvider = (
savedVisualizations,
timefilter,
Notifier,
Promise,
Private,
config) => {
return new VisualizeEmbeddableFactory(savedVisualizations, timefilter, Notifier, Promise, Private, config);
return new VisualizeEmbeddableFactory(savedVisualizations, timefilter, Promise, Private, config);
};
return Private(VisualizeEmbeddableFactoryProvider);
}
Expand Down
Loading

0 comments on commit a137be0

Please sign in to comment.