From 8609aa06f7498c26d3f7723659d88402c00734d6 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Fri, 13 Mar 2020 20:08:58 +0100 Subject: [PATCH] Move subscribe_with_scope to kibana_legacy (#59781) --- .../kibana/public/dashboard/legacy_imports.ts | 3 +- .../np_ready/dashboard_app_controller.tsx | 37 +++++++--- .../kibana/public/discover/kibana_services.ts | 2 +- .../discover/np_ready/angular/discover.js | 38 +++++++--- .../edit_index_pattern/edit_index_pattern.js | 15 ++-- .../kibana/public/visualize/legacy_imports.ts | 2 +- .../visualize/np_ready/editor/editor.js | 52 +++++++++----- .../ui/public/chrome/directives/kbn_chrome.js | 16 +++-- src/legacy/ui/public/config/config.js | 18 +++-- src/legacy/ui/public/notify/fatal_error.ts | 19 +---- src/legacy/ui/public/notify/index.js | 2 +- .../ui/public/timefilter/setup_router.test.js | 2 +- .../ui/public/timefilter/setup_router.ts | 25 +++++-- .../kibana_legacy/public/angular/index.ts | 1 + .../angular}/subscribe_with_scope.test.ts | 71 ++++++++++++------- .../public/angular}/subscribe_with_scope.ts | 43 ++++++----- .../public/notify/lib/add_fatal_error.ts} | 22 ++++-- .../kibana_legacy/public/notify/lib/index.ts | 1 + 18 files changed, 241 insertions(+), 128 deletions(-) rename src/{legacy/ui/public/utils => plugins/kibana_legacy/public/angular}/subscribe_with_scope.test.ts (75%) rename src/{legacy/ui/public/utils => plugins/kibana_legacy/public/angular}/subscribe_with_scope.ts (67%) rename src/{legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts => plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts} (61%) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index beadcda5952880..0c5329d8b259f8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -25,7 +25,7 @@ */ export { npSetup, npStart } from 'ui/new_platform'; -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; + export { KbnUrl } from 'ui/url/kbn_url'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url/index'; @@ -38,4 +38,5 @@ export { migrateLegacyQuery, PrivateProvider, PromiseServiceCreator, + subscribeWithScope, } from '../../../../../plugins/kibana_legacy/public'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index 54436b8d785a01..d1e4c9d2d2a0c0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -78,7 +78,11 @@ import { removeQueryParam, unhashUrl, } from '../../../../../../plugins/kibana_utils/public'; -import { KibanaLegacyStart } from '../../../../../../plugins/kibana_legacy/public'; +import { + addFatalError, + AngularHttpError, + KibanaLegacyStart, +} from '../../../../../../plugins/kibana_legacy/public'; export interface DashboardAppControllerDependencies extends RenderDeps { $scope: DashboardAppScope; @@ -115,6 +119,7 @@ export class DashboardAppController { overlays, chrome, injectedMetadata, + fatalErrors, uiSettings, savedObjects, http, @@ -592,21 +597,31 @@ export class DashboardAppController { $scope.timefilterSubscriptions$ = new Subscription(); $scope.timefilterSubscriptions$.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: () => { - updateState(); - refreshDashboardContainer(); + subscribeWithScope( + $scope, + timefilter.getRefreshIntervalUpdate$(), + { + next: () => { + updateState(); + refreshDashboardContainer(); + }, }, - }) + (error: AngularHttpError | Error | string) => addFatalError(fatalErrors, error) + ) ); $scope.timefilterSubscriptions$.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: () => { - updateState(); - refreshDashboardContainer(); + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: () => { + updateState(); + refreshDashboardContainer(); + }, }, - }) + (error: AngularHttpError | Error | string) => addFatalError(fatalErrors, error) + ) ); function updateViewMode(newMode: ViewMode) { diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 4634ef58f2f1cd..57a9e4966d6d6f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -56,7 +56,7 @@ export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggRes export { shortenDottedString } from '../../common/utils/shorten_dotted_string'; // @ts-ignore export { intervalOptions } from 'ui/agg_types'; -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; +export { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public'; // @ts-ignore export { timezoneProvider } from 'ui/vis/lib/timezone'; export { unhashUrl } from '../../../../../plugins/kibana_utils/public'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index c939de9b57078b..f3334c9211e4bd 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -76,6 +76,7 @@ import { getDefaultQuery, } from '../../../../../../../plugins/data/public'; import { getIndexPatternId } from '../helpers/get_index_pattern_id'; +import { addFatalError } from '../../../../../../../plugins/kibana_legacy/public'; const fetchStatuses = { UNINITIALIZED: 'uninitialized', @@ -255,11 +256,16 @@ function discoverController( // update data source when filters update subscriptions.add( - subscribeWithScope($scope, filterManager.getUpdates$(), { - next: () => { - $scope.updateDataSource(); + subscribeWithScope( + $scope, + filterManager.getUpdates$(), + { + next: () => { + $scope.updateDataSource(); + }, }, - }) + error => addFatalError(core.fatalErrors, error) + ) ); const inspectorAdapters = { @@ -621,16 +627,26 @@ function discoverController( ).pipe(debounceTime(100)); subscriptions.add( - subscribeWithScope($scope, searchBarChanges, { - next: $scope.fetch, - }) + subscribeWithScope( + $scope, + searchBarChanges, + { + next: $scope.fetch, + }, + error => addFatalError(core.fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: () => { - $scope.updateTime(); + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: () => { + $scope.updateTime(); + }, }, - }) + error => addFatalError(core.fatalErrors, error) + ) ); //Handling change oft the histogram interval $scope.$watch('state.interval', function(newInterval, oldInterval) { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js index 0cbac20a947bfc..6d302ac5a74f35 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js @@ -28,6 +28,7 @@ import uiRoutes from 'ui/routes'; import { uiModules } from 'ui/modules'; import template from './edit_index_pattern.html'; import { fieldWildcardMatcher } from '../../../../../../../../plugins/kibana_utils/public'; +import { subscribeWithScope } from '../../../../../../../../plugins/kibana_legacy/public'; import { setup as managementSetup } from '../../../../../../management/public/legacy'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; @@ -37,7 +38,6 @@ import { ScriptedFieldsTable } from './scripted_fields_table'; import { i18n } from '@kbn/i18n'; import { I18nContext } from 'ui/i18n'; import { npStart } from 'ui/new_platform'; -import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import { getEditBreadcrumbs } from '../breadcrumbs'; import { createEditIndexPatternPageStateContainer } from './edit_index_pattern_state_container'; @@ -214,11 +214,16 @@ uiModules $scope.getCurrentTab = getCurrentTab; $scope.setCurrentTab = setCurrentTab; - const stateChangedSub = subscribeWithScope($scope, state$, { - next: ({ tab }) => { - handleTabChange($scope, tab); + const stateChangedSub = subscribeWithScope( + $scope, + state$, + { + next: ({ tab }) => { + handleTabChange($scope, tab); + }, }, - }); + fatalError + ); handleTabChange($scope, getCurrentTab()); // setup initial tab depending on initial tab state diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index 66a7bd6f333737..0ddf3ee67aa94a 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -24,7 +24,6 @@ * directly where they are needed. */ -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; @@ -39,4 +38,5 @@ export { migrateLegacyQuery, PrivateProvider, PromiseServiceCreator, + subscribeWithScope, } from '../../../../../plugins/kibana_legacy/public'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 3fab650002c177..c023c402f5fead 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -31,7 +31,7 @@ import { getEditBreadcrumbs } from '../breadcrumbs'; import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public'; -import { kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public'; +import { addFatalError, kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public'; import { SavedObjectSaveModal, showSaveModal, @@ -88,7 +88,7 @@ function VisualizeAppController( toastNotifications, chrome, getBasePath, - core: { docLinks }, + core: { docLinks, fatalErrors }, savedQueryService, uiSettings, I18nContext, @@ -455,16 +455,26 @@ function VisualizeAppController( const subscriptions = new Subscription(); subscriptions.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: () => { - $scope.refreshInterval = timefilter.getRefreshInterval(); + subscribeWithScope( + $scope, + timefilter.getRefreshIntervalUpdate$(), + { + next: () => { + $scope.refreshInterval = timefilter.getRefreshInterval(); + }, }, - }) + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: updateTimeRange, - }) + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: updateTimeRange, + }, + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( @@ -487,16 +497,26 @@ function VisualizeAppController( // update the searchSource when filters update subscriptions.add( - subscribeWithScope($scope, filterManager.getUpdates$(), { - next: () => { - $scope.filters = filterManager.getFilters(); + subscribeWithScope( + $scope, + filterManager.getUpdates$(), + { + next: () => { + $scope.filters = filterManager.getFilters(); + }, }, - }) + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, filterManager.getFetches$(), { - next: $scope.fetch, - }) + subscribeWithScope( + $scope, + filterManager.getFetches$(), + { + next: $scope.fetch, + }, + error => addFatalError(fatalErrors, error) + ) ); $scope.$on('$destroy', () => { diff --git a/src/legacy/ui/public/chrome/directives/kbn_chrome.js b/src/legacy/ui/public/chrome/directives/kbn_chrome.js index 4c5d7981e962ac..45da4ab6b7472e 100644 --- a/src/legacy/ui/public/chrome/directives/kbn_chrome.js +++ b/src/legacy/ui/public/chrome/directives/kbn_chrome.js @@ -20,6 +20,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import $ from 'jquery'; +import { fatalError } from 'ui/notify/fatal_error'; import { uiModules } from '../../modules'; import template from './kbn_chrome.html'; @@ -30,7 +31,7 @@ import { chromeHeaderNavControlsRegistry, NavControlSide, } from '../../registry/chrome_header_nav_controls'; -import { subscribeWithScope } from '../../utils/subscribe_with_scope'; +import { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public'; export function kbnChromeProvider(chrome, internals) { uiModules.get('kibana').directive('kbnChrome', () => { @@ -84,11 +85,16 @@ export function kbnChromeProvider(chrome, internals) { ); } - const chromeVisibility = subscribeWithScope($scope, chrome.visible$, { - next: () => { - // just makes sure change detection is triggered when chrome visibility changes + const chromeVisibility = subscribeWithScope( + $scope, + chrome.visible$, + { + next: () => { + // just makes sure change detection is triggered when chrome visibility changes + }, }, - }); + fatalError + ); $scope.$on('$destroy', () => { chromeVisibility.unsubscribe(); }); diff --git a/src/legacy/ui/public/config/config.js b/src/legacy/ui/public/config/config.js index 28379c4feb94d4..80a9d39221b2c2 100644 --- a/src/legacy/ui/public/config/config.js +++ b/src/legacy/ui/public/config/config.js @@ -18,10 +18,11 @@ */ import angular from 'angular'; +import { fatalError } from 'ui/notify/fatal_error'; import chrome from '../chrome'; import { isPlainObject } from 'lodash'; import { uiModules } from '../modules'; -import { subscribeWithScope } from '../utils/subscribe_with_scope'; +import { subscribeWithScope } from '../../../../plugins/kibana_legacy/public'; const module = uiModules.get('kibana/config'); @@ -52,12 +53,17 @@ module.service(`config`, function($rootScope, Promise) { //* angular specific methods * ////////////////////////////// - const subscription = subscribeWithScope($rootScope, uiSettings.getUpdate$(), { - next: ({ key, newValue, oldValue }) => { - $rootScope.$broadcast('change:config', newValue, oldValue, key, this); - $rootScope.$broadcast(`change:config.${key}`, newValue, oldValue, key, this); + const subscription = subscribeWithScope( + $rootScope, + uiSettings.getUpdate$(), + { + next: ({ key, newValue, oldValue }) => { + $rootScope.$broadcast('change:config', newValue, oldValue, key, this); + $rootScope.$broadcast(`change:config.${key}`, newValue, oldValue, key, this); + }, }, - }); + fatalError + ); $rootScope.$on('$destroy', () => subscription.unsubscribe()); this.watchAll = function(handler, scope = $rootScope) { diff --git a/src/legacy/ui/public/notify/fatal_error.ts b/src/legacy/ui/public/notify/fatal_error.ts index 7fa2ae7ac6fe6a..5614ffea7913e7 100644 --- a/src/legacy/ui/public/notify/fatal_error.ts +++ b/src/legacy/ui/public/notify/fatal_error.ts @@ -18,23 +18,8 @@ */ import { npSetup } from 'ui/new_platform'; -import { - AngularHttpError, - formatAngularHttpError, - isAngularHttpError, -} from '../../../../plugins/kibana_legacy/public'; - -export function addFatalErrorCallback(callback: () => void) { - npSetup.core.fatalErrors.get$().subscribe(() => { - callback(); - }); -} +import { AngularHttpError, addFatalError } from '../../../../plugins/kibana_legacy/public'; export function fatalError(error: AngularHttpError | Error | string, location?: string) { - // add support for angular http errors to newPlatformFatalErrors - if (isAngularHttpError(error)) { - error = formatAngularHttpError(error); - } - - npSetup.core.fatalErrors.add(error, location); + addFatalError(npSetup.core.fatalErrors, error, location); } diff --git a/src/legacy/ui/public/notify/index.js b/src/legacy/ui/public/notify/index.js index 7ec6a394d7e885..51394033e4d2e0 100644 --- a/src/legacy/ui/public/notify/index.js +++ b/src/legacy/ui/public/notify/index.js @@ -17,6 +17,6 @@ * under the License. */ -export { fatalError, addFatalErrorCallback } from './fatal_error'; +export { fatalError } from './fatal_error'; export { toastNotifications } from './toasts'; export { banners } from './banners'; diff --git a/src/legacy/ui/public/timefilter/setup_router.test.js b/src/legacy/ui/public/timefilter/setup_router.test.js index 46465f3a89ef08..2ae9a053ae2db1 100644 --- a/src/legacy/ui/public/timefilter/setup_router.test.js +++ b/src/legacy/ui/public/timefilter/setup_router.test.js @@ -18,7 +18,7 @@ */ import { registerTimefilterWithGlobalState } from './setup_router'; -jest.mock('ui/utils/subscribe_with_scope', () => ({ +jest.mock('../../../../plugins/kibana_legacy/public', () => ({ subscribeWithScope: jest.fn(), })); diff --git a/src/legacy/ui/public/timefilter/setup_router.ts b/src/legacy/ui/public/timefilter/setup_router.ts index 64105b016fb44c..a7492e538b3af1 100644 --- a/src/legacy/ui/public/timefilter/setup_router.ts +++ b/src/legacy/ui/public/timefilter/setup_router.ts @@ -20,10 +20,11 @@ import _ from 'lodash'; import { IScope } from 'angular'; import moment from 'moment'; -import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import chrome from 'ui/chrome'; import { RefreshInterval, TimeRange, TimefilterContract } from 'src/plugins/data/public'; import { Subscription } from 'rxjs'; +import { fatalError } from 'ui/notify/fatal_error'; +import { subscribeWithScope } from '../../../../plugins/kibana_legacy/public'; // TODO // remove everything underneath once globalState is no longer an angular service @@ -79,15 +80,25 @@ export const registerTimefilterWithGlobalStateFactory = ( const subscriptions = new Subscription(); subscriptions.add( - subscribeWithScope($rootScope, timefilter.getRefreshIntervalUpdate$(), { - next: updateGlobalStateWithTime, - }) + subscribeWithScope( + $rootScope, + timefilter.getRefreshIntervalUpdate$(), + { + next: updateGlobalStateWithTime, + }, + fatalError + ) ); subscriptions.add( - subscribeWithScope($rootScope, timefilter.getTimeUpdate$(), { - next: updateGlobalStateWithTime, - }) + subscribeWithScope( + $rootScope, + timefilter.getTimeUpdate$(), + { + next: updateGlobalStateWithTime, + }, + fatalError + ) ); $rootScope.$on('$destroy', () => { diff --git a/src/plugins/kibana_legacy/public/angular/index.ts b/src/plugins/kibana_legacy/public/angular/index.ts index 0b234b70428508..5fc37ac39612a4 100644 --- a/src/plugins/kibana_legacy/public/angular/index.ts +++ b/src/plugins/kibana_legacy/public/angular/index.ts @@ -24,3 +24,4 @@ export * from './angular_config'; export { ensureDefaultIndexPattern } from './ensure_default_index_pattern'; // @ts-ignore export { createTopNavDirective, createTopNavHelper, loadKbnTopNavDirectives } from './kbn_top_nav'; +export { subscribeWithScope } from './subscribe_with_scope'; diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.test.ts b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts similarity index 75% rename from src/legacy/ui/public/utils/subscribe_with_scope.test.ts rename to src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts index c392d416112c83..a8565b11a7dfd0 100644 --- a/src/legacy/ui/public/utils/subscribe_with_scope.test.ts +++ b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import { mockFatalError } from './subscribe_with_scope.test.mocks'; - import * as Rx from 'rxjs'; import { subscribeWithScope } from './subscribe_with_scope'; @@ -73,14 +71,20 @@ it('calls observer.next() if already in a digest cycle, wraps in $scope.$apply i }); it('reports fatalError if observer.next() throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.of(undefined), { - next() { - throw new Error('foo bar'); + subscribeWithScope( + $scope as any, + Rx.of(undefined), + { + next() { + throw new Error('foo bar'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo bar], @@ -90,12 +94,13 @@ Array [ }); it('reports fatal error if observer.error is not defined and observable errors', () => { + const fatalError = jest.fn(); const $scope = new Scope(); const error = new Error('foo'); error.stack = `${error.message}\n---stack trace ---`; - subscribeWithScope($scope as any, Rx.throwError(error)); + subscribeWithScope($scope as any, Rx.throwError(error), undefined, fatalError); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: Uncaught error in subscribeWithScope(): foo @@ -106,14 +111,20 @@ Array [ }); it('reports fatal error if observer.error throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.throwError(new Error('foo')), { - error: () => { - throw new Error('foo'); + subscribeWithScope( + $scope as any, + Rx.throwError(new Error('foo')), + { + error: () => { + throw new Error('foo'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo], @@ -123,25 +134,37 @@ Array [ }); it('does not report fatal error if observer.error handles the error', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.throwError(new Error('foo')), { - error: () => { - // noop, swallow error + subscribeWithScope( + $scope as any, + Rx.throwError(new Error('foo')), + { + error: () => { + // noop, swallow error + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toEqual([]); + expect(fatalError.mock.calls).toEqual([]); }); it('reports fatal error if observer.complete throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.EMPTY, { - complete: () => { - throw new Error('foo'); + subscribeWithScope( + $scope as any, + Rx.EMPTY, + { + complete: () => { + throw new Error('foo'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo], diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.ts b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts similarity index 67% rename from src/legacy/ui/public/utils/subscribe_with_scope.ts rename to src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts index f4f158cbbd1a81..519291d39797ce 100644 --- a/src/legacy/ui/public/utils/subscribe_with_scope.ts +++ b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts @@ -19,9 +19,11 @@ import { IScope } from 'angular'; import * as Rx from 'rxjs'; -import { fatalError } from 'ui/notify/fatal_error'; +import { AngularHttpError } from '../notify/lib'; -function callInDigest($scope: IScope, fn: () => void) { +type FatalErrorFn = (error: AngularHttpError | Error | string, location?: string) => void; + +function callInDigest($scope: IScope, fn: () => void, fatalError?: FatalErrorFn) { try { // this is terrible, but necessary to synchronously deliver subscription values // to angular scopes. This is required by some APIs, like the `config` service, @@ -35,7 +37,9 @@ function callInDigest($scope: IScope, fn: () => void) { $scope.$apply(() => fn()); } } catch (error) { - fatalError(error); + if (fatalError) { + fatalError(error); + } } } @@ -46,30 +50,35 @@ function callInDigest($scope: IScope, fn: () => void) { export function subscribeWithScope( $scope: IScope, observable: Rx.Observable, - observer?: Rx.PartialObserver + observer?: Rx.PartialObserver, + fatalError?: FatalErrorFn ) { return observable.subscribe({ next(value) { if (observer && observer.next) { - callInDigest($scope, () => observer.next!(value)); + callInDigest($scope, () => observer.next!(value), fatalError); } }, error(error) { - callInDigest($scope, () => { - if (observer && observer.error) { - observer.error(error); - } else { - throw new Error( - `Uncaught error in subscribeWithScope(): ${ - error ? error.stack || error.message : error - }` - ); - } - }); + callInDigest( + $scope, + () => { + if (observer && observer.error) { + observer.error(error); + } else { + throw new Error( + `Uncaught error in subscribeWithScope(): ${ + error ? error.stack || error.message : error + }` + ); + } + }, + fatalError + ); }, complete() { if (observer && observer.complete) { - callInDigest($scope, () => observer.complete!()); + callInDigest($scope, () => observer.complete!(), fatalError); } }, }); diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts b/src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts similarity index 61% rename from src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts rename to src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts index 815d2f09150c7a..928d59d71fbdf7 100644 --- a/src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts +++ b/src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts @@ -16,8 +16,22 @@ * specific language governing permissions and limitations * under the License. */ +import { FatalErrorsSetup } from '../../../../../core/public'; +import { + AngularHttpError, + formatAngularHttpError, + isAngularHttpError, +} from './format_angular_http_error'; -export const mockFatalError = jest.fn(); -jest.mock('ui/notify/fatal_error', () => ({ - fatalError: mockFatalError, -})); +export function addFatalError( + fatalErrors: FatalErrorsSetup, + error: AngularHttpError | Error | string, + location?: string +) { + // add support for angular http errors to newPlatformFatalErrors + if (isAngularHttpError(error)) { + error = formatAngularHttpError(error); + } + + fatalErrors.add(error, location); +} diff --git a/src/plugins/kibana_legacy/public/notify/lib/index.ts b/src/plugins/kibana_legacy/public/notify/lib/index.ts index c374b5926b64f0..f43ba91b102e45 100644 --- a/src/plugins/kibana_legacy/public/notify/lib/index.ts +++ b/src/plugins/kibana_legacy/public/notify/lib/index.ts @@ -25,3 +25,4 @@ export { formatAngularHttpError, AngularHttpError, } from './format_angular_http_error'; +export { addFatalError } from './add_fatal_error';