Skip to content

Commit

Permalink
[new-platform] migrate ui/chrome/loading_count API to new platform (#…
Browse files Browse the repository at this point in the history
…21967)

Part of #20696, required for #20697

This migrates the `chrome.loadingCount` API to the new platform, which was not planned to happen before #20697 but is required as the UiSettingsClient uses the loading count to activate the global loading indicator in Kibana. This service is pretty simple, it allows adding an observable with `core.loadingCount.add(observable)` that will be subscribed to in order to contribute to the current "loading count", which can be retrieved with `core.loadingCount.get$()`.

The `ui/chrome/api/loading_count` module is taking the start contract from the service and re-exposing it via the existing `chrome.loadingCount` api that we have today, including `increment()`, `decrement()`, `subscribe()`, and the automatic watching of the loading count exposed by the angular `$http` service.
  • Loading branch information
Spencer committed Aug 17, 2018
1 parent 34b140b commit 191ea1f
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 66 deletions.
21 changes: 21 additions & 0 deletions src/core/public/core_system.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { FatalErrorsService } from './fatal_errors';
import { InjectedMetadataService } from './injected_metadata';
import { LegacyPlatformService } from './legacy_platform';
import { LoadingCountService } from './loading_count';
import { NotificationsService } from './notifications';

const MockLegacyPlatformService = jest.fn<LegacyPlatformService>(
Expand Down Expand Up @@ -65,6 +66,16 @@ jest.mock('./notifications', () => ({
NotificationsService: MockNotificationsService,
}));

const mockLoadingCountContract = {};
const MockLoadingCountService = jest.fn<LoadingCountService>(function _MockNotificationsService(
this: any
) {
this.start = jest.fn().mockReturnValue(mockLoadingCountContract);
});
jest.mock('./loading_count', () => ({
LoadingCountService: MockLoadingCountService,
}));

import { CoreSystem } from './core_system';
jest.spyOn(CoreSystem.prototype, 'stop');

Expand All @@ -89,6 +100,7 @@ describe('constructor', () => {
expect(MockLegacyPlatformService).toHaveBeenCalledTimes(1);
expect(MockFatalErrorsService).toHaveBeenCalledTimes(1);
expect(MockNotificationsService).toHaveBeenCalledTimes(1);
expect(MockLoadingCountService).toHaveBeenCalledTimes(1);
});

it('passes injectedMetadata param to InjectedMetadataService', () => {
Expand Down Expand Up @@ -200,6 +212,15 @@ describe('#start()', () => {
expect(mockInstance.start).toHaveBeenCalledWith();
});

it('calls loadingCount#start()', () => {
startCore();
const [mockInstance] = MockLoadingCountService.mock.instances;
expect(mockInstance.start).toHaveBeenCalledTimes(1);
expect(mockInstance.start).toHaveBeenCalledWith({
fatalErrors: mockFatalErrorsStartContract,
});
});

it('calls fatalErrors#start()', () => {
startCore();
const [mockInstance] = MockFatalErrorsService.mock.instances;
Expand Down
7 changes: 6 additions & 1 deletion src/core/public/core_system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import './core.css';
import { FatalErrorsService } from './fatal_errors';
import { InjectedMetadataParams, InjectedMetadataService } from './injected_metadata';
import { LegacyPlatformParams, LegacyPlatformService } from './legacy_platform';
import { LoadingCountService } from './loading_count';
import { NotificationsService } from './notifications';

interface Params {
Expand All @@ -41,6 +42,7 @@ export class CoreSystem {
private readonly injectedMetadata: InjectedMetadataService;
private readonly legacyPlatform: LegacyPlatformService;
private readonly notifications: NotificationsService;
private readonly loadingCount: LoadingCountService;

private readonly rootDomElement: HTMLElement;
private readonly notificationsTargetDomElement: HTMLDivElement;
Expand Down Expand Up @@ -68,6 +70,8 @@ export class CoreSystem {
targetDomElement: this.notificationsTargetDomElement,
});

this.loadingCount = new LoadingCountService();

this.legacyPlatformTargetDomElement = document.createElement('div');
this.legacyPlatform = new LegacyPlatformService({
targetDomElement: this.legacyPlatformTargetDomElement,
Expand All @@ -87,7 +91,8 @@ export class CoreSystem {
const notifications = this.notifications.start();
const injectedMetadata = this.injectedMetadata.start();
const fatalErrors = this.fatalErrors.start();
this.legacyPlatform.start({ injectedMetadata, fatalErrors, notifications });
const loadingCount = this.loadingCount.start({ fatalErrors });
this.legacyPlatform.start({ injectedMetadata, fatalErrors, notifications, loadingCount });
} catch (error) {
this.fatalErrors.add(error);
}
Expand Down
76 changes: 41 additions & 35 deletions src/core/public/legacy_platform/legacy_platform_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import angular from 'angular';
import * as Rx from 'rxjs';

const mockLoadOrder: string[] = [];

Expand Down Expand Up @@ -61,6 +62,14 @@ jest.mock('ui/notify/toasts', () => {
};
});

const mockLoadingCountInit = jest.fn();
jest.mock('ui/chrome/api/loading_count', () => {
mockLoadOrder.push('ui/chrome/api/loading_count');
return {
__newPlatformInit__: mockLoadingCountInit,
};
});

import { LegacyPlatformService } from './legacy_platform_service';

const fatalErrorsStartContract = {} as any;
Expand All @@ -72,13 +81,25 @@ const injectedMetadataStartContract = {
getLegacyMetadata: jest.fn(),
};

const loadingCountStartContract = {
add: jest.fn(),
getCount$: jest.fn().mockImplementation(() => new Rx.Observable(observer => observer.next(0))),
};

const defaultParams = {
targetDomElement: document.createElement('div'),
requireLegacyFiles: jest.fn(() => {
mockLoadOrder.push('legacy files');
}),
};

const defaultStartDeps = {
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
loadingCount: loadingCountStartContract,
};

afterEach(() => {
jest.clearAllMocks();
injectedMetadataStartContract.getLegacyMetadata.mockReset();
Expand All @@ -96,11 +117,7 @@ describe('#start()', () => {
...defaultParams,
});

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockUiMetadataInit).toHaveBeenCalledTimes(1);
expect(mockUiMetadataInit).toHaveBeenCalledWith(legacyMetadata);
Expand All @@ -111,11 +128,7 @@ describe('#start()', () => {
...defaultParams,
});

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockFatalErrorInit).toHaveBeenCalledTimes(1);
expect(mockFatalErrorInit).toHaveBeenCalledWith(fatalErrorsStartContract);
Expand All @@ -126,27 +139,30 @@ describe('#start()', () => {
...defaultParams,
});

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockNotifyToastsInit).toHaveBeenCalledTimes(1);
expect(mockNotifyToastsInit).toHaveBeenCalledWith(notificationsStartContract.toasts);
});

it('passes loadingCount service to ui/chrome/api/loading_count', () => {
const legacyPlatform = new LegacyPlatformService({
...defaultParams,
});

legacyPlatform.start(defaultStartDeps);

expect(mockLoadingCountInit).toHaveBeenCalledTimes(1);
expect(mockLoadingCountInit).toHaveBeenCalledWith(loadingCountStartContract);
});

describe('useLegacyTestHarness = false', () => {
it('passes the targetDomElement to ui/chrome', () => {
const legacyPlatform = new LegacyPlatformService({
...defaultParams,
});

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockUiTestHarnessBootstrap).not.toHaveBeenCalled();
expect(mockUiChromeBootstrap).toHaveBeenCalledTimes(1);
Expand All @@ -160,11 +176,7 @@ describe('#start()', () => {
useLegacyTestHarness: true,
});

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockUiChromeBootstrap).not.toHaveBeenCalled();
expect(mockUiTestHarnessBootstrap).toHaveBeenCalledTimes(1);
Expand All @@ -182,16 +194,13 @@ describe('#start()', () => {

expect(mockLoadOrder).toEqual([]);

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockLoadOrder).toEqual([
'ui/metadata',
'ui/notify/fatal_error',
'ui/notify/toasts',
'ui/chrome/api/loading_count',
'ui/chrome',
'legacy files',
]);
Expand All @@ -207,16 +216,13 @@ describe('#start()', () => {

expect(mockLoadOrder).toEqual([]);

legacyPlatform.start({
fatalErrors: fatalErrorsStartContract,
injectedMetadata: injectedMetadataStartContract,
notifications: notificationsStartContract,
});
legacyPlatform.start(defaultStartDeps);

expect(mockLoadOrder).toEqual([
'ui/metadata',
'ui/notify/fatal_error',
'ui/notify/toasts',
'ui/chrome/api/loading_count',
'ui/test_harness',
'legacy files',
]);
Expand Down
5 changes: 4 additions & 1 deletion src/core/public/legacy_platform/legacy_platform_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import angular from 'angular';
import { FatalErrorsStartContract } from '../fatal_errors';
import { InjectedMetadataStartContract } from '../injected_metadata';
import { LoadingCountStartContract } from '../loading_count';
import { NotificationsStartContract } from '../notifications';

interface Deps {
injectedMetadata: InjectedMetadataStartContract;
fatalErrors: FatalErrorsStartContract;
notifications: NotificationsStartContract;
loadingCount: LoadingCountStartContract;
}

export interface LegacyPlatformParams {
Expand All @@ -44,12 +46,13 @@ export interface LegacyPlatformParams {
export class LegacyPlatformService {
constructor(private readonly params: LegacyPlatformParams) {}

public start({ injectedMetadata, fatalErrors, notifications }: Deps) {
public start({ injectedMetadata, fatalErrors, notifications, loadingCount }: Deps) {
// Inject parts of the new platform into parts of the legacy platform
// so that legacy APIs/modules can mimic their new platform counterparts
require('ui/metadata').__newPlatformInit__(injectedMetadata.getLegacyMetadata());
require('ui/notify/fatal_error').__newPlatformInit__(fatalErrors);
require('ui/notify/toasts').__newPlatformInit__(notifications.toasts);
require('ui/chrome/api/loading_count').__newPlatformInit__(loadingCount);

// Load the bootstrap module before loading the legacy platform files so that
// the bootstrap module can modify the environment a bit first
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`adds a fatal error if count observable emits a negative number 1`] = `
Array [
Array [
[Error: Observables passed to loadingCount.add() must only emit positive numbers],
],
]
`;

exports[`adds a fatal error if count observables emit an error 1`] = `
Array [
Array [
[Error: foo bar],
],
]
`;

exports[`emits 0 initially, the right count when sources emit their own count, and ends with zero 1`] = `
Array [
0,
100,
110,
111,
11,
21,
20,
0,
]
`;

exports[`only emits when loading count changes 1`] = `
Array [
0,
1,
0,
]
`;
20 changes: 20 additions & 0 deletions src/core/public/loading_count/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.
*/

export { LoadingCountService, LoadingCountStartContract } from './loading_count_service';
Loading

0 comments on commit 191ea1f

Please sign in to comment.