[new-platform] migrate ui/chrome/loading_count API to new platform (#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.
This commit is contained in:
parent
34b140b2ba
commit
191ea1ffd8
|
@ -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>(
|
||||
|
@ -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');
|
||||
|
||||
|
@ -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', () => {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import angular from 'angular';
|
||||
import * as Rx from 'rxjs';
|
||||
|
||||
const mockLoadOrder: string[] = [];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -72,6 +81,11 @@ 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(() => {
|
||||
|
@ -79,6 +93,13 @@ const defaultParams = {
|
|||
}),
|
||||
};
|
||||
|
||||
const defaultStartDeps = {
|
||||
fatalErrors: fatalErrorsStartContract,
|
||||
injectedMetadata: injectedMetadataStartContract,
|
||||
notifications: notificationsStartContract,
|
||||
loadingCount: loadingCountStartContract,
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
injectedMetadataStartContract.getLegacyMetadata.mockReset();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
]);
|
||||
|
@ -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',
|
||||
]);
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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
|
||||
|
|
|
@ -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
src/core/public/loading_count/index.ts
Normal file
20
src/core/public/loading_count/index.ts
Normal file
|
@ -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';
|
119
src/core/public/loading_count/loading_count_service.test.ts
Normal file
119
src/core/public/loading_count/loading_count_service.test.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
import { toArray } from 'rxjs/operators';
|
||||
|
||||
import { LoadingCountService } from './loading_count_service';
|
||||
|
||||
function setup() {
|
||||
const service = new LoadingCountService();
|
||||
const fatalErrors: any = {
|
||||
add: jest.fn(),
|
||||
};
|
||||
const startContract = service.start({ fatalErrors });
|
||||
|
||||
return { service, fatalErrors, startContract };
|
||||
}
|
||||
|
||||
it('subscribes to sources passed to add(), unsubscribes on stop', () => {
|
||||
const { service, startContract } = setup();
|
||||
|
||||
const unsubA = jest.fn();
|
||||
const subA = jest.fn().mockReturnValue(unsubA);
|
||||
startContract.add(new Rx.Observable(subA));
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).not.toHaveBeenCalled();
|
||||
|
||||
const unsubB = jest.fn();
|
||||
const subB = jest.fn().mockReturnValue(unsubB);
|
||||
startContract.add(new Rx.Observable(subB));
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).not.toHaveBeenCalled();
|
||||
|
||||
service.stop();
|
||||
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).toHaveBeenCalledTimes(1);
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('emits 0 initially, the right count when sources emit their own count, and ends with zero', async () => {
|
||||
const { service, startContract } = setup();
|
||||
|
||||
const countA$ = new Rx.Subject<number>();
|
||||
const countB$ = new Rx.Subject<number>();
|
||||
const countC$ = new Rx.Subject<number>();
|
||||
const promise = startContract
|
||||
.getCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
startContract.add(countA$);
|
||||
startContract.add(countB$);
|
||||
startContract.add(countC$);
|
||||
|
||||
countA$.next(100);
|
||||
countB$.next(10);
|
||||
countC$.next(1);
|
||||
countA$.complete();
|
||||
countB$.next(20);
|
||||
countC$.complete();
|
||||
countB$.next(0);
|
||||
|
||||
service.stop();
|
||||
expect(await promise).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('only emits when loading count changes', async () => {
|
||||
const { service, startContract } = setup();
|
||||
|
||||
const count$ = new Rx.Subject<number>();
|
||||
const promise = startContract
|
||||
.getCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
startContract.add(count$);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(1);
|
||||
count$.next(1);
|
||||
service.stop();
|
||||
|
||||
expect(await promise).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds a fatal error if count observables emit an error', async () => {
|
||||
const { startContract, fatalErrors } = setup();
|
||||
|
||||
startContract.add(Rx.throwError(new Error('foo bar')));
|
||||
expect(fatalErrors.add.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds a fatal error if count observable emits a negative number', async () => {
|
||||
const { startContract, fatalErrors } = setup();
|
||||
|
||||
startContract.add(Rx.of(1, 2, 3, 4, -9));
|
||||
expect(fatalErrors.add.mock.calls).toMatchSnapshot();
|
||||
});
|
86
src/core/public/loading_count/loading_count_service.ts
Normal file
86
src/core/public/loading_count/loading_count_service.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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 * as Rx from 'rxjs';
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
endWith,
|
||||
map,
|
||||
pairwise,
|
||||
startWith,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { FatalErrorsStartContract } from '../fatal_errors';
|
||||
|
||||
interface Deps {
|
||||
fatalErrors: FatalErrorsStartContract;
|
||||
}
|
||||
|
||||
export class LoadingCountService {
|
||||
private readonly total$ = new Rx.BehaviorSubject(0);
|
||||
private readonly stop$ = new Rx.Subject();
|
||||
|
||||
public start({ fatalErrors }: Deps) {
|
||||
return {
|
||||
add: (count$: Rx.Observable<number>) => {
|
||||
count$
|
||||
.pipe(
|
||||
distinctUntilChanged(),
|
||||
|
||||
tap(count => {
|
||||
if (count < 0) {
|
||||
throw new Error(
|
||||
'Observables passed to loadingCount.add() must only emit positive numbers'
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
// use takeUntil() so that we can finish each stream on stop() the same way we do when they complete,
|
||||
// by removing the previous count from the total
|
||||
takeUntil(this.stop$),
|
||||
endWith(0),
|
||||
startWith(0),
|
||||
pairwise(),
|
||||
map(([prev, next]) => next - prev)
|
||||
)
|
||||
.subscribe({
|
||||
next: delta => {
|
||||
this.total$.next(this.total$.getValue() + delta);
|
||||
},
|
||||
error: error => {
|
||||
fatalErrors.add(error);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getCount$: () => {
|
||||
return this.total$.pipe(distinctUntilChanged());
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.stop$.next();
|
||||
this.total$.complete();
|
||||
}
|
||||
}
|
||||
|
||||
export type LoadingCountStartContract = ReturnType<LoadingCountService['start']>;
|
|
@ -17,43 +17,43 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
|
||||
import { isSystemApiRequest } from '../../system_api';
|
||||
|
||||
let newPlatformLoadingCount;
|
||||
|
||||
export function __newPlatformInit__(instance) {
|
||||
if (newPlatformLoadingCount) {
|
||||
throw new Error('ui/chrome/api/loading_count already initialized with new platform apis');
|
||||
}
|
||||
newPlatformLoadingCount = instance;
|
||||
}
|
||||
|
||||
export function initLoadingCountApi(chrome, internals) {
|
||||
const counts = { angular: 0, manual: 0 };
|
||||
const handlers = new Set();
|
||||
|
||||
function getCount() {
|
||||
return counts.angular + counts.manual;
|
||||
}
|
||||
|
||||
// update counts and call handlers with sum if there is a change
|
||||
function update(name, count) {
|
||||
if (counts[name] === count) {
|
||||
return;
|
||||
}
|
||||
|
||||
counts[name] = count;
|
||||
for (const handler of handlers) {
|
||||
handler(getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injected into angular module by ui/chrome angular integration
|
||||
* and adds a root-level watcher that will capture the count of
|
||||
* active $http requests on each digest loop
|
||||
* active $http requests on each digest loop and expose the count to
|
||||
* the core.loadingCount api
|
||||
* @param {Angular.Scope} $rootScope
|
||||
* @param {HttpService} $http
|
||||
* @return {undefined}
|
||||
*/
|
||||
internals.capture$httpLoadingCount = function ($rootScope, $http) {
|
||||
$rootScope.$watch(() => {
|
||||
const reqs = $http.pendingRequests || [];
|
||||
update('angular', reqs.filter(req => !isSystemApiRequest(req)).length);
|
||||
});
|
||||
newPlatformLoadingCount.add(new Rx.Observable(observer => {
|
||||
const unwatch = $rootScope.$watch(() => {
|
||||
const reqs = $http.pendingRequests || [];
|
||||
observer.next(reqs.filter(req => !isSystemApiRequest(req)).length);
|
||||
});
|
||||
|
||||
return unwatch;
|
||||
}));
|
||||
};
|
||||
|
||||
const manualCount$ = new Rx.BehaviorSubject(0);
|
||||
newPlatformLoadingCount.add(manualCount$);
|
||||
|
||||
chrome.loadingCount = new class ChromeLoadingCountApi {
|
||||
/**
|
||||
* Call to add a subscriber to for the loading count that
|
||||
|
@ -63,13 +63,14 @@ export function initLoadingCountApi(chrome, internals) {
|
|||
* @return {Function} unsubscribe
|
||||
*/
|
||||
subscribe(handler) {
|
||||
handlers.add(handler);
|
||||
|
||||
// send the current count to the handler
|
||||
handler(getCount());
|
||||
const subscription = newPlatformLoadingCount.getCount$().subscribe({
|
||||
next(count) {
|
||||
handler(count);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
handlers.delete(handler);
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ export function initLoadingCountApi(chrome, internals) {
|
|||
* @return {undefined}
|
||||
*/
|
||||
increment() {
|
||||
update('manual', counts.manual + 1);
|
||||
manualCount$.next(manualCount$.getValue() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +87,7 @@ export function initLoadingCountApi(chrome, internals) {
|
|||
* @return {undefined}
|
||||
*/
|
||||
decrement() {
|
||||
update('manual', counts.manual - 1);
|
||||
manualCount$.next(manualCount$.getValue() - 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue