From 66e3b4266a742ff4c3d1a61a9e17157d411d4d30 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 14 May 2021 17:23:25 +0200 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20url=20servic?= =?UTF-8?q?e=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/share/common/url_service/index.ts | 10 +++ .../share/common/url_service/locators.ts | 86 +++++++++++++++++++ .../share/common/url_service/url_service.ts | 19 ++++ 3 files changed, 115 insertions(+) create mode 100644 src/plugins/share/common/url_service/index.ts create mode 100644 src/plugins/share/common/url_service/locators.ts create mode 100644 src/plugins/share/common/url_service/url_service.ts diff --git a/src/plugins/share/common/url_service/index.ts b/src/plugins/share/common/url_service/index.ts new file mode 100644 index 0000000000000..84f74356bcf18 --- /dev/null +++ b/src/plugins/share/common/url_service/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './url_service'; +export * from './locators'; diff --git a/src/plugins/share/common/url_service/locators.ts b/src/plugins/share/common/url_service/locators.ts new file mode 100644 index 0000000000000..74ebd77acf1dd --- /dev/null +++ b/src/plugins/share/common/url_service/locators.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PersistableState, SerializableState } from 'src/plugins/kibana_utils/common'; + +/** + * URL locator registry. + */ +export interface LocatorClient { + /** + * Create and register a new locator. + * + * @param urlGenerator Definition of the new locator. + */ + create

(urlGenerator: LocatorDefinition

): LocatorPublic

; + + /** + * Retrieve a previously registered locator. + * + * @param id Unique ID of the locator. + */ + get

(id: string): LocatorPublic

; +} + +/** + * A convenience interface used to define and register a locator. + */ +export interface LocatorDefinition

extends PersistableState

{ + /** + * Unique ID of the locator. Should be constant and unique across Kibana. + */ + id: string; + + /** + * Returns a deep link, including location state, which can be used for + * navigation in Kibana. + * + * @param params Parameters from which to generate a Kibana location. + */ + getLocation(params: P): KibanaLocation; +} + +/** + * Public interface of a registered locator. + */ +export interface LocatorPublic

{ + /** + * Returns a relative URL to the client-side redirect endpoint using this + * locator. (This method is necessary for compatibility with URL generators.) + */ + getRedirectPath(params: P): string; + + /** + * Navigate using the `core.application.navigateToApp()` method to a Kibana + * location generated by this locator. This method is available only on the + * browser. + */ + navigate(params: P): void; +} + +/** + * This interface represents a location in Kibana to which one can navigate + * using the `core.application.navigateToApp()` method. + */ +export interface KibanaLocation { + /** + * Kibana application ID. + */ + app: string; + + /** + * A URL route within a Kibana application. + */ + route: string; + + /** + * A serializable location state object, which the app can use to determine + * what should be displayed on the screen. + */ + state: S; +} diff --git a/src/plugins/share/common/url_service/url_service.ts b/src/plugins/share/common/url_service/url_service.ts new file mode 100644 index 0000000000000..cca6e901ed9cc --- /dev/null +++ b/src/plugins/share/common/url_service/url_service.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { LocatorClient } from './locators'; + +/** + * Common URL Service client interface for server-side and client-side. + */ +export interface UrlService { + /** + * Client to work with locators. + */ + locators: LocatorClient; +} From 2fee1cce7ad1769d81692dacd06b532f9b165d4d Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 14 May 2021 18:48:56 +0200 Subject: [PATCH 02/13] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20move=20locator?= =?UTF-8?q?=20types=20into=20its=20own=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/url_service/{locators.ts => locators/types.ts} | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) rename src/plugins/share/common/url_service/{locators.ts => locators/types.ts} (89%) diff --git a/src/plugins/share/common/url_service/locators.ts b/src/plugins/share/common/url_service/locators/types.ts similarity index 89% rename from src/plugins/share/common/url_service/locators.ts rename to src/plugins/share/common/url_service/locators/types.ts index 74ebd77acf1dd..8514c87911a34 100644 --- a/src/plugins/share/common/url_service/locators.ts +++ b/src/plugins/share/common/url_service/locators/types.ts @@ -17,7 +17,7 @@ export interface LocatorClient { * * @param urlGenerator Definition of the new locator. */ - create

(urlGenerator: LocatorDefinition

): LocatorPublic

; + create

(locatorDefinition: LocatorDefinition

): LocatorPublic

; /** * Retrieve a previously registered locator. @@ -30,7 +30,8 @@ export interface LocatorClient { /** * A convenience interface used to define and register a locator. */ -export interface LocatorDefinition

extends PersistableState

{ +export interface LocatorDefinition

+ extends Partial> { /** * Unique ID of the locator. Should be constant and unique across Kibana. */ @@ -53,7 +54,7 @@ export interface LocatorPublic

{ * Returns a relative URL to the client-side redirect endpoint using this * locator. (This method is necessary for compatibility with URL generators.) */ - getRedirectPath(params: P): string; + getLocation(params: P): KibanaLocation; /** * Navigate using the `core.application.navigateToApp()` method to a Kibana From 26a9cc270432d56a18729d81ca3746c7b5788aa2 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 14 May 2021 18:49:20 +0200 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20abstract=20l?= =?UTF-8?q?ocator=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../url_service/locators/abstract_locator.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/plugins/share/common/url_service/locators/abstract_locator.ts diff --git a/src/plugins/share/common/url_service/locators/abstract_locator.ts b/src/plugins/share/common/url_service/locators/abstract_locator.ts new file mode 100644 index 0000000000000..976d852a9783e --- /dev/null +++ b/src/plugins/share/common/url_service/locators/abstract_locator.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PersistableState, SerializableState } from 'src/plugins/kibana_utils/common'; +import { LocatorDefinition, LocatorPublic, KibanaLocation } from './types'; + +export abstract class AbstractLocator

+ implements PersistableState

, LocatorPublic

{ + public readonly migrations: PersistableState

['migrations']; + + constructor(public readonly definition: LocatorDefinition

) { + this.migrations = definition.migrations || {}; + } + + // PersistableState ---------------------------------------------------------- + + public readonly telemetry: PersistableState

['telemetry'] = () => { + throw new Error('not implemented'); + }; + + public readonly inject: PersistableState

['inject'] = () => { + throw new Error('not implemented'); + }; + + public readonly extract: PersistableState

['extract'] = () => { + throw new Error('not implemented'); + }; + + // LocatorPublic ------------------------------------------------------------- + + public getLocation(params: P): KibanaLocation { + throw new Error('not implemented'); + } + + public navigate(params: P): void { + throw new Error('not implemented'); + } +} From 306ae7b6a6b8293e49a18eecf09e1aaa149fddca Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 14 May 2021 18:50:11 +0200 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20abstra?= =?UTF-8?q?ct=20locator=20client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../locators/abstract_locator_client.ts | 31 +++++++++++++++++++ .../common/url_service/locators/index.ts | 11 +++++++ 2 files changed, 42 insertions(+) create mode 100644 src/plugins/share/common/url_service/locators/abstract_locator_client.ts create mode 100644 src/plugins/share/common/url_service/locators/index.ts diff --git a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts new file mode 100644 index 0000000000000..aa912c41b49be --- /dev/null +++ b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SerializableState } from 'src/plugins/kibana_utils/common'; +import { AbstractLocator } from './abstract_locator'; +import { LocatorClient, LocatorDefinition, LocatorPublic } from './types'; + +export abstract class AbstractLocatorClient implements Pick { + protected abstract readonly Locator: new

( + definition: LocatorDefinition

+ ) => AbstractLocator

; + + protected locators: Map> = new Map(); + + public create

(definition: LocatorDefinition

): LocatorPublic

{ + const locator = new this.Locator

(definition); + + this.locators.set(definition.id, locator); + + return locator; + } + + public get

(id: string): LocatorPublic

{ + throw new Error('not implemented'); + } +} diff --git a/src/plugins/share/common/url_service/locators/index.ts b/src/plugins/share/common/url_service/locators/index.ts new file mode 100644 index 0000000000000..3fb16071dd670 --- /dev/null +++ b/src/plugins/share/common/url_service/locators/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './types'; +export * from './abstract_locator'; +export * from './abstract_locator_client'; From ed4c6716287ee37079e68f6314e9940d1a6fe061 Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 27 May 2021 15:21:01 +0200 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20browser-side?= =?UTF-8?q?=20locators=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/discover/public/url_generator.ts | 14 ++++------- .../url_service/locators/abstract_locator.ts | 4 ++-- .../locators/abstract_locator_client.ts | 6 ++--- src/plugins/share/public/plugin.ts | 24 +++++++++++-------- .../public/url_service/browser_url_service.ts | 14 +++++++++++ src/plugins/share/public/url_service/index.ts | 10 ++++++++ .../url_service/locators/browser_locator.ts | 12 ++++++++++ .../locators/browser_locator_client.ts | 14 +++++++++++ .../public/url_service/locators/index.ts | 10 ++++++++ 9 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 src/plugins/share/public/url_service/browser_url_service.ts create mode 100644 src/plugins/share/public/url_service/index.ts create mode 100644 src/plugins/share/public/url_service/locators/browser_locator.ts create mode 100644 src/plugins/share/public/url_service/locators/browser_locator_client.ts create mode 100644 src/plugins/share/public/url_service/locators/index.ts diff --git a/src/plugins/discover/public/url_generator.ts b/src/plugins/discover/public/url_generator.ts index 21bdbf225d6aa..63dea20fecc0a 100644 --- a/src/plugins/discover/public/url_generator.ts +++ b/src/plugins/discover/public/url_generator.ts @@ -6,16 +6,10 @@ * Side Public License, v 1. */ -import { - TimeRange, - Filter, - Query, - esFilters, - QueryState, - RefreshInterval, -} from '../../data/public'; +import type { UrlGeneratorsDefinition } from '../../share/public'; +import type { TimeRange, Filter, Query, QueryState, RefreshInterval } from '../../data/public'; +import { esFilters } from '../../data/public'; import { setStateToKbnUrl } from '../../kibana_utils/public'; -import { UrlGeneratorsDefinition } from '../../share/public'; export const DISCOVER_APP_URL_GENERATOR = 'DISCOVER_APP_URL_GENERATOR'; @@ -71,10 +65,12 @@ export interface DiscoverUrlGeneratorState { * Used interval of the histogram */ interval?: string; + /** * Array of the used sorting [[field,direction],...] */ sort?: string[][]; + /** * id of the used saved query */ diff --git a/src/plugins/share/common/url_service/locators/abstract_locator.ts b/src/plugins/share/common/url_service/locators/abstract_locator.ts index 976d852a9783e..39ee66f93e31b 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator.ts +++ b/src/plugins/share/common/url_service/locators/abstract_locator.ts @@ -17,7 +17,7 @@ export abstract class AbstractLocator

this.migrations = definition.migrations || {}; } - // PersistableState ---------------------------------------------------------- + // PersistableState

------------------------------------------------------- public readonly telemetry: PersistableState

['telemetry'] = () => { throw new Error('not implemented'); @@ -31,7 +31,7 @@ export abstract class AbstractLocator

throw new Error('not implemented'); }; - // LocatorPublic ------------------------------------------------------------- + // LocatorPublic

---------------------------------------------------------- public getLocation(params: P): KibanaLocation { throw new Error('not implemented'); diff --git a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts index aa912c41b49be..7b66167d51986 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts +++ b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import { SerializableState } from 'src/plugins/kibana_utils/common'; -import { AbstractLocator } from './abstract_locator'; -import { LocatorClient, LocatorDefinition, LocatorPublic } from './types'; +import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import type { AbstractLocator } from './abstract_locator'; +import type { LocatorClient, LocatorDefinition, LocatorPublic } from './types'; export abstract class AbstractLocatorClient implements Pick { protected abstract readonly Locator: new

( diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts index 14d74e055cbd9..e93a523a14619 100644 --- a/src/plugins/share/public/plugin.ts +++ b/src/plugins/share/public/plugin.ts @@ -18,6 +18,8 @@ import { UrlGeneratorsSetup, UrlGeneratorsStart, } from './url_generators/url_generator_service'; +import { UrlService } from '../common/url_service'; +import { BrowserUrlService } from './url_service'; export interface ShareSetupDependencies { securityOss?: SecurityOssPluginSetup; @@ -27,6 +29,17 @@ export interface ShareStartDependencies { securityOss?: SecurityOssPluginStart; } +/** @public */ +export type SharePluginSetup = ShareMenuRegistrySetup & { + urlGenerators: UrlGeneratorsSetup; + url: UrlService; +}; + +/** @public */ +export type SharePluginStart = ShareMenuManagerStart & { + urlGenerators: UrlGeneratorsStart; +}; + export class SharePlugin implements Plugin { private readonly shareMenuRegistry = new ShareMenuRegistry(); private readonly shareContextMenu = new ShareMenuManager(); @@ -37,6 +50,7 @@ export class SharePlugin implements Plugin { return { ...this.shareMenuRegistry.setup(), urlGenerators: this.urlGeneratorsService.setup(core), + url: new BrowserUrlService(), }; } @@ -51,13 +65,3 @@ export class SharePlugin implements Plugin { }; } } - -/** @public */ -export type SharePluginSetup = ShareMenuRegistrySetup & { - urlGenerators: UrlGeneratorsSetup; -}; - -/** @public */ -export type SharePluginStart = ShareMenuManagerStart & { - urlGenerators: UrlGeneratorsStart; -}; diff --git a/src/plugins/share/public/url_service/browser_url_service.ts b/src/plugins/share/public/url_service/browser_url_service.ts new file mode 100644 index 0000000000000..4ffe60421a151 --- /dev/null +++ b/src/plugins/share/public/url_service/browser_url_service.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { UrlService } from '../../common/url_service'; +import { BrowserLocatorsClient } from './locators'; + +export class BrowserUrlService implements UrlService { + public readonly locators = new BrowserLocatorsClient(); +} diff --git a/src/plugins/share/public/url_service/index.ts b/src/plugins/share/public/url_service/index.ts new file mode 100644 index 0000000000000..5b64711790b82 --- /dev/null +++ b/src/plugins/share/public/url_service/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './browser_url_service'; +export type { BrowserLocator, BrowserLocatorsClient } from './locators'; diff --git a/src/plugins/share/public/url_service/locators/browser_locator.ts b/src/plugins/share/public/url_service/locators/browser_locator.ts new file mode 100644 index 0000000000000..ce8c4152ab742 --- /dev/null +++ b/src/plugins/share/public/url_service/locators/browser_locator.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import { AbstractLocator } from '../../../common/url_service'; + +export class BrowserLocator

extends AbstractLocator

{} diff --git a/src/plugins/share/public/url_service/locators/browser_locator_client.ts b/src/plugins/share/public/url_service/locators/browser_locator_client.ts new file mode 100644 index 0000000000000..f329da1e849aa --- /dev/null +++ b/src/plugins/share/public/url_service/locators/browser_locator_client.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AbstractLocatorClient } from '../../../common/url_service'; +import { BrowserLocator } from './browser_locator'; + +export class BrowserLocatorsClient extends AbstractLocatorClient { + protected readonly Locator = BrowserLocator; +} diff --git a/src/plugins/share/public/url_service/locators/index.ts b/src/plugins/share/public/url_service/locators/index.ts new file mode 100644 index 0000000000000..ef005a094b044 --- /dev/null +++ b/src/plugins/share/public/url_service/locators/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './browser_locator'; +export * from './browser_locator_client'; From d60760bf7bdb39475a9cda9df62e077dadcb8080 Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 27 May 2021 16:18:52 +0200 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20locato?= =?UTF-8?q?r=20.getLocation()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../url_service/locators/abstract_locator.ts | 2 +- .../locators/abstract_locator_client.ts | 19 ++++++- .../common/url_service/locators/types.ts | 2 +- .../url_service/__tests__/locators.test.ts | 51 +++++++++++++++++++ .../public/url_service/__tests__/setup.ts | 35 +++++++++++++ 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/plugins/share/public/url_service/__tests__/locators.test.ts create mode 100644 src/plugins/share/public/url_service/__tests__/setup.ts diff --git a/src/plugins/share/common/url_service/locators/abstract_locator.ts b/src/plugins/share/common/url_service/locators/abstract_locator.ts index 39ee66f93e31b..e8a16e6e95ecb 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator.ts +++ b/src/plugins/share/common/url_service/locators/abstract_locator.ts @@ -34,7 +34,7 @@ export abstract class AbstractLocator

// LocatorPublic

---------------------------------------------------------- public getLocation(params: P): KibanaLocation { - throw new Error('not implemented'); + return this.definition.getLocation(params); } public navigate(params: P): void { diff --git a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts index 7b66167d51986..3dbc84ca49e54 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts +++ b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts @@ -15,8 +15,17 @@ export abstract class AbstractLocatorClient implements Pick ) => AbstractLocator

; + /** + * Collection of registered locators. + */ protected locators: Map> = new Map(); + /** + * Creates and register a URL locator. + * + * @param definition A definition of URL locator. + * @returns A public interface of URL locator. + */ public create

(definition: LocatorDefinition

): LocatorPublic

{ const locator = new this.Locator

(definition); @@ -25,7 +34,13 @@ export abstract class AbstractLocatorClient implements Pick(id: string): LocatorPublic

{ - throw new Error('not implemented'); + /** + * Returns a previously registered URL locator. + * + * @param id ID of a URL locator. + * @returns A public interface of a registered URL locator. + */ + public get

(id: string): undefined | LocatorPublic

{ + return this.locators.get(id); } } diff --git a/src/plugins/share/common/url_service/locators/types.ts b/src/plugins/share/common/url_service/locators/types.ts index 8514c87911a34..a4d2adf9fe2e2 100644 --- a/src/plugins/share/common/url_service/locators/types.ts +++ b/src/plugins/share/common/url_service/locators/types.ts @@ -24,7 +24,7 @@ export interface LocatorClient { * * @param id Unique ID of the locator. */ - get

(id: string): LocatorPublic

; + get

(id: string): undefined | LocatorPublic

; } /** diff --git a/src/plugins/share/public/url_service/__tests__/locators.test.ts b/src/plugins/share/public/url_service/__tests__/locators.test.ts new file mode 100644 index 0000000000000..7cc560c71f113 --- /dev/null +++ b/src/plugins/share/public/url_service/__tests__/locators.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { browserTestLocator, BrowserTestLocatorState, urlServiceTestSetup } from './setup'; + +describe('locators', () => { + test('can start locators service', () => { + const { locators } = urlServiceTestSetup(); + + expect(typeof locators).toBe('object'); + expect(typeof locators.create).toBe('function'); + expect(typeof locators.get).toBe('function'); + }); + + test('returns "undefined" for unregistered locator', () => { + const { locators } = urlServiceTestSetup(); + + expect(locators.get(browserTestLocator.id)).toBe(undefined); + }); + + test('can register a locator', () => { + const { locators } = urlServiceTestSetup(); + + locators.create(browserTestLocator); + expect(typeof locators.get(browserTestLocator.id)).toBe('object'); + }); + + test('getLocation() returns KibanaLocation generated by the locator', () => { + const { locators } = urlServiceTestSetup(); + + locators.create(browserTestLocator); + + const locator = locators.get(browserTestLocator.id); + const location = locator?.getLocation({ + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + pageNumber: 21, + showFlyout: true, + }); + + expect(location).toEqual({ + app: 'test_app', + route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=21', + state: { isFlyoutOpen: true }, + }); + }); +}); diff --git a/src/plugins/share/public/url_service/__tests__/setup.ts b/src/plugins/share/public/url_service/__tests__/setup.ts new file mode 100644 index 0000000000000..b9c7ed8c938d7 --- /dev/null +++ b/src/plugins/share/public/url_service/__tests__/setup.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import type { LocatorDefinition, UrlService } from 'src/plugins/share/common/url_service'; +import { BrowserUrlService } from '../browser_url_service'; + +export interface BrowserTestLocatorState extends SerializableState { + savedObjectId: string; + showFlyout: boolean; + pageNumber: number; +} + +export const browserTestLocator: LocatorDefinition = { + id: 'BROWSER_TEST_LOCATOR', + getLocation: ({ savedObjectId, pageNumber, showFlyout }) => { + return { + app: 'test_app', + route: `/my-object/${savedObjectId}?page=${pageNumber}`, + state: { + isFlyoutOpen: showFlyout, + }, + }; + }, +}; + +export const urlServiceTestSetup = (): UrlService => { + const urlService = new BrowserUrlService(); + return urlService; +}; From 298530e7e1c7742078e525466c0c7c3c72ae5ec1 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 28 May 2021 13:34:32 +0200 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20naviga?= =?UTF-8?q?te=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../locators/abstract_locator_client.ts | 10 ++++---- src/plugins/share/public/plugin.ts | 6 ++++- .../public/url_service/browser_url_service.ts | 7 +++++- .../url_service/locators/browser_locator.ts | 23 ++++++++++++++++++- .../locators/browser_locator_client.ts | 13 ++++++++++- 5 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts index 3dbc84ca49e54..06d4cf1b8a477 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts +++ b/src/plugins/share/common/url_service/locators/abstract_locator_client.ts @@ -11,15 +11,15 @@ import type { AbstractLocator } from './abstract_locator'; import type { LocatorClient, LocatorDefinition, LocatorPublic } from './types'; export abstract class AbstractLocatorClient implements Pick { - protected abstract readonly Locator: new

( - definition: LocatorDefinition

- ) => AbstractLocator

; - /** * Collection of registered locators. */ protected locators: Map> = new Map(); + protected abstract createLocator

( + definition: LocatorDefinition

+ ): AbstractLocator

; + /** * Creates and register a URL locator. * @@ -27,7 +27,7 @@ export abstract class AbstractLocatorClient implements Pick(definition: LocatorDefinition

): LocatorPublic

{ - const locator = new this.Locator

(definition); + const locator = this.createLocator

(definition); this.locators.set(definition.id, locator); diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts index e93a523a14619..890028eb9bb01 100644 --- a/src/plugins/share/public/plugin.ts +++ b/src/plugins/share/public/plugin.ts @@ -50,7 +50,11 @@ export class SharePlugin implements Plugin { return { ...this.shareMenuRegistry.setup(), urlGenerators: this.urlGeneratorsService.setup(core), - url: new BrowserUrlService(), + url: new BrowserUrlService({ + navigate: async () => { + throw new Error('not implemented'); + }, + }), }; } diff --git a/src/plugins/share/public/url_service/browser_url_service.ts b/src/plugins/share/public/url_service/browser_url_service.ts index 4ffe60421a151..e51cbd63263c9 100644 --- a/src/plugins/share/public/url_service/browser_url_service.ts +++ b/src/plugins/share/public/url_service/browser_url_service.ts @@ -7,8 +7,13 @@ */ import { UrlService } from '../../common/url_service'; +import type { BrowserLocatorClientDependencies } from './locators'; import { BrowserLocatorsClient } from './locators'; +export type BrowserUrlServiceDependencies = BrowserLocatorClientDependencies; + export class BrowserUrlService implements UrlService { - public readonly locators = new BrowserLocatorsClient(); + public readonly locators = new BrowserLocatorsClient(this.deps); + + constructor(protected readonly deps: BrowserUrlServiceDependencies) {} } diff --git a/src/plugins/share/public/url_service/locators/browser_locator.ts b/src/plugins/share/public/url_service/locators/browser_locator.ts index ce8c4152ab742..0defa59687c4d 100644 --- a/src/plugins/share/public/url_service/locators/browser_locator.ts +++ b/src/plugins/share/public/url_service/locators/browser_locator.ts @@ -7,6 +7,27 @@ */ import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import type { KibanaLocation, LocatorDefinition } from '../../../common/url_service'; import { AbstractLocator } from '../../../common/url_service'; -export class BrowserLocator

extends AbstractLocator

{} +export interface BrowserLocatorDependencies { + navigate: (location: KibanaLocation, params?: NavigationParams) => Promise; +} + +export interface NavigationParams { + replace?: boolean; +} + +export class BrowserLocator

extends AbstractLocator

{ + constructor( + definition: LocatorDefinition

, + protected readonly deps: BrowserLocatorDependencies + ) { + super(definition); + } + + public async navigate(params: P, navigationParams?: NavigationParams): Promise { + const location = this.getLocation(params); + await this.deps.navigate(location, navigationParams); + } +} diff --git a/src/plugins/share/public/url_service/locators/browser_locator_client.ts b/src/plugins/share/public/url_service/locators/browser_locator_client.ts index f329da1e849aa..596e6eaf1fc97 100644 --- a/src/plugins/share/public/url_service/locators/browser_locator_client.ts +++ b/src/plugins/share/public/url_service/locators/browser_locator_client.ts @@ -6,9 +6,20 @@ * Side Public License, v 1. */ +import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import type { BrowserLocatorDependencies } from './browser_locator'; +import type { LocatorDefinition } from '../../../common/url_service'; import { AbstractLocatorClient } from '../../../common/url_service'; import { BrowserLocator } from './browser_locator'; +export type BrowserLocatorClientDependencies = BrowserLocatorDependencies; + export class BrowserLocatorsClient extends AbstractLocatorClient { - protected readonly Locator = BrowserLocator; + constructor(protected readonly deps: BrowserLocatorClientDependencies) { + super(); + } + + protected createLocator

(definition: LocatorDefinition

) { + return new BrowserLocator(definition, this.deps); + } } From f93859f4237c2a6777d834c6a2ec2faeda5295c1 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 28 May 2021 15:54:13 +0200 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20locato?= =?UTF-8?q?r=20service=20in=20/common=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../url_service/__tests__/locators.test.ts | 165 ++++++++++++++++++ .../common/url_service/__tests__/setup.ts | 42 +++++ .../url_service/locators/abstract_locator.ts | 43 ----- .../common/url_service/locators/index.ts | 4 +- .../common/url_service/locators/locator.ts | 69 ++++++++ ...ct_locator_client.ts => locator_client.ts} | 17 +- .../common/url_service/locators/types.ts | 8 +- .../share/common/url_service/url_service.ts | 10 +- 8 files changed, 300 insertions(+), 58 deletions(-) create mode 100644 src/plugins/share/common/url_service/__tests__/locators.test.ts create mode 100644 src/plugins/share/common/url_service/__tests__/setup.ts delete mode 100644 src/plugins/share/common/url_service/locators/abstract_locator.ts create mode 100644 src/plugins/share/common/url_service/locators/locator.ts rename src/plugins/share/common/url_service/locators/{abstract_locator_client.ts => locator_client.ts} (69%) diff --git a/src/plugins/share/common/url_service/__tests__/locators.test.ts b/src/plugins/share/common/url_service/__tests__/locators.test.ts new file mode 100644 index 0000000000000..a505587c93320 --- /dev/null +++ b/src/plugins/share/common/url_service/__tests__/locators.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { of } from 'src/plugins/kibana_utils/common'; +import { testLocator, TestLocatorState, urlServiceTestSetup } from './setup'; + +describe('locators', () => { + test('can start locators service', () => { + const { + service: { locators }, + } = urlServiceTestSetup(); + + expect(typeof locators).toBe('object'); + expect(typeof locators.create).toBe('function'); + expect(typeof locators.get).toBe('function'); + }); + + test('returns "undefined" for unregistered locator', () => { + const { + service: { locators }, + } = urlServiceTestSetup(); + + expect(locators.get(testLocator.id)).toBe(undefined); + }); + + test('can register a locator', () => { + const { + service: { locators }, + } = urlServiceTestSetup(); + + locators.create(testLocator); + expect(typeof locators.get(testLocator.id)).toBe('object'); + }); + + test('getLocation() returns KibanaLocation generated by the locator', () => { + const { + service: { locators }, + } = urlServiceTestSetup(); + + locators.create(testLocator); + + const locator = locators.get(testLocator.id); + const location = locator?.getLocation({ + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + pageNumber: 21, + showFlyout: true, + }); + + expect(location).toEqual({ + app: 'test_app', + route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=21', + state: { isFlyoutOpen: true }, + }); + }); + + describe('.navigate()', () => { + test('throws if navigation method is not implemented', async () => { + const { + service: { locators }, + } = urlServiceTestSetup(); + const locator = locators.create(testLocator); + const [, error] = await of( + locator.navigate({ + pageNumber: 1, + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + showFlyout: false, + }) + ); + + expect(error).toBeInstanceOf(Error); + expect(error.message).toBe('not implemented'); + }); + + test('navigates user when .navigate() method is called', async () => { + const { + service: { locators }, + deps, + } = urlServiceTestSetup({ + navigate: jest.fn(async () => {}), + }); + const locator = locators.create(testLocator); + const [, error] = await of( + locator.navigate({ + pageNumber: 1, + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + showFlyout: false, + }) + ); + + expect(error).toBe(undefined); + expect(deps.navigate).toHaveBeenCalledTimes(1); + expect(deps.navigate).toHaveBeenCalledWith( + { + app: 'test_app', + route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=1', + state: { + isFlyoutOpen: false, + }, + }, + { replace: false } + ); + }); + + test('can specify "replace" navigation parameter', async () => { + const { + service: { locators }, + deps, + } = urlServiceTestSetup({ + navigate: jest.fn(async () => {}), + }); + const locator = locators.create(testLocator); + + await locator.navigate( + { + pageNumber: 1, + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + showFlyout: false, + }, + { + replace: false, + } + ); + + expect(deps.navigate).toHaveBeenCalledTimes(1); + expect(deps.navigate).toHaveBeenCalledWith( + { + app: 'test_app', + route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=1', + state: { + isFlyoutOpen: false, + }, + }, + { replace: false } + ); + + await locator.navigate( + { + pageNumber: 2, + savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + showFlyout: false, + }, + { + replace: true, + } + ); + + expect(deps.navigate).toHaveBeenCalledTimes(2); + expect(deps.navigate).toHaveBeenCalledWith( + { + app: 'test_app', + route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=2', + state: { + isFlyoutOpen: false, + }, + }, + { replace: true } + ); + }); + }); +}); diff --git a/src/plugins/share/common/url_service/__tests__/setup.ts b/src/plugins/share/common/url_service/__tests__/setup.ts new file mode 100644 index 0000000000000..b86d8b638d4a0 --- /dev/null +++ b/src/plugins/share/common/url_service/__tests__/setup.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SerializableState } from 'src/plugins/kibana_utils/common'; +import { LocatorDefinition } from '../locators'; +import { UrlService, UrlServiceDependencies } from '../url_service'; + +export interface TestLocatorState extends SerializableState { + savedObjectId: string; + showFlyout: boolean; + pageNumber: number; +} + +export const testLocator: LocatorDefinition = { + id: 'TEST_LOCATOR', + getLocation: ({ savedObjectId, pageNumber, showFlyout }) => { + return { + app: 'test_app', + route: `/my-object/${savedObjectId}?page=${pageNumber}`, + state: { + isFlyoutOpen: showFlyout, + }, + }; + }, +}; + +export const urlServiceTestSetup = (partialDeps: Partial = {}) => { + const deps: UrlServiceDependencies = { + navigate: async () => { + throw new Error('not implemented'); + }, + ...partialDeps, + }; + const service = new UrlService(deps); + + return { service, deps }; +}; diff --git a/src/plugins/share/common/url_service/locators/abstract_locator.ts b/src/plugins/share/common/url_service/locators/abstract_locator.ts deleted file mode 100644 index e8a16e6e95ecb..0000000000000 --- a/src/plugins/share/common/url_service/locators/abstract_locator.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { PersistableState, SerializableState } from 'src/plugins/kibana_utils/common'; -import { LocatorDefinition, LocatorPublic, KibanaLocation } from './types'; - -export abstract class AbstractLocator

- implements PersistableState

, LocatorPublic

{ - public readonly migrations: PersistableState

['migrations']; - - constructor(public readonly definition: LocatorDefinition

) { - this.migrations = definition.migrations || {}; - } - - // PersistableState

------------------------------------------------------- - - public readonly telemetry: PersistableState

['telemetry'] = () => { - throw new Error('not implemented'); - }; - - public readonly inject: PersistableState

['inject'] = () => { - throw new Error('not implemented'); - }; - - public readonly extract: PersistableState

['extract'] = () => { - throw new Error('not implemented'); - }; - - // LocatorPublic

---------------------------------------------------------- - - public getLocation(params: P): KibanaLocation { - return this.definition.getLocation(params); - } - - public navigate(params: P): void { - throw new Error('not implemented'); - } -} diff --git a/src/plugins/share/common/url_service/locators/index.ts b/src/plugins/share/common/url_service/locators/index.ts index 3fb16071dd670..f9f87215eb4db 100644 --- a/src/plugins/share/common/url_service/locators/index.ts +++ b/src/plugins/share/common/url_service/locators/index.ts @@ -7,5 +7,5 @@ */ export * from './types'; -export * from './abstract_locator'; -export * from './abstract_locator_client'; +export * from './locator'; +export * from './locator_client'; diff --git a/src/plugins/share/common/url_service/locators/locator.ts b/src/plugins/share/common/url_service/locators/locator.ts new file mode 100644 index 0000000000000..2ede8b15a6d7f --- /dev/null +++ b/src/plugins/share/common/url_service/locators/locator.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SavedObjectReference } from 'kibana/server'; +import type { PersistableState, SerializableState } from 'src/plugins/kibana_utils/common'; +import type { + LocatorDefinition, + LocatorPublic, + KibanaLocation, + LocatorNavigationParams, +} from './types'; + +export interface LocatorDependencies { + navigate: (location: KibanaLocation, params?: LocatorNavigationParams) => Promise; +} + +export class Locator

implements PersistableState

, LocatorPublic

{ + public readonly migrations: PersistableState

['migrations']; + + constructor( + public readonly definition: LocatorDefinition

, + protected readonly deps: LocatorDependencies + ) { + this.migrations = definition.migrations || {}; + } + + // PersistableState

------------------------------------------------------- + + public readonly telemetry: PersistableState

['telemetry'] = ( + state: P, + stats: Record + ): Record => { + return this.definition.telemetry ? this.definition.telemetry(state, stats) : stats; + }; + + public readonly inject: PersistableState

['inject'] = ( + state: P, + references: SavedObjectReference[] + ): P => { + return this.definition.inject ? this.definition.inject(state, references) : state; + }; + + public readonly extract: PersistableState

['extract'] = ( + state: P + ): { state: P; references: SavedObjectReference[] } => { + return this.definition.extract ? this.definition.extract(state) : { state, references: [] }; + }; + + // LocatorPublic

---------------------------------------------------------- + + public getLocation(params: P): KibanaLocation { + return this.definition.getLocation(params); + } + + public async navigate( + params: P, + { replace = false }: LocatorNavigationParams = {} + ): Promise { + const location = this.getLocation(params); + await this.deps.navigate(location, { + replace, + }); + } +} diff --git a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts b/src/plugins/share/common/url_service/locators/locator_client.ts similarity index 69% rename from src/plugins/share/common/url_service/locators/abstract_locator_client.ts rename to src/plugins/share/common/url_service/locators/locator_client.ts index 06d4cf1b8a477..168cc02d03ff1 100644 --- a/src/plugins/share/common/url_service/locators/abstract_locator_client.ts +++ b/src/plugins/share/common/url_service/locators/locator_client.ts @@ -7,18 +7,19 @@ */ import type { SerializableState } from 'src/plugins/kibana_utils/common'; -import type { AbstractLocator } from './abstract_locator'; -import type { LocatorClient, LocatorDefinition, LocatorPublic } from './types'; +import type { LocatorDependencies } from './locator'; +import type { LocatorDefinition, LocatorPublic, ILocatorClient } from './types'; +import { Locator } from './locator'; -export abstract class AbstractLocatorClient implements Pick { +export type LocatorClientDependencies = LocatorDependencies; + +export class LocatorClient implements ILocatorClient { /** * Collection of registered locators. */ - protected locators: Map> = new Map(); + protected locators: Map> = new Map(); - protected abstract createLocator

( - definition: LocatorDefinition

- ): AbstractLocator

; + constructor(protected readonly deps: LocatorClientDependencies) {} /** * Creates and register a URL locator. @@ -27,7 +28,7 @@ export abstract class AbstractLocatorClient implements Pick(definition: LocatorDefinition

): LocatorPublic

{ - const locator = this.createLocator

(definition); + const locator = new Locator

(definition, this.deps); this.locators.set(definition.id, locator); diff --git a/src/plugins/share/common/url_service/locators/types.ts b/src/plugins/share/common/url_service/locators/types.ts index a4d2adf9fe2e2..2319f80f8227f 100644 --- a/src/plugins/share/common/url_service/locators/types.ts +++ b/src/plugins/share/common/url_service/locators/types.ts @@ -11,7 +11,7 @@ import { PersistableState, SerializableState } from 'src/plugins/kibana_utils/co /** * URL locator registry. */ -export interface LocatorClient { +export interface ILocatorClient { /** * Create and register a new locator. * @@ -61,7 +61,11 @@ export interface LocatorPublic

{ * location generated by this locator. This method is available only on the * browser. */ - navigate(params: P): void; + navigate(params: P, navigationParams?: LocatorNavigationParams): Promise; +} + +export interface LocatorNavigationParams { + replace?: boolean; } /** diff --git a/src/plugins/share/common/url_service/url_service.ts b/src/plugins/share/common/url_service/url_service.ts index cca6e901ed9cc..0c3a0aabb750b 100644 --- a/src/plugins/share/common/url_service/url_service.ts +++ b/src/plugins/share/common/url_service/url_service.ts @@ -6,14 +6,18 @@ * Side Public License, v 1. */ -import { LocatorClient } from './locators'; +import { LocatorClient, LocatorClientDependencies } from './locators'; + +export type UrlServiceDependencies = LocatorClientDependencies; /** * Common URL Service client interface for server-side and client-side. */ -export interface UrlService { +export class UrlService { /** * Client to work with locators. */ - locators: LocatorClient; + locators: LocatorClient = new LocatorClient(this.deps); + + constructor(protected readonly deps: UrlServiceDependencies) {} } From a3f0ecd3ef43e9023cd6a375ed5fa2a97c1effb2 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 28 May 2021 17:04:32 +0200 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20expose=20locators?= =?UTF-8?q?=20client=20on=20browser=20and=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/share/public/plugin.ts | 22 +++++--- .../url_service/__tests__/locators.test.ts | 51 ------------------- .../public/url_service/__tests__/setup.ts | 35 ------------- .../public/url_service/browser_url_service.ts | 19 ------- src/plugins/share/public/url_service/index.ts | 10 ---- .../url_service/locators/browser_locator.ts | 33 ------------ .../locators/browser_locator_client.ts | 25 --------- .../public/url_service/locators/index.ts | 10 ---- src/plugins/share/server/plugin.ts | 29 ++++++++++- 9 files changed, 44 insertions(+), 190 deletions(-) delete mode 100644 src/plugins/share/public/url_service/__tests__/locators.test.ts delete mode 100644 src/plugins/share/public/url_service/__tests__/setup.ts delete mode 100644 src/plugins/share/public/url_service/browser_url_service.ts delete mode 100644 src/plugins/share/public/url_service/index.ts delete mode 100644 src/plugins/share/public/url_service/locators/browser_locator.ts delete mode 100644 src/plugins/share/public/url_service/locators/browser_locator_client.ts delete mode 100644 src/plugins/share/public/url_service/locators/index.ts diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts index 890028eb9bb01..64f6d757de773 100644 --- a/src/plugins/share/public/plugin.ts +++ b/src/plugins/share/public/plugin.ts @@ -19,7 +19,6 @@ import { UrlGeneratorsStart, } from './url_generators/url_generator_service'; import { UrlService } from '../common/url_service'; -import { BrowserUrlService } from './url_service'; export interface ShareSetupDependencies { securityOss?: SecurityOssPluginSetup; @@ -38,23 +37,33 @@ export type SharePluginSetup = ShareMenuRegistrySetup & { /** @public */ export type SharePluginStart = ShareMenuManagerStart & { urlGenerators: UrlGeneratorsStart; + url: UrlService; }; export class SharePlugin implements Plugin { private readonly shareMenuRegistry = new ShareMenuRegistry(); private readonly shareContextMenu = new ShareMenuManager(); private readonly urlGeneratorsService = new UrlGeneratorsService(); + private url?: UrlService; public setup(core: CoreSetup, plugins: ShareSetupDependencies): SharePluginSetup { core.application.register(createShortUrlRedirectApp(core, window.location)); + + this.url = new UrlService({ + navigate: async (location, { replace = false } = {}) => { + const [start] = await core.getStartServices(); + await start.application.navigateToApp(location.app, { + path: location.route, + state: location.state, + replace, + }); + }, + }); + return { ...this.shareMenuRegistry.setup(), urlGenerators: this.urlGeneratorsService.setup(core), - url: new BrowserUrlService({ - navigate: async () => { - throw new Error('not implemented'); - }, - }), + url: this.url, }; } @@ -66,6 +75,7 @@ export class SharePlugin implements Plugin { plugins.securityOss?.anonymousAccess ), urlGenerators: this.urlGeneratorsService.start(core), + url: this.url!, }; } } diff --git a/src/plugins/share/public/url_service/__tests__/locators.test.ts b/src/plugins/share/public/url_service/__tests__/locators.test.ts deleted file mode 100644 index 7cc560c71f113..0000000000000 --- a/src/plugins/share/public/url_service/__tests__/locators.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { browserTestLocator, BrowserTestLocatorState, urlServiceTestSetup } from './setup'; - -describe('locators', () => { - test('can start locators service', () => { - const { locators } = urlServiceTestSetup(); - - expect(typeof locators).toBe('object'); - expect(typeof locators.create).toBe('function'); - expect(typeof locators.get).toBe('function'); - }); - - test('returns "undefined" for unregistered locator', () => { - const { locators } = urlServiceTestSetup(); - - expect(locators.get(browserTestLocator.id)).toBe(undefined); - }); - - test('can register a locator', () => { - const { locators } = urlServiceTestSetup(); - - locators.create(browserTestLocator); - expect(typeof locators.get(browserTestLocator.id)).toBe('object'); - }); - - test('getLocation() returns KibanaLocation generated by the locator', () => { - const { locators } = urlServiceTestSetup(); - - locators.create(browserTestLocator); - - const locator = locators.get(browserTestLocator.id); - const location = locator?.getLocation({ - savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', - pageNumber: 21, - showFlyout: true, - }); - - expect(location).toEqual({ - app: 'test_app', - route: '/my-object/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?page=21', - state: { isFlyoutOpen: true }, - }); - }); -}); diff --git a/src/plugins/share/public/url_service/__tests__/setup.ts b/src/plugins/share/public/url_service/__tests__/setup.ts deleted file mode 100644 index b9c7ed8c938d7..0000000000000 --- a/src/plugins/share/public/url_service/__tests__/setup.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { SerializableState } from 'src/plugins/kibana_utils/common'; -import type { LocatorDefinition, UrlService } from 'src/plugins/share/common/url_service'; -import { BrowserUrlService } from '../browser_url_service'; - -export interface BrowserTestLocatorState extends SerializableState { - savedObjectId: string; - showFlyout: boolean; - pageNumber: number; -} - -export const browserTestLocator: LocatorDefinition = { - id: 'BROWSER_TEST_LOCATOR', - getLocation: ({ savedObjectId, pageNumber, showFlyout }) => { - return { - app: 'test_app', - route: `/my-object/${savedObjectId}?page=${pageNumber}`, - state: { - isFlyoutOpen: showFlyout, - }, - }; - }, -}; - -export const urlServiceTestSetup = (): UrlService => { - const urlService = new BrowserUrlService(); - return urlService; -}; diff --git a/src/plugins/share/public/url_service/browser_url_service.ts b/src/plugins/share/public/url_service/browser_url_service.ts deleted file mode 100644 index e51cbd63263c9..0000000000000 --- a/src/plugins/share/public/url_service/browser_url_service.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { UrlService } from '../../common/url_service'; -import type { BrowserLocatorClientDependencies } from './locators'; -import { BrowserLocatorsClient } from './locators'; - -export type BrowserUrlServiceDependencies = BrowserLocatorClientDependencies; - -export class BrowserUrlService implements UrlService { - public readonly locators = new BrowserLocatorsClient(this.deps); - - constructor(protected readonly deps: BrowserUrlServiceDependencies) {} -} diff --git a/src/plugins/share/public/url_service/index.ts b/src/plugins/share/public/url_service/index.ts deleted file mode 100644 index 5b64711790b82..0000000000000 --- a/src/plugins/share/public/url_service/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export * from './browser_url_service'; -export type { BrowserLocator, BrowserLocatorsClient } from './locators'; diff --git a/src/plugins/share/public/url_service/locators/browser_locator.ts b/src/plugins/share/public/url_service/locators/browser_locator.ts deleted file mode 100644 index 0defa59687c4d..0000000000000 --- a/src/plugins/share/public/url_service/locators/browser_locator.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { SerializableState } from 'src/plugins/kibana_utils/common'; -import type { KibanaLocation, LocatorDefinition } from '../../../common/url_service'; -import { AbstractLocator } from '../../../common/url_service'; - -export interface BrowserLocatorDependencies { - navigate: (location: KibanaLocation, params?: NavigationParams) => Promise; -} - -export interface NavigationParams { - replace?: boolean; -} - -export class BrowserLocator

extends AbstractLocator

{ - constructor( - definition: LocatorDefinition

, - protected readonly deps: BrowserLocatorDependencies - ) { - super(definition); - } - - public async navigate(params: P, navigationParams?: NavigationParams): Promise { - const location = this.getLocation(params); - await this.deps.navigate(location, navigationParams); - } -} diff --git a/src/plugins/share/public/url_service/locators/browser_locator_client.ts b/src/plugins/share/public/url_service/locators/browser_locator_client.ts deleted file mode 100644 index 596e6eaf1fc97..0000000000000 --- a/src/plugins/share/public/url_service/locators/browser_locator_client.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { SerializableState } from 'src/plugins/kibana_utils/common'; -import type { BrowserLocatorDependencies } from './browser_locator'; -import type { LocatorDefinition } from '../../../common/url_service'; -import { AbstractLocatorClient } from '../../../common/url_service'; -import { BrowserLocator } from './browser_locator'; - -export type BrowserLocatorClientDependencies = BrowserLocatorDependencies; - -export class BrowserLocatorsClient extends AbstractLocatorClient { - constructor(protected readonly deps: BrowserLocatorClientDependencies) { - super(); - } - - protected createLocator

(definition: LocatorDefinition

) { - return new BrowserLocator(definition, this.deps); - } -} diff --git a/src/plugins/share/public/url_service/locators/index.ts b/src/plugins/share/public/url_service/locators/index.ts deleted file mode 100644 index ef005a094b044..0000000000000 --- a/src/plugins/share/public/url_service/locators/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -export * from './browser_locator'; -export * from './browser_locator_client'; diff --git a/src/plugins/share/server/plugin.ts b/src/plugins/share/server/plugin.ts index 744a4148215c3..688e657fe7a11 100644 --- a/src/plugins/share/server/plugin.ts +++ b/src/plugins/share/server/plugin.ts @@ -12,11 +12,30 @@ import { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; import { createRoutes } from './routes/create_routes'; import { url } from './saved_objects'; import { CSV_SEPARATOR_SETTING, CSV_QUOTE_VALUES_SETTING } from '../common/constants'; +import { UrlService } from '../common/url_service'; + +/** @public */ +export interface SharePluginSetup { + url: UrlService; +} + +/** @public */ +export interface SharePluginStart { + url: UrlService; +} + +export class SharePlugin implements Plugin { + private url?: UrlService; -export class SharePlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup) { + this.url = new UrlService({ + navigate: async () => { + throw new Error('Locator .navigate() works only in browser.'); + }, + }); + createRoutes(core, this.initializerContext.logger.get()); core.savedObjects.registerType(url); core.uiSettings.register({ @@ -41,10 +60,18 @@ export class SharePlugin implements Plugin { schema: schema.boolean(), }, }); + + return { + url: this.url, + }; } public start() { this.initializerContext.logger.get().debug('Starting plugin'); + + return { + url: this.url!, + }; } public stop() { From 29931272e9ac961c91c5a47bf2a45fc9c63c8c3b Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 31 May 2021 11:52:44 +0200 Subject: [PATCH 10/13] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20make=20locator?= =?UTF-8?q?s=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../share/common/url_service/__tests__/locators.test.ts | 4 ++-- src/plugins/share/common/url_service/locators/locator.ts | 6 +++--- src/plugins/share/common/url_service/locators/types.ts | 4 ++-- src/plugins/share/server/plugin.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/share/common/url_service/__tests__/locators.test.ts b/src/plugins/share/common/url_service/__tests__/locators.test.ts index a505587c93320..45d727df7de48 100644 --- a/src/plugins/share/common/url_service/__tests__/locators.test.ts +++ b/src/plugins/share/common/url_service/__tests__/locators.test.ts @@ -37,7 +37,7 @@ describe('locators', () => { expect(typeof locators.get(testLocator.id)).toBe('object'); }); - test('getLocation() returns KibanaLocation generated by the locator', () => { + test('getLocation() returns KibanaLocation generated by the locator', async () => { const { service: { locators }, } = urlServiceTestSetup(); @@ -45,7 +45,7 @@ describe('locators', () => { locators.create(testLocator); const locator = locators.get(testLocator.id); - const location = locator?.getLocation({ + const location = await locator?.getLocation({ savedObjectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', pageNumber: 21, showFlyout: true, diff --git a/src/plugins/share/common/url_service/locators/locator.ts b/src/plugins/share/common/url_service/locators/locator.ts index 2ede8b15a6d7f..68c3b05a7f411 100644 --- a/src/plugins/share/common/url_service/locators/locator.ts +++ b/src/plugins/share/common/url_service/locators/locator.ts @@ -53,15 +53,15 @@ export class Locator

implements PersistableState

// LocatorPublic

---------------------------------------------------------- - public getLocation(params: P): KibanaLocation { - return this.definition.getLocation(params); + public async getLocation(params: P): Promise { + return await this.definition.getLocation(params); } public async navigate( params: P, { replace = false }: LocatorNavigationParams = {} ): Promise { - const location = this.getLocation(params); + const location = await this.getLocation(params); await this.deps.navigate(location, { replace, }); diff --git a/src/plugins/share/common/url_service/locators/types.ts b/src/plugins/share/common/url_service/locators/types.ts index 2319f80f8227f..d811ae0fd4aa2 100644 --- a/src/plugins/share/common/url_service/locators/types.ts +++ b/src/plugins/share/common/url_service/locators/types.ts @@ -43,7 +43,7 @@ export interface LocatorDefinition

* * @param params Parameters from which to generate a Kibana location. */ - getLocation(params: P): KibanaLocation; + getLocation(params: P): Promise; } /** @@ -54,7 +54,7 @@ export interface LocatorPublic

{ * Returns a relative URL to the client-side redirect endpoint using this * locator. (This method is necessary for compatibility with URL generators.) */ - getLocation(params: P): KibanaLocation; + getLocation(params: P): Promise; /** * Navigate using the `core.application.navigateToApp()` method to a Kibana diff --git a/src/plugins/share/server/plugin.ts b/src/plugins/share/server/plugin.ts index 688e657fe7a11..6e3c68935f77b 100644 --- a/src/plugins/share/server/plugin.ts +++ b/src/plugins/share/server/plugin.ts @@ -32,7 +32,7 @@ export class SharePlugin implements Plugin { public setup(core: CoreSetup) { this.url = new UrlService({ navigate: async () => { - throw new Error('Locator .navigate() works only in browser.'); + throw new Error('Locator .navigate() does not work on server.'); }, }); From 9d5cb9de2a5c8325ee5445cea6a4b5c7c6eb5b8b Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 1 Jun 2021 13:53:01 +0200 Subject: [PATCH 11/13] =?UTF-8?q?chore:=20=F0=9F=A4=96=20add=20deprecation?= =?UTF-8?q?=20notice=20to=20URL=20generators?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/share/public/plugin.ts | 18 ++++++++++++++++++ .../url_generators/url_generator_service.ts | 10 ++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/plugins/share/public/plugin.ts b/src/plugins/share/public/plugin.ts index 64f6d757de773..eb7c46cdaef86 100644 --- a/src/plugins/share/public/plugin.ts +++ b/src/plugins/share/public/plugin.ts @@ -30,13 +30,31 @@ export interface ShareStartDependencies { /** @public */ export type SharePluginSetup = ShareMenuRegistrySetup & { + /** + * @deprecated + * + * URL Generators are deprecated use UrlService instead. + */ urlGenerators: UrlGeneratorsSetup; + + /** + * Utilities to work with URL locators and short URLs. + */ url: UrlService; }; /** @public */ export type SharePluginStart = ShareMenuManagerStart & { + /** + * @deprecated + * + * URL Generators are deprecated use UrlService instead. + */ urlGenerators: UrlGeneratorsStart; + + /** + * Utilities to work with URL locators and short URLs. + */ url: UrlService; }; diff --git a/src/plugins/share/public/url_generators/url_generator_service.ts b/src/plugins/share/public/url_generators/url_generator_service.ts index 982f0692102df..5a8e7a1b5c17a 100644 --- a/src/plugins/share/public/url_generators/url_generator_service.ts +++ b/src/plugins/share/public/url_generators/url_generator_service.ts @@ -13,10 +13,20 @@ import { UrlGeneratorInternal } from './url_generator_internal'; import { UrlGeneratorContract } from './url_generator_contract'; export interface UrlGeneratorsStart { + /** + * @deprecated + * + * URL Generators are deprecated, use URL locators in UrlService instead. + */ getUrlGenerator: (urlGeneratorId: T) => UrlGeneratorContract; } export interface UrlGeneratorsSetup { + /** + * @deprecated + * + * URL Generators are deprecated, use URL locators in UrlService instead. + */ registerUrlGenerator: ( generator: UrlGeneratorsDefinition ) => UrlGeneratorContract; From 5361362e837cd0ad8784b16a839d7ea8c13b093c Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 1 Jun 2021 13:56:44 +0200 Subject: [PATCH 12/13] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20add=20deprec?= =?UTF-8?q?ation=20notice=20to=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/share/public/url_generators/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/share/public/url_generators/README.md b/src/plugins/share/public/url_generators/README.md index 39ee5f2901e91..f948354aad959 100644 --- a/src/plugins/share/public/url_generators/README.md +++ b/src/plugins/share/public/url_generators/README.md @@ -1,3 +1,9 @@ +# URL Generators are deprecated + +__Below is documentation of URL Generators, which are now deprecated and will be removed in favor of URL locators in 7.14.__ + +--- + ## URL Generator Services Developers who maintain pages in Kibana that other developers may want to link to From fefd1092d32793a4169adf9bdd0b7f14ec1b08ed Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 1 Jun 2021 15:13:31 +0200 Subject: [PATCH 13/13] =?UTF-8?q?test:=20=F0=9F=92=8D=20make=20test=20loca?= =?UTF-8?q?tor=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/share/common/url_service/__tests__/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/share/common/url_service/__tests__/setup.ts b/src/plugins/share/common/url_service/__tests__/setup.ts index b86d8b638d4a0..ad13bb8d8d216 100644 --- a/src/plugins/share/common/url_service/__tests__/setup.ts +++ b/src/plugins/share/common/url_service/__tests__/setup.ts @@ -18,7 +18,7 @@ export interface TestLocatorState extends SerializableState { export const testLocator: LocatorDefinition = { id: 'TEST_LOCATOR', - getLocation: ({ savedObjectId, pageNumber, showFlyout }) => { + getLocation: async ({ savedObjectId, pageNumber, showFlyout }) => { return { app: 'test_app', route: `/my-object/${savedObjectId}?page=${pageNumber}`,