Use updated deepLinks when using navigateToApp with deepLinkId (#125238)

* Use updated deepLinks when using `navigateToApp` with `deepLinkId`

* add integration test
This commit is contained in:
Pierre Gayvallet 2022-02-10 21:52:34 +01:00 committed by GitHub
parent f3b01b6751
commit 21e26a421a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 19 deletions

View file

@ -67,8 +67,9 @@ const getAppUrl = (mounters: Map<string, Mounter>, appId: string, path: string =
return appendAppPath(appBasePath, path);
};
const getAppDeepLinkPath = (mounters: Map<string, Mounter>, appId: string, deepLinkId: string) => {
return mounters.get(appId)?.deepLinkPaths[deepLinkId];
const getAppDeepLinkPath = (app: App<any>, appId: string, deepLinkId: string) => {
const flattenedLinks = flattenDeepLinks(app.deepLinks);
return flattenedLinks[deepLinkId];
};
const allApplicationsFilter = '__ALL__';
@ -182,7 +183,6 @@ export class ApplicationService {
this.mounters.set(app.id, {
appRoute: app.appRoute!,
appBasePath: basePath.prepend(app.appRoute!),
deepLinkPaths: toDeepLinkPaths(app.deepLinks),
exactRoute: app.exactRoute ?? false,
mount: wrapMount(plugin, app),
unmountBeforeMounting: false,
@ -242,15 +242,17 @@ export class ApplicationService {
? true
: await this.shouldNavigate(overlays, appId);
const targetApp = applications$.value.get(appId);
if (shouldNavigate) {
if (deepLinkId) {
const deepLinkPath = getAppDeepLinkPath(availableMounters, appId, deepLinkId);
if (deepLinkId && targetApp) {
const deepLinkPath = getAppDeepLinkPath(targetApp, appId, deepLinkId);
if (deepLinkPath) {
path = appendAppPath(deepLinkPath, path);
}
}
if (path === undefined) {
path = applications$.value.get(appId)?.defaultPath;
path = targetApp?.defaultPath;
}
if (openInNewTab) {
this.openInNewTab!(getAppUrl(availableMounters, appId, path));
@ -290,8 +292,9 @@ export class ApplicationService {
deepLinkId,
}: { path?: string; absolute?: boolean; deepLinkId?: string } = {}
) => {
if (deepLinkId) {
const deepLinkPath = getAppDeepLinkPath(availableMounters, appId, deepLinkId);
const targetApp = applications$.value.get(appId);
if (deepLinkId && targetApp) {
const deepLinkPath = getAppDeepLinkPath(targetApp, appId, deepLinkId);
if (deepLinkPath) {
path = appendAppPath(deepLinkPath, path);
}
@ -439,12 +442,12 @@ const populateDeepLinkDefaults = (deepLinks?: AppDeepLink[]): AppDeepLink[] => {
}));
};
const toDeepLinkPaths = (deepLinks?: AppDeepLink[]): Mounter['deepLinkPaths'] => {
const flattenDeepLinks = (deepLinks?: AppDeepLink[]): Record<string, string> => {
if (!deepLinks) {
return {};
}
return deepLinks.reduce((deepLinkPaths: Mounter['deepLinkPaths'], deepLink) => {
return deepLinks.reduce((deepLinkPaths: Record<string, string>, deepLink) => {
if (deepLink.path) deepLinkPaths[deepLink.id] = deepLink.path;
return { ...deepLinkPaths, ...toDeepLinkPaths(deepLink.deepLinks) };
return { ...deepLinkPaths, ...flattenDeepLinks(deepLink.deepLinks) };
}, {});
};

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
import { BehaviorSubject } from 'rxjs';
import { take } from 'rxjs/operators';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory, MemoryHistory } from 'history';
@ -16,7 +17,7 @@ import { httpServiceMock } from '../../http/http_service.mock';
import { MockLifecycle } from '../test_types';
import { overlayServiceMock } from '../../overlays/overlay_service.mock';
import { themeServiceMock } from '../../theme/theme_service.mock';
import { AppMountParameters } from '../types';
import { AppMountParameters, AppUpdater } from '../types';
import { Observable } from 'rxjs';
import { MountPoint } from 'kibana/public';
@ -134,6 +135,42 @@ describe('ApplicationService', () => {
expect(history.entries.map((entry) => entry.pathname)).toEqual(['/', '/app/app1/bar']);
});
it('handles updated deepLinks', async () => {
const { register } = service.setup(setupDeps);
const updater$ = new BehaviorSubject<AppUpdater>(() => ({}));
register(Symbol(), {
id: 'app1',
title: 'App1',
deepLinks: [],
updater$,
mount: async ({}: AppMountParameters) => {
return () => undefined;
},
});
const { navigateToApp } = await service.start(startDeps);
updater$.next(() => ({
deepLinks: [
{
id: 'deepLink',
title: 'Some deep link',
path: '/deep-link',
},
],
}));
await navigateToApp('app1', { deepLinkId: 'deepLink' });
expect(history.entries.map((entry) => entry.pathname)).toEqual([
'/',
'/app/app1/deep-link',
]);
});
////
});
});

View file

@ -40,14 +40,12 @@ export const createAppMounter = ({
appId,
html = `<div>App ${appId}</div>`,
appRoute = `/app/${appId}`,
deepLinkPaths = {},
exactRoute = false,
extraMountHook,
}: {
appId: string;
html?: string;
appRoute?: string;
deepLinkPaths?: Record<string, string>;
exactRoute?: boolean;
extraMountHook?: (params: AppMountParameters) => void;
}): MockedMounterTuple => {
@ -58,7 +56,6 @@ export const createAppMounter = ({
mounter: {
appRoute,
appBasePath: appRoute,
deepLinkPaths,
exactRoute,
mount: jest.fn(async (params: AppMountParameters) => {
const { appBasePath: basename, element } = params;

View file

@ -636,7 +636,6 @@ export interface AppLeaveActionFactory {
export interface Mounter {
appRoute: string;
appBasePath: string;
deepLinkPaths: Record<string, string>;
mount: AppMount;
exactRoute: boolean;
unmountBeforeMounting?: boolean;

View file

@ -51,7 +51,6 @@ describe('AppContainer', () => {
appRoute: '/some-route',
unmountBeforeMounting: false,
exactRoute: false,
deepLinkPaths: {},
mount: async ({ element }: AppMountParameters) => {
await promise;
const container = document.createElement('div');
@ -67,7 +66,6 @@ describe('AppContainer', () => {
appRoute: '/some-route',
unmountBeforeMounting: false,
exactRoute: false,
deepLinkPaths: {},
mount: jest.fn().mockImplementation(({ element }) => {
const container = document.createElement('div');
container.innerHTML = 'some-content';
@ -190,7 +188,6 @@ describe('AppContainer', () => {
const mounter = {
appBasePath: '/base-path/some-route',
appRoute: '/some-route',
deepLinkPaths: {},
unmountBeforeMounting: false,
exactRoute: false,
mount: async ({ element }: AppMountParameters) => {