diff --git a/docs/development/core/public/kibana-plugin-public.app.md b/docs/development/core/public/kibana-plugin-public.app.md
index faea94c467726..f31db3674f5ba 100644
--- a/docs/development/core/public/kibana-plugin-public.app.md
+++ b/docs/development/core/public/kibana-plugin-public.app.md
@@ -9,7 +9,7 @@ Extension of [common app properties](./kibana-plugin-public.appbase.md) with the
Signature:
```typescript
-export interface App extends AppBase
+export interface App extends AppBase
```
## Properties
@@ -18,5 +18,5 @@ export interface App extends AppBase
| --- | --- | --- |
| [appRoute](./kibana-plugin-public.app.approute.md) | string | Override the application's routing path from /app/${id}. Must be unique across registered applications. Should not include the base path from HTTP. |
| [chromeless](./kibana-plugin-public.app.chromeless.md) | boolean | Hide the UI chrome when the application is mounted. Defaults to false. Takes precedence over chrome service visibility settings. |
-| [mount](./kibana-plugin-public.app.mount.md) | AppMount | AppMountDeprecated | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). |
+| [mount](./kibana-plugin-public.app.mount.md) | AppMount<HistoryLocationState> | AppMountDeprecated<HistoryLocationState> | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). |
diff --git a/docs/development/core/public/kibana-plugin-public.app.mount.md b/docs/development/core/public/kibana-plugin-public.app.mount.md
index 2af5f0277759a..4829307ff267c 100644
--- a/docs/development/core/public/kibana-plugin-public.app.mount.md
+++ b/docs/development/core/public/kibana-plugin-public.app.mount.md
@@ -9,7 +9,7 @@ A mount function called when the user navigates to this app's route. May have si
Signature:
```typescript
-mount: AppMount | AppMountDeprecated;
+mount: AppMount | AppMountDeprecated;
```
## Remarks
diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md
index 5c6c7cd252b0a..27c3e28c05a0d 100644
--- a/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md
+++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md
@@ -9,14 +9,14 @@ Register an mountable application to the system.
Signature:
```typescript
-register(app: App): void;
+register(app: App): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| app | App | an [App](./kibana-plugin-public.app.md) |
+| app | App<HistoryLocationState> | an [App](./kibana-plugin-public.app.md) |
Returns:
diff --git a/docs/development/core/public/kibana-plugin-public.appmount.md b/docs/development/core/public/kibana-plugin-public.appmount.md
index 84a52b09a119c..a001b1f75c99e 100644
--- a/docs/development/core/public/kibana-plugin-public.appmount.md
+++ b/docs/development/core/public/kibana-plugin-public.appmount.md
@@ -9,5 +9,5 @@ A mount function called when the user navigates to this app's route.
Signature:
```typescript
-export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise;
+export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise;
```
diff --git a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md
index 8c8114182b60f..2bd2e956124c0 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md
@@ -13,7 +13,7 @@ A mount function called when the user navigates to this app's route.
Signature:
```typescript
-export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
+export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise;
```
## Remarks
diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md
index 041d976aa42a2..beedda98d8f4d 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.appbasepath.md
@@ -4,6 +4,11 @@
## AppMountParameters.appBasePath property
+> Warning: This API is now obsolete.
+>
+> Use [AppMountParameters.history](./kibana-plugin-public.appmountparameters.history.md) instead.
+>
+
The route path for configuring navigation to the application. This string should not include the base path from HTTP.
Signature:
@@ -39,10 +44,10 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
-import { CoreStart, AppMountParams } from 'src/core/public';
+import { CoreStart, AppMountParameters } from 'src/core/public';
import { MyPluginDepsStart } from './plugin';
-export renderApp = ({ appBasePath, element }: AppMountParams) => {
+export renderApp = ({ appBasePath, element }: AppMountParameters) => {
ReactDOM.render(
// pass `appBasePath` to `basename`
diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md
new file mode 100644
index 0000000000000..9a3fa1a1bb48a
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.history.md
@@ -0,0 +1,58 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMountParameters](./kibana-plugin-public.appmountparameters.md) > [history](./kibana-plugin-public.appmountparameters.history.md)
+
+## AppMountParameters.history property
+
+A scoped history instance for your application. Should be used to wire up your applications Router.
+
+Signature:
+
+```typescript
+history: ScopedHistory;
+```
+
+## Example
+
+How to configure react-router with a base path:
+
+```ts
+// inside your plugin's setup function
+export class MyPlugin implements Plugin {
+ setup({ application }) {
+ application.register({
+ id: 'my-app',
+ appRoute: '/my-app',
+ async mount(params) {
+ const { renderApp } = await import('./application');
+ return renderApp(params);
+ },
+ });
+ }
+}
+
+```
+
+```ts
+// application.tsx
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { Router, Route } from 'react-router-dom';
+
+import { CoreStart, AppMountParameters } from 'src/core/public';
+import { MyPluginDepsStart } from './plugin';
+
+export renderApp = ({ element, history }: AppMountParameters) => {
+ ReactDOM.render(
+ // pass `appBasePath` to `basename`
+
+
+ ,
+ element
+ );
+
+ return () => ReactDOM.unmountComponentAtNode(element);
+}
+
+```
+
diff --git a/docs/development/core/public/kibana-plugin-public.appmountparameters.md b/docs/development/core/public/kibana-plugin-public.appmountparameters.md
index c21889c28bda4..e652379fc3034 100644
--- a/docs/development/core/public/kibana-plugin-public.appmountparameters.md
+++ b/docs/development/core/public/kibana-plugin-public.appmountparameters.md
@@ -8,7 +8,7 @@
Signature:
```typescript
-export interface AppMountParameters
+export interface AppMountParameters
```
## Properties
@@ -17,5 +17,6 @@ export interface AppMountParameters
| --- | --- | --- |
| [appBasePath](./kibana-plugin-public.appmountparameters.appbasepath.md) | string | The route path for configuring navigation to the application. This string should not include the base path from HTTP. |
| [element](./kibana-plugin-public.appmountparameters.element.md) | HTMLElement | The container element to render the application into. |
+| [history](./kibana-plugin-public.appmountparameters.history.md) | ScopedHistory<HistoryLocationState> | A scoped history instance for your application. Should be used to wire up your applications Router. |
| [onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md) | (handler: AppLeaveHandler) => void | A function that can be used to register a handler that will be called when the user is leaving the current application, allowing to prompt a confirmation message before actually changing the page.This will be called either when the user goes to another application, or when trying to close the tab or manually changing the url. |
diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md
index 95a4327728139..79bdb11b80fa4 100644
--- a/docs/development/core/public/kibana-plugin-public.md
+++ b/docs/development/core/public/kibana-plugin-public.md
@@ -15,6 +15,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| Class | Description |
| --- | --- |
| [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state. The client-side SavedObjectsClient is a thin convenience library around the SavedObjects HTTP API for interacting with Saved Objects. |
+| [ScopedHistory](./kibana-plugin-public.scopedhistory.md) | A wrapper around a History instance that is scoped to a particular base path of the history stack. Behaves similarly to the basename option except that this wrapper hides any history stack entries from outside the scope of this base path.This wrapper also allows Core and Plugins to share a single underlying global History instance without exposing the history of other applications.The [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) method is particularly useful for applications that contain any number of "sub-apps" which should not have access to the main application's history or basePath. |
| [SimpleSavedObject](./kibana-plugin-public.simplesavedobject.md) | This class is a very simple wrapper for SavedObjects loaded from the server with the [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md).It provides basic functionality for creating/saving/deleting saved objects, but doesn't include any type-specific implementations. |
| [ToastsApi](./kibana-plugin-public.toastsapi.md) | Methods for adding and removing global toast messages. |
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md b/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md
new file mode 100644
index 0000000000000..d21c908890b6b
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory._constructor_.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [(constructor)](./kibana-plugin-public.scopedhistory._constructor_.md)
+
+## ScopedHistory.(constructor)
+
+Constructs a new instance of the `ScopedHistory` class
+
+Signature:
+
+```typescript
+constructor(parentHistory: History, basePath: string);
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| parentHistory | History | |
+| basePath | string | |
+
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md
new file mode 100644
index 0000000000000..c3b52b9041871
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.action.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [action](./kibana-plugin-public.scopedhistory.action.md)
+
+## ScopedHistory.action property
+
+The last action dispatched on the history stack.
+
+Signature:
+
+```typescript
+get action(): Action;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md
new file mode 100644
index 0000000000000..b6c5da58d4684
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.block.md
@@ -0,0 +1,18 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [block](./kibana-plugin-public.scopedhistory.block.md)
+
+## ScopedHistory.block property
+
+Not supported. Use [AppMountParameters.onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md).
+
+Signature:
+
+```typescript
+block: (prompt?: string | boolean | History.TransitionPromptHook | undefined) => UnregisterCallback;
+```
+
+## Remarks
+
+We prefer that applications use the `onAppLeave` API because it supports a more graceful experience that prefers a modal when possible, falling back to a confirm dialog box in the beforeunload case.
+
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md
new file mode 100644
index 0000000000000..6bbd78dc9b3c9
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.createhref.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [createHref](./kibana-plugin-public.scopedhistory.createhref.md)
+
+## ScopedHistory.createHref property
+
+Creates an href (string) to the location.
+
+Signature:
+
+```typescript
+createHref: (location: LocationDescriptorObject) => string;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md
new file mode 100644
index 0000000000000..045289c98e4ee
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.createsubhistory.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md)
+
+## ScopedHistory.createSubHistory property
+
+Creates a `ScopedHistory` for a subpath of this `ScopedHistory`. Useful for applications that may have sub-apps that do not need access to the containing application's history.
+
+Signature:
+
+```typescript
+createSubHistory: (basePath: string) => ScopedHistory;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md
new file mode 100644
index 0000000000000..b9d124d06a109
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.go.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [go](./kibana-plugin-public.scopedhistory.go.md)
+
+## ScopedHistory.go property
+
+Send the user forward or backwards in the history stack.
+
+Signature:
+
+```typescript
+go: (n: number) => void;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md
new file mode 100644
index 0000000000000..8f1d4b25ebcbf
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.goback.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [goBack](./kibana-plugin-public.scopedhistory.goback.md)
+
+## ScopedHistory.goBack property
+
+Send the user one location back in the history stack. Equivalent to calling [ScopedHistory.go(-1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available backwards, this is a no-op.
+
+Signature:
+
+```typescript
+goBack: () => void;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md
new file mode 100644
index 0000000000000..587d5035bb5b5
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.goforward.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [goForward](./kibana-plugin-public.scopedhistory.goforward.md)
+
+## ScopedHistory.goForward property
+
+Send the user one location forward in the history stack. Equivalent to calling [ScopedHistory.go(1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available forwards, this is a no-op.
+
+Signature:
+
+```typescript
+goForward: () => void;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md
new file mode 100644
index 0000000000000..8a8d6accc1fbc
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.length.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [length](./kibana-plugin-public.scopedhistory.length.md)
+
+## ScopedHistory.length property
+
+The number of entries in the history stack, including all entries forwards and backwards from the current location.
+
+Signature:
+
+```typescript
+get length(): number;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md
new file mode 100644
index 0000000000000..a0693e5a0428d
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.listen.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [listen](./kibana-plugin-public.scopedhistory.listen.md)
+
+## ScopedHistory.listen property
+
+Adds a listener for location updates.
+
+Signature:
+
+```typescript
+listen: (listener: (location: Location, action: Action) => void) => UnregisterCallback;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md
new file mode 100644
index 0000000000000..c40f73333ec7d
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.location.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [location](./kibana-plugin-public.scopedhistory.location.md)
+
+## ScopedHistory.location property
+
+The current location of the history stack.
+
+Signature:
+
+```typescript
+get location(): Location;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.md
new file mode 100644
index 0000000000000..5b429c1e6ec9e
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.md
@@ -0,0 +1,41 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md)
+
+## ScopedHistory class
+
+A wrapper around a `History` instance that is scoped to a particular base path of the history stack. Behaves similarly to the `basename` option except that this wrapper hides any history stack entries from outside the scope of this base path.
+
+This wrapper also allows Core and Plugins to share a single underlying global `History` instance without exposing the history of other applications.
+
+The [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) method is particularly useful for applications that contain any number of "sub-apps" which should not have access to the main application's history or basePath.
+
+Signature:
+
+```typescript
+export declare class ScopedHistory implements History
+```
+
+## Constructors
+
+| Constructor | Modifiers | Description |
+| --- | --- | --- |
+| [(constructor)(parentHistory, basePath)](./kibana-plugin-public.scopedhistory._constructor_.md) | | Constructs a new instance of the ScopedHistory class |
+
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [action](./kibana-plugin-public.scopedhistory.action.md) | | Action | The last action dispatched on the history stack. |
+| [block](./kibana-plugin-public.scopedhistory.block.md) | | (prompt?: string | boolean | History.TransitionPromptHook<HistoryLocationState> | undefined) => UnregisterCallback | Not supported. Use [AppMountParameters.onAppLeave](./kibana-plugin-public.appmountparameters.onappleave.md). |
+| [createHref](./kibana-plugin-public.scopedhistory.createhref.md) | | (location: LocationDescriptorObject<HistoryLocationState>) => string | Creates an href (string) to the location. |
+| [createSubHistory](./kibana-plugin-public.scopedhistory.createsubhistory.md) | | <SubHistoryLocationState = unknown>(basePath: string) => ScopedHistory<SubHistoryLocationState> | Creates a ScopedHistory for a subpath of this ScopedHistory. Useful for applications that may have sub-apps that do not need access to the containing application's history. |
+| [go](./kibana-plugin-public.scopedhistory.go.md) | | (n: number) => void | Send the user forward or backwards in the history stack. |
+| [goBack](./kibana-plugin-public.scopedhistory.goback.md) | | () => void | Send the user one location back in the history stack. Equivalent to calling [ScopedHistory.go(-1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available backwards, this is a no-op. |
+| [goForward](./kibana-plugin-public.scopedhistory.goforward.md) | | () => void | Send the user one location forward in the history stack. Equivalent to calling [ScopedHistory.go(1)](./kibana-plugin-public.scopedhistory.go.md). If no more entries are available forwards, this is a no-op. |
+| [length](./kibana-plugin-public.scopedhistory.length.md) | | number | The number of entries in the history stack, including all entries forwards and backwards from the current location. |
+| [listen](./kibana-plugin-public.scopedhistory.listen.md) | | (listener: (location: Location<HistoryLocationState>, action: Action) => void) => UnregisterCallback | Adds a listener for location updates. |
+| [location](./kibana-plugin-public.scopedhistory.location.md) | | Location<HistoryLocationState> | The current location of the history stack. |
+| [push](./kibana-plugin-public.scopedhistory.push.md) | | (pathOrLocation: string | LocationDescriptorObject<HistoryLocationState>, state?: HistoryLocationState | undefined) => void | Pushes a new location onto the history stack. If there are forward entries in the stack, they will be removed. |
+| [replace](./kibana-plugin-public.scopedhistory.replace.md) | | (pathOrLocation: string | LocationDescriptorObject<HistoryLocationState>, state?: HistoryLocationState | undefined) => void | Replaces the current location in the history stack. Does not remove forward or backward entries. |
+
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md
new file mode 100644
index 0000000000000..0d8d635d0f189
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.push.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [push](./kibana-plugin-public.scopedhistory.push.md)
+
+## ScopedHistory.push property
+
+Pushes a new location onto the history stack. If there are forward entries in the stack, they will be removed.
+
+Signature:
+
+```typescript
+push: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md b/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md
new file mode 100644
index 0000000000000..f9c1171d4217e
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.scopedhistory.replace.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ScopedHistory](./kibana-plugin-public.scopedhistory.md) > [replace](./kibana-plugin-public.scopedhistory.replace.md)
+
+## ScopedHistory.replace property
+
+Replaces the current location in the history stack. Does not remove forward or backward entries.
+
+Signature:
+
+```typescript
+replace: (pathOrLocation: string | LocationDescriptorObject, state?: HistoryLocationState | undefined) => void;
+```
diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts
index 5487ca53170dd..c25918c6b7328 100644
--- a/src/core/public/application/application_service.test.ts
+++ b/src/core/public/application/application_service.test.ts
@@ -588,6 +588,16 @@ describe('#start()', () => {
expect(getUrlForApp('app1', { path: 'deep/link///' })).toBe('/base-path/app/app1/deep/link');
});
+ it('does not append trailing slash if hash is provided in path parameter', async () => {
+ service.setup(setupDeps);
+ const { getUrlForApp } = await service.start(startDeps);
+
+ expect(getUrlForApp('app1', { path: '#basic-hash' })).toBe('/base-path/app/app1#basic-hash');
+ expect(getUrlForApp('app1', { path: '#/hash/router/path' })).toBe(
+ '/base-path/app/app1#/hash/router/path'
+ );
+ });
+
it('creates absolute URLs when `absolute` parameter is true', async () => {
service.setup(setupDeps);
const { getUrlForApp } = await service.start(startDeps);
@@ -646,6 +656,26 @@ describe('#start()', () => {
);
});
+ it('appends a path if specified with hash', async () => {
+ const { register } = service.setup(setupDeps);
+
+ register(Symbol(), createApp({ id: 'app2', appRoute: '/custom/path' }));
+
+ const { navigateToApp } = await service.start(startDeps);
+
+ await navigateToApp('myTestApp', { path: '#basic-hash' });
+ expect(MockHistory.push).toHaveBeenCalledWith('/app/myTestApp#basic-hash', undefined);
+
+ await navigateToApp('myTestApp', { path: '#/hash/router/path' });
+ expect(MockHistory.push).toHaveBeenCalledWith('/app/myTestApp#/hash/router/path', undefined);
+
+ await navigateToApp('app2', { path: '#basic-hash' });
+ expect(MockHistory.push).toHaveBeenCalledWith('/custom/path#basic-hash', undefined);
+
+ await navigateToApp('app2', { path: '#/hash/router/path' });
+ expect(MockHistory.push).toHaveBeenCalledWith('/custom/path#/hash/router/path', undefined);
+ });
+
it('includes state if specified', async () => {
const { register } = service.setup(setupDeps);
diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx
index 77f06e316c0aa..1c9492d81c7f6 100644
--- a/src/core/public/application/application_service.tsx
+++ b/src/core/public/application/application_service.tsx
@@ -76,10 +76,19 @@ function filterAvailable(m: Map, capabilities: Capabilities) {
}
const findMounter = (mounters: Map, appRoute?: string) =>
[...mounters].find(([, mounter]) => mounter.appRoute === appRoute);
-const getAppUrl = (mounters: Map, appId: string, path: string = '') =>
- `/${mounters.get(appId)?.appRoute ?? `/app/${appId}`}/${path}`
+
+const getAppUrl = (mounters: Map, appId: string, path: string = '') => {
+ const appBasePath = mounters.get(appId)?.appRoute
+ ? `/${mounters.get(appId)!.appRoute}`
+ : `/app/${appId}`;
+
+ // Only preppend slash if not a hash or query path
+ path = path.startsWith('#') || path.startsWith('?') ? path : `/${path}`;
+
+ return `${appBasePath}${path}`
.replace(/\/{2,}/g, '/') // Remove duplicate slashes
.replace(/\/$/, ''); // Remove trailing slash
+};
const allApplicationsFilter = '__ALL__';
@@ -93,7 +102,7 @@ interface AppUpdaterWrapper {
* @internal
*/
export class ApplicationService {
- private readonly apps = new Map();
+ private readonly apps = new Map | LegacyApp>();
private readonly mounters = new Map();
private readonly capabilities = new CapabilitiesService();
private readonly appLeaveHandlers = new Map();
@@ -143,7 +152,7 @@ export class ApplicationService {
return {
registerMountContext: this.mountContext!.registerContext,
- register: (plugin, app) => {
+ register: (plugin, app: App) => {
app = { appRoute: `/app/${app.id}`, ...app };
if (this.registrationClosed) {
diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts
index e7ea330657648..ec10d2bc22871 100644
--- a/src/core/public/application/index.ts
+++ b/src/core/public/application/index.ts
@@ -19,6 +19,7 @@
export { ApplicationService } from './application_service';
export { Capabilities } from './capabilities';
+export { ScopedHistory } from './scoped_history';
export {
App,
AppBase,
diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx
index 0c5f5a138d58f..2f26bc1409104 100644
--- a/src/core/public/application/integration_tests/router.test.tsx
+++ b/src/core/public/application/integration_tests/router.test.tsx
@@ -25,15 +25,17 @@ import { AppRouter, AppNotFound } from '../ui';
import { EitherApp, MockedMounterMap, MockedMounterTuple } from '../test_types';
import { createRenderer, createAppMounter, createLegacyAppMounter, getUnmounter } from './utils';
import { AppStatus } from '../types';
+import { ScopedHistory } from '../scoped_history';
describe('AppContainer', () => {
let mounters: MockedMounterMap;
- let history: History;
+ let globalHistory: History;
let appStatuses$: BehaviorSubject