mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[7.x] Remove browser basePath service, move functionality into browser http service (#36611) (#37387)
* Remove browser basePath service, move functionality into browser http service (#36611) * Remove browser basePath service, move functionality into browser http service * Update generated documentation for removal of browser basePath * Fix type interface for removal of basePath * Split IHttpService into separate setup and start interfaces * Rename appendToBasePath to prependBasePath, rename removeFromBasePath to removeBasePath * Fix import of http test setup
This commit is contained in:
parent
c0b857598a
commit
c019dc5bd0
69 changed files with 789 additions and 830 deletions
|
@ -1,24 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathSetup](./kibana-plugin-public.basepathsetup.md) > [addToPath](./kibana-plugin-public.basepathsetup.addtopath.md)
|
||||
|
||||
## BasePathSetup.addToPath() method
|
||||
|
||||
Add the current basePath to a path string.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
addToPath(path: string): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>string</code> | A relative url including the leading <code>/</code>, otherwise it will be returned without modification |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathSetup](./kibana-plugin-public.basepathsetup.md) > [get](./kibana-plugin-public.basepathsetup.get.md)
|
||||
|
||||
## BasePathSetup.get() method
|
||||
|
||||
Get the basePath as defined by the server
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
get(): string;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
||||
The basePath as defined by the server
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathSetup](./kibana-plugin-public.basepathsetup.md)
|
||||
|
||||
## BasePathSetup interface
|
||||
|
||||
Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface BasePathSetup
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [addToPath(path)](./kibana-plugin-public.basepathsetup.addtopath.md) | Add the current basePath to a path string. |
|
||||
| [get()](./kibana-plugin-public.basepathsetup.get.md) | Get the basePath as defined by the server |
|
||||
| [removeFromPath(path)](./kibana-plugin-public.basepathsetup.removefrompath.md) | Removes basePath from the given path if the path starts with it |
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathSetup](./kibana-plugin-public.basepathsetup.md) > [removeFromPath](./kibana-plugin-public.basepathsetup.removefrompath.md)
|
||||
|
||||
## BasePathSetup.removeFromPath() method
|
||||
|
||||
Removes basePath from the given path if the path starts with it
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
removeFromPath(path: string): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>string</code> | A relative url that starts with the basePath, which will be stripped |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathStart](./kibana-plugin-public.basepathstart.md)
|
||||
|
||||
## BasePathStart type
|
||||
|
||||
Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type BasePathStart = BasePathSetup;
|
||||
```
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreSetup](./kibana-plugin-public.coresetup.md) > [basePath](./kibana-plugin-public.coresetup.basepath.md)
|
||||
|
||||
## CoreSetup.basePath property
|
||||
|
||||
[BasePathSetup](./kibana-plugin-public.basepathsetup.md)
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
basePath: BasePathSetup;
|
||||
```
|
|
@ -16,7 +16,6 @@ export interface CoreSetup
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [basePath](./kibana-plugin-public.coresetup.basepath.md) | <code>BasePathSetup</code> | [BasePathSetup](./kibana-plugin-public.basepathsetup.md) |
|
||||
| [chrome](./kibana-plugin-public.coresetup.chrome.md) | <code>ChromeSetup</code> | [ChromeSetup](./kibana-plugin-public.chromesetup.md) |
|
||||
| [fatalErrors](./kibana-plugin-public.coresetup.fatalerrors.md) | <code>FatalErrorsSetup</code> | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) |
|
||||
| [http](./kibana-plugin-public.coresetup.http.md) | <code>HttpSetup</code> | [HttpSetup](./kibana-plugin-public.httpsetup.md) |
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [basePath](./kibana-plugin-public.corestart.basepath.md)
|
||||
|
||||
## CoreStart.basePath property
|
||||
|
||||
[BasePathStart](./kibana-plugin-public.basepathstart.md)
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
basePath: BasePathStart;
|
||||
```
|
|
@ -17,7 +17,6 @@ export interface CoreStart
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [application](./kibana-plugin-public.corestart.application.md) | <code>Pick<ApplicationStart, 'capabilities'></code> | [ApplicationStart](./kibana-plugin-public.applicationstart.md) |
|
||||
| [basePath](./kibana-plugin-public.corestart.basepath.md) | <code>BasePathStart</code> | [BasePathStart](./kibana-plugin-public.basepathstart.md) |
|
||||
| [chrome](./kibana-plugin-public.corestart.chrome.md) | <code>ChromeStart</code> | [ChromeStart](./kibana-plugin-public.chromestart.md) |
|
||||
| [http](./kibana-plugin-public.corestart.http.md) | <code>HttpStart</code> | [HttpStart](./kibana-plugin-public.httpstart.md) |
|
||||
| [i18n](./kibana-plugin-public.corestart.i18n.md) | <code>I18nStart</code> | [I18nStart](./kibana-plugin-public.i18nstart.md) |
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [addLoadingCount](./kibana-plugin-public.httpservicebase.addloadingcount.md)
|
||||
|
||||
## HttpServiceBase.addLoadingCount() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
addLoadingCount(count$: Observable<number>): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| count$ | <code>Observable<number></code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [delete](./kibana-plugin-public.httpservicebase.delete.md)
|
||||
|
||||
## HttpServiceBase.delete property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
delete: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [fetch](./kibana-plugin-public.httpservicebase.fetch.md)
|
||||
|
||||
## HttpServiceBase.fetch property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
fetch: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [get](./kibana-plugin-public.httpservicebase.get.md)
|
||||
|
||||
## HttpServiceBase.get property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
get: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [getBasePath](./kibana-plugin-public.httpservicebase.getbasepath.md)
|
||||
|
||||
## HttpServiceBase.getBasePath() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getBasePath(): string;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [getLoadingCount$](./kibana-plugin-public.httpservicebase.getloadingcount$.md)
|
||||
|
||||
## HttpServiceBase.getLoadingCount$() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getLoadingCount$(): Observable<number>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Observable<number>`
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [head](./kibana-plugin-public.httpservicebase.head.md)
|
||||
|
||||
## HttpServiceBase.head property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
head: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,37 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md)
|
||||
|
||||
## HttpServiceBase interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface HttpServiceBase
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [delete](./kibana-plugin-public.httpservicebase.delete.md) | <code>HttpHandler</code> | |
|
||||
| [fetch](./kibana-plugin-public.httpservicebase.fetch.md) | <code>HttpHandler</code> | |
|
||||
| [get](./kibana-plugin-public.httpservicebase.get.md) | <code>HttpHandler</code> | |
|
||||
| [head](./kibana-plugin-public.httpservicebase.head.md) | <code>HttpHandler</code> | |
|
||||
| [options](./kibana-plugin-public.httpservicebase.options.md) | <code>HttpHandler</code> | |
|
||||
| [patch](./kibana-plugin-public.httpservicebase.patch.md) | <code>HttpHandler</code> | |
|
||||
| [post](./kibana-plugin-public.httpservicebase.post.md) | <code>HttpHandler</code> | |
|
||||
| [put](./kibana-plugin-public.httpservicebase.put.md) | <code>HttpHandler</code> | |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [addLoadingCount(count$)](./kibana-plugin-public.httpservicebase.addloadingcount.md) | |
|
||||
| [getBasePath()](./kibana-plugin-public.httpservicebase.getbasepath.md) | |
|
||||
| [getLoadingCount$()](./kibana-plugin-public.httpservicebase.getloadingcount$.md) | |
|
||||
| [prependBasePath(path)](./kibana-plugin-public.httpservicebase.prependbasepath.md) | |
|
||||
| [removeBasePath(path)](./kibana-plugin-public.httpservicebase.removebasepath.md) | |
|
||||
| [stop()](./kibana-plugin-public.httpservicebase.stop.md) | |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [options](./kibana-plugin-public.httpservicebase.options.md)
|
||||
|
||||
## HttpServiceBase.options property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
options: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [patch](./kibana-plugin-public.httpservicebase.patch.md)
|
||||
|
||||
## HttpServiceBase.patch property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
patch: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [post](./kibana-plugin-public.httpservicebase.post.md)
|
||||
|
||||
## HttpServiceBase.post property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
post: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [prependBasePath](./kibana-plugin-public.httpservicebase.prependbasepath.md)
|
||||
|
||||
## HttpServiceBase.prependBasePath() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
prependBasePath(path: string): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>string</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [put](./kibana-plugin-public.httpservicebase.put.md)
|
||||
|
||||
## HttpServiceBase.put property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
put: HttpHandler;
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [removeBasePath](./kibana-plugin-public.httpservicebase.removebasepath.md)
|
||||
|
||||
## HttpServiceBase.removeBasePath() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
removeBasePath(path: string): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>string</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [stop](./kibana-plugin-public.httpservicebase.stop.md)
|
||||
|
||||
## HttpServiceBase.stop() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stop(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
|
@ -8,5 +8,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpSetup = ReturnType<HttpService['setup']>;
|
||||
export declare type HttpSetup = HttpServiceBase;
|
||||
```
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpStart = ReturnType<HttpService['start']>;
|
||||
export declare type HttpStart = HttpServiceBase;
|
||||
```
|
||||
|
|
|
@ -23,7 +23,6 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| --- | --- |
|
||||
| [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) | |
|
||||
| [ApplicationStart](./kibana-plugin-public.applicationstart.md) | |
|
||||
| [BasePathSetup](./kibana-plugin-public.basepathsetup.md) | Provides access to the 'server.basePath' configuration option in kibana.yml |
|
||||
| [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. |
|
||||
| [ChromeBadge](./kibana-plugin-public.chromebadge.md) | |
|
||||
| [ChromeBrand](./kibana-plugin-public.chromebrand.md) | |
|
||||
|
@ -33,6 +32,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [CoreStart](./kibana-plugin-public.corestart.md) | Core services exposed to the <code>Plugin</code> start lifecycle |
|
||||
| [FatalErrorInfo](./kibana-plugin-public.fatalerrorinfo.md) | Represents the <code>message</code> and <code>stack</code> of a fatal Error |
|
||||
| [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
|
||||
| [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | |
|
||||
| [I18nSetup](./kibana-plugin-public.i18nsetup.md) | I18nSetup.Context is required by any localizable React component from @<!-- -->kbn/i18n and @<!-- -->elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. |
|
||||
| [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) | |
|
||||
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | |
|
||||
|
@ -46,7 +46,6 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
|
||||
| Type Alias | Description |
|
||||
| --- | --- |
|
||||
| [BasePathStart](./kibana-plugin-public.basepathstart.md) | Provides access to the 'server.basePath' configuration option in kibana.yml |
|
||||
| [ChromeHelpExtension](./kibana-plugin-public.chromehelpextension.md) | |
|
||||
| [ChromeSetup](./kibana-plugin-public.chromesetup.md) | |
|
||||
| [ChromeStart](./kibana-plugin-public.chromestart.md) | |
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { MockCapabilitiesService } from './application_service.test.mocks';
|
||||
import { ApplicationService } from './application_service';
|
||||
|
@ -29,9 +28,7 @@ describe('#start()', () => {
|
|||
setup.registerApp({ id: 'app1' } as any);
|
||||
setup.registerLegacyApp({ id: 'app2' } as any);
|
||||
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||
const basePath = basePathServiceMock.createStartContract();
|
||||
expect((await service.start({ basePath, injectedMetadata })).availableApps)
|
||||
.toMatchInlineSnapshot(`
|
||||
expect((await service.start({ injectedMetadata })).availableApps).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"id": "app1",
|
||||
|
@ -48,11 +45,9 @@ Array [
|
|||
const setup = service.setup();
|
||||
setup.registerApp({ id: 'app1' } as any);
|
||||
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||
const basePath = basePathServiceMock.createStartContract();
|
||||
await service.start({ basePath, injectedMetadata });
|
||||
await service.start({ injectedMetadata });
|
||||
expect(MockCapabilitiesService.start).toHaveBeenCalledWith({
|
||||
apps: [{ id: 'app1' }],
|
||||
basePath,
|
||||
injectedMetadata,
|
||||
});
|
||||
});
|
||||
|
@ -62,11 +57,9 @@ Array [
|
|||
const setup = service.setup();
|
||||
setup.registerLegacyApp({ id: 'legacyApp1' } as any);
|
||||
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||
const basePath = basePathServiceMock.createStartContract();
|
||||
await service.start({ basePath, injectedMetadata });
|
||||
await service.start({ injectedMetadata });
|
||||
expect(MockCapabilitiesService.start).toHaveBeenCalledWith({
|
||||
apps: [{ id: 'legacyApp1' }],
|
||||
basePath,
|
||||
injectedMetadata,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
import { Observable, BehaviorSubject } from 'rxjs';
|
||||
import { CapabilitiesStart, CapabilitiesService, Capabilities } from './capabilities';
|
||||
import { InjectedMetadataStart } from '../injected_metadata';
|
||||
import { BasePathStart } from '../base_path';
|
||||
|
||||
interface BaseApp {
|
||||
id: string;
|
||||
|
@ -106,7 +105,6 @@ export interface ApplicationStart {
|
|||
}
|
||||
|
||||
interface StartDeps {
|
||||
basePath: BasePathStart;
|
||||
injectedMetadata: InjectedMetadataStart;
|
||||
}
|
||||
|
||||
|
@ -130,14 +128,13 @@ export class ApplicationService {
|
|||
};
|
||||
}
|
||||
|
||||
public async start({ basePath, injectedMetadata }: StartDeps): Promise<ApplicationStart> {
|
||||
public async start({ injectedMetadata }: StartDeps): Promise<ApplicationStart> {
|
||||
this.apps$.complete();
|
||||
this.legacyApps$.complete();
|
||||
|
||||
const apps = [...this.apps$.value, ...this.legacyApps$.value];
|
||||
const { capabilities, availableApps } = await this.capabilities.start({
|
||||
apps,
|
||||
basePath,
|
||||
injectedMetadata,
|
||||
});
|
||||
|
||||
|
|
|
@ -19,13 +19,11 @@
|
|||
|
||||
import { InjectedMetadataService } from '../../injected_metadata';
|
||||
import { CapabilitiesService } from './capabilities_service';
|
||||
import { basePathServiceMock } from '../../base_path/base_path_service.mock';
|
||||
|
||||
describe('#start', () => {
|
||||
const basePath = basePathServiceMock.createStartContract();
|
||||
basePath.addToPath.mockImplementation(str => str);
|
||||
const injectedMetadata = new InjectedMetadataService({
|
||||
injectedMetadata: {
|
||||
version: 'kibanaVersion',
|
||||
capabilities: {
|
||||
catalogue: {},
|
||||
management: {},
|
||||
|
@ -42,7 +40,7 @@ describe('#start', () => {
|
|||
|
||||
it('filters available apps based on returned navLinks', async () => {
|
||||
const service = new CapabilitiesService();
|
||||
expect((await service.start({ apps, basePath, injectedMetadata })).availableApps).toEqual([
|
||||
expect((await service.start({ apps, injectedMetadata })).availableApps).toEqual([
|
||||
{ id: 'app1' },
|
||||
]);
|
||||
});
|
||||
|
@ -51,7 +49,6 @@ describe('#start', () => {
|
|||
const service = new CapabilitiesService();
|
||||
const { capabilities } = await service.start({
|
||||
apps,
|
||||
basePath,
|
||||
injectedMetadata,
|
||||
});
|
||||
|
||||
|
|
|
@ -20,11 +20,9 @@
|
|||
import { deepFreeze, RecursiveReadonly } from '../../utils/deep_freeze';
|
||||
import { MixedApp } from '../application_service';
|
||||
import { InjectedMetadataStart } from '../../injected_metadata';
|
||||
import { BasePathStart } from '../../base_path';
|
||||
|
||||
interface StartDeps {
|
||||
apps: ReadonlyArray<MixedApp>;
|
||||
basePath: BasePathStart;
|
||||
injectedMetadata: InjectedMetadataStart;
|
||||
}
|
||||
|
||||
|
@ -74,7 +72,7 @@ export interface CapabilitiesStart {
|
|||
* Service that is responsible for UI Capabilities.
|
||||
*/
|
||||
export class CapabilitiesService {
|
||||
public async start({ apps, basePath, injectedMetadata }: StartDeps): Promise<CapabilitiesStart> {
|
||||
public async start({ apps, injectedMetadata }: StartDeps): Promise<CapabilitiesStart> {
|
||||
const capabilities = deepFreeze(injectedMetadata.getCapabilities());
|
||||
const availableApps = apps.filter(app => capabilities.navLinks[app.id]);
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { BasePathService, BasePathSetup } from './base_path_service';
|
||||
|
||||
const createSetupContractMock = () => {
|
||||
const setupContract: jest.Mocked<BasePathSetup> = {
|
||||
get: jest.fn(),
|
||||
addToPath: jest.fn(),
|
||||
removeFromPath: jest.fn(),
|
||||
};
|
||||
setupContract.get.mockReturnValue('get');
|
||||
setupContract.addToPath.mockReturnValue('addToPath');
|
||||
setupContract.removeFromPath.mockReturnValue('removeFromPath');
|
||||
return setupContract;
|
||||
};
|
||||
|
||||
const createStartContractMock = createSetupContractMock;
|
||||
|
||||
type BasePathServiceContract = PublicMethodsOf<BasePathService>;
|
||||
const createMock = () => {
|
||||
const mocked: jest.Mocked<BasePathServiceContract> = {
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
};
|
||||
mocked.setup.mockReturnValue(createSetupContractMock());
|
||||
mocked.start.mockReturnValue(createStartContractMock());
|
||||
return mocked;
|
||||
};
|
||||
|
||||
export const basePathServiceMock = {
|
||||
create: createMock,
|
||||
createSetupContract: createSetupContractMock,
|
||||
createStartContract: createStartContractMock,
|
||||
};
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { BasePathService } from './base_path_service';
|
||||
|
||||
function setupService(options: any = {}) {
|
||||
const injectedBasePath: string =
|
||||
options.injectedBasePath === undefined ? '/foo/bar' : options.injectedBasePath;
|
||||
|
||||
const service = new BasePathService();
|
||||
|
||||
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
|
||||
injectedMetadata.getBasePath.mockReturnValue(injectedBasePath);
|
||||
|
||||
const setupContract = service.setup({
|
||||
injectedMetadata,
|
||||
});
|
||||
|
||||
return {
|
||||
service,
|
||||
setupContract,
|
||||
injectedBasePath,
|
||||
};
|
||||
}
|
||||
|
||||
describe('setup.get()', () => {
|
||||
it('returns an empty string if no basePath is injected', () => {
|
||||
const { setupContract } = setupService({ injectedBasePath: null });
|
||||
expect(setupContract.get()).toBe('');
|
||||
});
|
||||
|
||||
it('returns the injected basePath', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.get()).toBe('/foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup.addToPath()', () => {
|
||||
it('adds the base path to the path if it is relative and starts with a slash', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.addToPath('/a/b')).toBe('/foo/bar/a/b');
|
||||
});
|
||||
|
||||
it('leaves the query string and hash of path unchanged', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.addToPath('/a/b?x=y#c/d/e')).toBe('/foo/bar/a/b?x=y#c/d/e');
|
||||
});
|
||||
|
||||
it('returns the path unchanged if it does not start with a slash', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.addToPath('a/b')).toBe('a/b');
|
||||
});
|
||||
|
||||
it('returns the path unchanged it it has a hostname', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.addToPath('http://localhost:5601/a/b')).toBe('http://localhost:5601/a/b');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup.removeFromPath()', () => {
|
||||
it('removes the basePath if relative path starts with it', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.removeFromPath('/foo/bar/a/b')).toBe('/a/b');
|
||||
});
|
||||
|
||||
it('leaves query string and hash intact', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.removeFromPath('/foo/bar/a/b?c=y#1234')).toBe('/a/b?c=y#1234');
|
||||
});
|
||||
|
||||
it('ignores urls with hostnames', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.removeFromPath('http://localhost:5601/foo/bar/a/b')).toBe(
|
||||
'http://localhost:5601/foo/bar/a/b'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns slash if path is just basePath', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.removeFromPath('/foo/bar')).toBe('/');
|
||||
});
|
||||
|
||||
it('returns full path if basePath is not its own segment', () => {
|
||||
const { setupContract } = setupService();
|
||||
expect(setupContract.removeFromPath('/foo/barhop')).toBe('/foo/barhop');
|
||||
});
|
||||
});
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { InjectedMetadataSetup, InjectedMetadataStart } from '../injected_metadata';
|
||||
import { modifyUrl } from '../utils';
|
||||
|
||||
/**
|
||||
* Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface BasePathSetup {
|
||||
/**
|
||||
* Get the basePath as defined by the server
|
||||
*
|
||||
* @returns The basePath as defined by the server
|
||||
*/
|
||||
get(): string;
|
||||
|
||||
/**
|
||||
* Add the current basePath to a path string.
|
||||
*
|
||||
* @param path - A relative url including the leading `/`, otherwise it will be returned without modification
|
||||
*/
|
||||
addToPath(path: string): string;
|
||||
|
||||
/**
|
||||
* Removes basePath from the given path if the path starts with it
|
||||
*
|
||||
* @param path - A relative url that starts with the basePath, which will be stripped
|
||||
*/
|
||||
removeFromPath(path: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BasePathStart = BasePathSetup;
|
||||
|
||||
interface SetupDeps {
|
||||
injectedMetadata: InjectedMetadataSetup;
|
||||
}
|
||||
|
||||
interface StartDeps {
|
||||
injectedMetadata: InjectedMetadataStart;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class BasePathService {
|
||||
public setup({ injectedMetadata }: SetupDeps) {
|
||||
const basePath = injectedMetadata.getBasePath() || '';
|
||||
|
||||
const basePathSetup: BasePathSetup = {
|
||||
get: () => basePath,
|
||||
addToPath: path => {
|
||||
return modifyUrl(path, parts => {
|
||||
if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) {
|
||||
parts.pathname = `${basePath}${parts.pathname}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
removeFromPath(path: string): string {
|
||||
if (!basePath) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path === basePath) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (path.startsWith(basePath + '/')) {
|
||||
return path.slice(basePath.length);
|
||||
}
|
||||
|
||||
return path;
|
||||
},
|
||||
};
|
||||
|
||||
return basePathSetup;
|
||||
}
|
||||
|
||||
public start({ injectedMetadata }: StartDeps) {
|
||||
return this.setup({ injectedMetadata });
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { BasePathService, BasePathSetup, BasePathStart } from './base_path_service';
|
|
@ -27,7 +27,7 @@ import { InjectedMetadataSetup } from '../injected_metadata';
|
|||
import { NotificationsSetup } from '../notifications';
|
||||
import { NavLinksService } from './nav_links/nav_links_service';
|
||||
import { ApplicationStart } from '../application';
|
||||
import { BasePathStart } from '../base_path';
|
||||
import { HttpStart } from '../http';
|
||||
|
||||
const IS_COLLAPSED_KEY = 'core.chrome.isCollapsed';
|
||||
|
||||
|
@ -70,7 +70,7 @@ interface SetupDeps {
|
|||
|
||||
interface StartDeps {
|
||||
application: ApplicationStart;
|
||||
basePath: BasePathStart;
|
||||
http: HttpStart;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -230,9 +230,9 @@ export class ChromeService {
|
|||
};
|
||||
}
|
||||
|
||||
public start({ application, basePath }: StartDeps) {
|
||||
public start({ application, http }: StartDeps) {
|
||||
return {
|
||||
navLinks: this.navLinks.start({ application, basePath }),
|
||||
navLinks: this.navLinks.start({ application, http }),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ const mockAppService = {
|
|||
],
|
||||
} as any;
|
||||
|
||||
const mockBasePath = {
|
||||
addToPath: (url: string) => `wow${url}`,
|
||||
const mockHttp = {
|
||||
prependBasePath: (url: string) => `wow${url}`,
|
||||
} as any;
|
||||
|
||||
describe('NavLinksService', () => {
|
||||
|
@ -38,7 +38,7 @@ describe('NavLinksService', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
service = new NavLinksService();
|
||||
start = service.start({ application: mockAppService, basePath: mockBasePath });
|
||||
start = service.start({ application: mockAppService, http: mockHttp });
|
||||
});
|
||||
|
||||
describe('#getNavLinks$()', () => {
|
||||
|
|
|
@ -22,17 +22,17 @@ import { BehaviorSubject, ReplaySubject } from 'rxjs';
|
|||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { NavLinkWrapper, NavLinkUpdateableFields } from './nav_link';
|
||||
import { ApplicationStart } from '../../application';
|
||||
import { BasePathStart } from '../../base_path';
|
||||
import { HttpStart } from '../../http';
|
||||
|
||||
interface StartDeps {
|
||||
application: ApplicationStart;
|
||||
basePath: BasePathStart;
|
||||
http: HttpStart;
|
||||
}
|
||||
|
||||
export class NavLinksService {
|
||||
private readonly stop$ = new ReplaySubject(1);
|
||||
|
||||
public start({ application, basePath }: StartDeps) {
|
||||
public start({ application, http }: StartDeps) {
|
||||
const navLinks$ = new BehaviorSubject<ReadonlyMap<string, NavLinkWrapper>>(
|
||||
new Map(
|
||||
application.availableApps.map(
|
||||
|
@ -42,7 +42,7 @@ export class NavLinksService {
|
|||
new NavLinkWrapper({
|
||||
...app,
|
||||
// Either rootRoute or appUrl must be defined.
|
||||
baseUrl: relativeToAbsolute(basePath.addToPath((app.rootRoute || app.appUrl)!)),
|
||||
baseUrl: relativeToAbsolute(http.prependBasePath((app.rootRoute || app.appUrl)!)),
|
||||
}),
|
||||
] as [string, NavLinkWrapper]
|
||||
)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { basePathServiceMock } from './base_path/base_path_service.mock';
|
||||
import { applicationServiceMock } from './application/application_service.mock';
|
||||
import { chromeServiceMock } from './chrome/chrome_service.mock';
|
||||
import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
|
||||
|
@ -74,12 +73,6 @@ jest.doMock('./http', () => ({
|
|||
HttpService: HttpServiceConstructor,
|
||||
}));
|
||||
|
||||
export const MockBasePathService = basePathServiceMock.create();
|
||||
export const BasePathServiceConstructor = jest.fn().mockImplementation(() => MockBasePathService);
|
||||
jest.doMock('./base_path', () => ({
|
||||
BasePathService: BasePathServiceConstructor,
|
||||
}));
|
||||
|
||||
export const MockUiSettingsService = uiSettingsServiceMock.create();
|
||||
export const UiSettingsServiceConstructor = jest
|
||||
.fn()
|
||||
|
|
|
@ -18,14 +18,12 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
BasePathServiceConstructor,
|
||||
ChromeServiceConstructor,
|
||||
FatalErrorsServiceConstructor,
|
||||
HttpServiceConstructor,
|
||||
I18nServiceConstructor,
|
||||
InjectedMetadataServiceConstructor,
|
||||
LegacyPlatformServiceConstructor,
|
||||
MockBasePathService,
|
||||
MockChromeService,
|
||||
MockFatalErrorsService,
|
||||
MockHttpService,
|
||||
|
@ -78,7 +76,6 @@ describe('constructor', () => {
|
|||
expect(FatalErrorsServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(NotificationServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(HttpServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(BasePathServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(UiSettingsServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(ChromeServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
expect(OverlayServiceConstructor).toHaveBeenCalledTimes(1);
|
||||
|
@ -169,11 +166,6 @@ describe('#setup()', () => {
|
|||
expect(MockHttpService.setup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('calls basePath#setup()', async () => {
|
||||
await setupCore();
|
||||
expect(MockBasePathService.setup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('calls uiSettings#setup()', async () => {
|
||||
await setupCore();
|
||||
expect(MockUiSettingsService.setup).toHaveBeenCalledTimes(1);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
import './core.css';
|
||||
|
||||
import { InternalCoreSetup, InternalCoreStart } from '.';
|
||||
import { BasePathService } from './base_path';
|
||||
import { ChromeService } from './chrome';
|
||||
import { FatalErrorsService, FatalErrorsSetup } from './fatal_errors';
|
||||
import { HttpService } from './http';
|
||||
|
@ -61,7 +60,6 @@ export class CoreSystem {
|
|||
private readonly notifications: NotificationsService;
|
||||
private readonly http: HttpService;
|
||||
private readonly uiSettings: UiSettingsService;
|
||||
private readonly basePath: BasePathService;
|
||||
private readonly chrome: ChromeService;
|
||||
private readonly i18n: I18nService;
|
||||
private readonly overlay: OverlayService;
|
||||
|
@ -95,7 +93,6 @@ export class CoreSystem {
|
|||
|
||||
this.notifications = new NotificationsService();
|
||||
this.http = new HttpService();
|
||||
this.basePath = new BasePathService();
|
||||
this.uiSettings = new UiSettingsService();
|
||||
this.overlay = new OverlayService();
|
||||
this.application = new ApplicationService();
|
||||
|
@ -117,27 +114,14 @@ export class CoreSystem {
|
|||
const i18n = this.i18n.setup();
|
||||
const injectedMetadata = this.injectedMetadata.setup();
|
||||
this.fatalErrorsSetup = this.fatalErrors.setup({ injectedMetadata, i18n });
|
||||
const basePath = this.basePath.setup({ injectedMetadata });
|
||||
const http = this.http.setup({
|
||||
basePath,
|
||||
injectedMetadata,
|
||||
fatalErrors: this.fatalErrorsSetup,
|
||||
});
|
||||
const uiSettings = this.uiSettings.setup({
|
||||
http,
|
||||
injectedMetadata,
|
||||
basePath,
|
||||
});
|
||||
const http = this.http.setup({ injectedMetadata, fatalErrors: this.fatalErrorsSetup });
|
||||
const uiSettings = this.uiSettings.setup({ http, injectedMetadata });
|
||||
const notifications = this.notifications.setup({ uiSettings });
|
||||
const application = this.application.setup();
|
||||
const chrome = this.chrome.setup({
|
||||
injectedMetadata,
|
||||
notifications,
|
||||
});
|
||||
const chrome = this.chrome.setup({ injectedMetadata, notifications });
|
||||
|
||||
const core: InternalCoreSetup = {
|
||||
application,
|
||||
basePath,
|
||||
chrome,
|
||||
fatalErrors: this.fatalErrorsSetup,
|
||||
http,
|
||||
|
@ -166,11 +150,10 @@ export class CoreSystem {
|
|||
public async start() {
|
||||
try {
|
||||
const injectedMetadata = await this.injectedMetadata.start();
|
||||
const basePath = await this.basePath.start({ injectedMetadata });
|
||||
const http = await this.http.start();
|
||||
const http = await this.http.start({ injectedMetadata, fatalErrors: this.fatalErrorsSetup });
|
||||
const i18n = await this.i18n.start();
|
||||
const application = await this.application.start({ basePath, injectedMetadata });
|
||||
const chrome = await this.chrome.start({ application, basePath });
|
||||
const application = await this.application.start({ injectedMetadata });
|
||||
const chrome = await this.chrome.start({ application, http });
|
||||
|
||||
const notificationsTargetDomElement = document.createElement('div');
|
||||
const overlayTargetDomElement = document.createElement('div');
|
||||
|
@ -191,7 +174,6 @@ export class CoreSystem {
|
|||
|
||||
const core: InternalCoreStart = {
|
||||
application,
|
||||
basePath,
|
||||
chrome,
|
||||
http,
|
||||
i18n,
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { merge } from 'lodash';
|
||||
import { format } from 'url';
|
||||
|
||||
import { HttpFetchOptions, HttpBody, Deps } from './types';
|
||||
import { HttpFetchError } from './http_fetch_error';
|
||||
|
||||
const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/;
|
||||
const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/;
|
||||
|
||||
export const setup = ({ basePath, injectedMetadata }: Deps) => {
|
||||
async function fetch(path: string, options: HttpFetchOptions = {}): Promise<HttpBody> {
|
||||
const { query, prependBasePath, ...fetchOptions } = merge(
|
||||
{
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
prependBasePath: true,
|
||||
headers: {
|
||||
'kbn-version': injectedMetadata.getKibanaVersion(),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
options
|
||||
);
|
||||
const url = format({
|
||||
pathname: prependBasePath ? basePath.addToPath(path) : path,
|
||||
query,
|
||||
});
|
||||
|
||||
if (
|
||||
options.headers &&
|
||||
'Content-Type' in options.headers &&
|
||||
options.headers['Content-Type'] === undefined
|
||||
) {
|
||||
delete fetchOptions.headers['Content-Type'];
|
||||
}
|
||||
|
||||
let response;
|
||||
let body = null;
|
||||
|
||||
try {
|
||||
response = await window.fetch(url, fetchOptions as RequestInit);
|
||||
} catch (err) {
|
||||
throw new HttpFetchError(err.message);
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('Content-Type') || '';
|
||||
|
||||
try {
|
||||
if (NDJSON_CONTENT.test(contentType)) {
|
||||
body = await response.blob();
|
||||
} else if (JSON_CONTENT.test(contentType)) {
|
||||
body = await response.json();
|
||||
} else {
|
||||
body = await response.text();
|
||||
}
|
||||
} catch (err) {
|
||||
throw new HttpFetchError(err.message, response, body);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new HttpFetchError(response.statusText, response, body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function shorthand(method: string) {
|
||||
return (path: string, options: HttpFetchOptions = {}) => fetch(path, { ...options, method });
|
||||
}
|
||||
|
||||
return { fetch, shorthand };
|
||||
};
|
|
@ -17,9 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpService, HttpSetup, HttpStart } from './http_service';
|
||||
import { HttpService } from './http_service';
|
||||
import { HttpSetup, HttpStart } from './types';
|
||||
|
||||
const createSetupContractMock = (): jest.Mocked<HttpSetup> => ({
|
||||
const createServiceMock = () => ({
|
||||
fetch: jest.fn(),
|
||||
get: jest.fn(),
|
||||
head: jest.fn(),
|
||||
|
@ -28,10 +29,16 @@ const createSetupContractMock = (): jest.Mocked<HttpSetup> => ({
|
|||
patch: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
options: jest.fn(),
|
||||
getBasePath: jest.fn(),
|
||||
prependBasePath: jest.fn(),
|
||||
removeBasePath: jest.fn(),
|
||||
addLoadingCount: jest.fn(),
|
||||
getLoadingCount$: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
});
|
||||
const createStartContractMock = (): jest.Mocked<HttpStart> => undefined;
|
||||
|
||||
const createSetupContractMock = (): jest.Mocked<HttpSetup> => createServiceMock();
|
||||
const createStartContractMock = (): jest.Mocked<HttpStart> => createServiceMock();
|
||||
const createMock = (): jest.Mocked<PublicMethodsOf<HttpService>> => ({
|
||||
setup: jest.fn().mockReturnValue(createSetupContractMock()),
|
||||
start: jest.fn().mockReturnValue(createStartContractMock()),
|
||||
|
|
|
@ -21,34 +21,97 @@ import * as Rx from 'rxjs';
|
|||
import { toArray } from 'rxjs/operators';
|
||||
// @ts-ignore
|
||||
import fetchMock from 'fetch-mock/es5/client';
|
||||
|
||||
import { BasePathService } from '../base_path/base_path_service';
|
||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { HttpService } from './http_service';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { setup, SetupTap } from '../../../test_utils/public/http_test_setup';
|
||||
|
||||
function setupService() {
|
||||
const httpService = new HttpService();
|
||||
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
|
||||
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
|
||||
const setupFakeBasePath: SetupTap = injectedMetadata => {
|
||||
injectedMetadata.getBasePath.mockReturnValue('/foo/bar');
|
||||
};
|
||||
|
||||
injectedMetadata.getBasePath.mockReturnValueOnce('http://localhost/myBase');
|
||||
describe('getBasePath', () => {
|
||||
it('returns an empty string if no basePath is injected', () => {
|
||||
const { http } = setup(injectedMetadata => {
|
||||
injectedMetadata.getBasePath.mockReturnValue('');
|
||||
});
|
||||
|
||||
const basePath = new BasePathService().setup({ injectedMetadata });
|
||||
const http = httpService.setup({ basePath, fatalErrors, injectedMetadata });
|
||||
expect(http.getBasePath()).toBe('');
|
||||
});
|
||||
|
||||
return { httpService, fatalErrors, http };
|
||||
}
|
||||
it('returns the injected basePath', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
describe('http requests', async () => {
|
||||
expect(http.getBasePath()).toBe('/foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prependBasePath', () => {
|
||||
it('adds the base path to the path if it is relative and starts with a slash', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.prependBasePath('/a/b')).toBe('/foo/bar/a/b');
|
||||
});
|
||||
|
||||
it('leaves the query string and hash of path unchanged', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.prependBasePath('/a/b?x=y#c/d/e')).toBe('/foo/bar/a/b?x=y#c/d/e');
|
||||
});
|
||||
|
||||
it('returns the path unchanged if it does not start with a slash', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.prependBasePath('a/b')).toBe('a/b');
|
||||
});
|
||||
|
||||
it('returns the path unchanged it it has a hostname', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.prependBasePath('http://localhost:5601/a/b')).toBe('http://localhost:5601/a/b');
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeBasePath', () => {
|
||||
it('removes the basePath if relative path starts with it', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.removeBasePath('/foo/bar/a/b')).toBe('/a/b');
|
||||
});
|
||||
|
||||
it('leaves query string and hash intact', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.removeBasePath('/foo/bar/a/b?c=y#1234')).toBe('/a/b?c=y#1234');
|
||||
});
|
||||
|
||||
it('ignores urls with hostnames', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.removeBasePath('http://localhost:5601/foo/bar/a/b')).toBe(
|
||||
'http://localhost:5601/foo/bar/a/b'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns slash if path is just basePath', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.removeBasePath('/foo/bar')).toBe('/');
|
||||
});
|
||||
|
||||
it('returns full path if basePath is not its own segment', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.removeBasePath('/foo/barhop')).toBe('/foo/barhop');
|
||||
});
|
||||
});
|
||||
|
||||
describe('http requests', () => {
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it('should use supplied request method', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.post('*', {});
|
||||
await http.fetch('/my/path', { method: 'POST' });
|
||||
|
@ -57,7 +120,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should use supplied Content-Type', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', { headers: { 'Content-Type': 'CustomContentType' } });
|
||||
|
@ -68,7 +131,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should use supplied pathname and querystring', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', { query: { a: 'b' } });
|
||||
|
@ -77,7 +140,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should use supplied headers', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', {
|
||||
|
@ -92,7 +155,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should return response', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
|
||||
|
@ -102,7 +165,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should prepend url with basepath by default', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path');
|
||||
|
@ -111,7 +174,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should not prepend url with basepath when disabled', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('my/path', { prependBasePath: false });
|
||||
|
@ -120,7 +183,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should make request with defaults', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path');
|
||||
|
@ -136,7 +199,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should reject on network error', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
expect.assertions(1);
|
||||
fetchMock.get('*', { status: 500 });
|
||||
|
@ -145,7 +208,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should contain error message when throwing response', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', { status: 404, body: { foo: 'bar' } });
|
||||
|
||||
|
@ -162,7 +225,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support get() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.get('/my/path', { method: 'POST' });
|
||||
|
@ -171,7 +234,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support head() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.head('*', {});
|
||||
await http.head('/my/path', { method: 'GET' });
|
||||
|
@ -180,7 +243,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support post() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.post('*', {});
|
||||
await http.post('/my/path', { method: 'GET', body: '{}' });
|
||||
|
@ -189,7 +252,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support put() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.put('*', {});
|
||||
await http.put('/my/path', { method: 'GET', body: '{}' });
|
||||
|
@ -198,7 +261,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support patch() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.patch('*', {});
|
||||
await http.patch('/my/path', { method: 'GET', body: '{}' });
|
||||
|
@ -207,7 +270,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support delete() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.delete('*', {});
|
||||
await http.delete('/my/path', { method: 'GET' });
|
||||
|
@ -216,7 +279,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should support options() helper', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.mock('*', { method: 'OPTIONS' });
|
||||
await http.options('/my/path', { method: 'GET' });
|
||||
|
@ -225,7 +288,7 @@ describe('http requests', async () => {
|
|||
});
|
||||
|
||||
it('should make requests for NDJSON content', async () => {
|
||||
const { http } = setupService();
|
||||
const { http } = setup();
|
||||
const content = readFileSync(join(__dirname, '_import_objects.ndjson'), { encoding: 'utf-8' });
|
||||
const body = new FormData();
|
||||
|
||||
|
@ -250,9 +313,9 @@ describe('http requests', async () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('addLoadingCount()', async () => {
|
||||
describe('addLoadingCount()', () => {
|
||||
it('subscribes to passed in sources, unsubscribes on stop', () => {
|
||||
const { httpService, http } = setupService();
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const unsubA = jest.fn();
|
||||
const subA = jest.fn().mockReturnValue(unsubA);
|
||||
|
@ -275,23 +338,23 @@ describe('addLoadingCount()', async () => {
|
|||
});
|
||||
|
||||
it('adds a fatal error if source observables emit an error', async () => {
|
||||
const { http, fatalErrors } = setupService();
|
||||
const { http, fatalErrors } = setup();
|
||||
|
||||
http.addLoadingCount(Rx.throwError(new Error('foo bar')));
|
||||
expect(fatalErrors.add.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds a fatal error if source observable emits a negative number', async () => {
|
||||
const { http, fatalErrors } = setupService();
|
||||
const { http, fatalErrors } = setup();
|
||||
|
||||
http.addLoadingCount(Rx.of(1, 2, 3, 4, -9));
|
||||
expect(fatalErrors.add.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLoadingCount$()', async () => {
|
||||
describe('getLoadingCount$()', () => {
|
||||
it('emits 0 initially, the right count when sources emit their own count, and ends with zero', async () => {
|
||||
const { httpService, http } = setupService();
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const countA$ = new Rx.Subject<number>();
|
||||
const countB$ = new Rx.Subject<number>();
|
||||
|
@ -318,7 +381,7 @@ describe('getLoadingCount$()', async () => {
|
|||
});
|
||||
|
||||
it('only emits when loading count changes', async () => {
|
||||
const { httpService, http } = setupService();
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const count$ = new Rx.Subject<number>();
|
||||
const promise = http
|
||||
|
|
|
@ -17,84 +17,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
endWith,
|
||||
map,
|
||||
pairwise,
|
||||
startWith,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { Deps } from './types';
|
||||
import { setup } from './fetch';
|
||||
import { HttpDeps, HttpSetup, HttpStart, HttpServiceBase } from './types';
|
||||
import { setup } from './http_setup';
|
||||
|
||||
/** @internal */
|
||||
export class HttpService {
|
||||
private readonly loadingCount$ = new Rx.BehaviorSubject(0);
|
||||
private readonly stop$ = new Rx.Subject();
|
||||
private service!: HttpServiceBase;
|
||||
|
||||
public setup(deps: Deps) {
|
||||
const { fetch, shorthand } = setup(deps);
|
||||
|
||||
return {
|
||||
fetch,
|
||||
delete: shorthand('DELETE'),
|
||||
get: shorthand('GET'),
|
||||
head: shorthand('HEAD'),
|
||||
options: shorthand('OPTIONS'),
|
||||
patch: shorthand('PATCH'),
|
||||
post: shorthand('POST'),
|
||||
put: shorthand('PUT'),
|
||||
addLoadingCount: (count$: Rx.Observable<number>) => {
|
||||
count$
|
||||
.pipe(
|
||||
distinctUntilChanged(),
|
||||
|
||||
tap(count => {
|
||||
if (count < 0) {
|
||||
throw new Error(
|
||||
'Observables passed to loadingCount.add() must only emit positive numbers'
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
// use takeUntil() so that we can finish each stream on stop() the same way we do when they complete,
|
||||
// by removing the previous count from the total
|
||||
takeUntil(this.stop$),
|
||||
endWith(0),
|
||||
startWith(0),
|
||||
pairwise(),
|
||||
map(([prev, next]) => next - prev)
|
||||
)
|
||||
.subscribe({
|
||||
next: delta => {
|
||||
this.loadingCount$.next(this.loadingCount$.getValue() + delta);
|
||||
},
|
||||
error: error => {
|
||||
deps.fatalErrors.add(error);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
getLoadingCount$: () => {
|
||||
return this.loadingCount$.pipe(distinctUntilChanged());
|
||||
},
|
||||
};
|
||||
public setup(deps: HttpDeps): HttpSetup {
|
||||
this.service = setup(deps.injectedMetadata, deps.fatalErrors);
|
||||
return this.service;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-params
|
||||
public start() {}
|
||||
public start(deps: HttpDeps): HttpStart {
|
||||
return this.service || this.setup(deps);
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.stop$.next();
|
||||
this.loadingCount$.complete();
|
||||
if (this.service) {
|
||||
this.service.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type HttpSetup = ReturnType<HttpService['setup']>;
|
||||
/** @public */
|
||||
export type HttpStart = ReturnType<HttpService['start']>;
|
||||
|
|
203
src/core/public/http/http_setup.ts
Normal file
203
src/core/public/http/http_setup.ts
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
endWith,
|
||||
map,
|
||||
pairwise,
|
||||
startWith,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
import { merge } from 'lodash';
|
||||
import { format } from 'url';
|
||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
||||
import { FatalErrorsSetup } from '../fatal_errors';
|
||||
import { modifyUrl } from '../utils';
|
||||
import { HttpBody, HttpFetchOptions, HttpServiceBase } from './types';
|
||||
import { HttpFetchError } from './http_fetch_error';
|
||||
|
||||
const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/;
|
||||
const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/;
|
||||
|
||||
export const setup = (
|
||||
injectedMetadata: InjectedMetadataSetup,
|
||||
fatalErrors: FatalErrorsSetup | null
|
||||
): HttpServiceBase => {
|
||||
const loadingCount$ = new BehaviorSubject(0);
|
||||
const stop$ = new Subject();
|
||||
const kibanaVersion = injectedMetadata.getKibanaVersion();
|
||||
const basePath = injectedMetadata.getBasePath() || '';
|
||||
|
||||
function prependBasePath(path: string): string {
|
||||
return modifyUrl(path, parts => {
|
||||
if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) {
|
||||
parts.pathname = `${basePath}${parts.pathname}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetch(path: string, options?: HttpFetchOptions): Promise<HttpBody> {
|
||||
const { query, prependBasePath: shouldPrependBasePath, ...fetchOptions } = merge(
|
||||
{
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
prependBasePath: true,
|
||||
headers: {
|
||||
'kbn-version': kibanaVersion,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
options || {}
|
||||
);
|
||||
const url = format({
|
||||
pathname: shouldPrependBasePath ? prependBasePath(path) : path,
|
||||
query,
|
||||
});
|
||||
|
||||
if (
|
||||
options &&
|
||||
options.headers &&
|
||||
'Content-Type' in options.headers &&
|
||||
options.headers['Content-Type'] === undefined
|
||||
) {
|
||||
delete fetchOptions.headers['Content-Type'];
|
||||
}
|
||||
|
||||
let response;
|
||||
let body = null;
|
||||
|
||||
try {
|
||||
response = await window.fetch(url, fetchOptions as RequestInit);
|
||||
} catch (err) {
|
||||
throw new HttpFetchError(err.message);
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('Content-Type') || '';
|
||||
|
||||
try {
|
||||
if (NDJSON_CONTENT.test(contentType)) {
|
||||
body = await response.blob();
|
||||
} else if (JSON_CONTENT.test(contentType)) {
|
||||
body = await response.json();
|
||||
} else {
|
||||
const text = await response.text();
|
||||
|
||||
try {
|
||||
body = JSON.parse(text);
|
||||
} catch (err) {
|
||||
body = text;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw new HttpFetchError(err.message, response, body);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new HttpFetchError(response.statusText, response, body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function shorthand(method: string) {
|
||||
return (path: string, options: HttpFetchOptions = {}) => fetch(path, { ...options, method });
|
||||
}
|
||||
|
||||
function stop() {
|
||||
stop$.next();
|
||||
loadingCount$.complete();
|
||||
}
|
||||
|
||||
function getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
function removeBasePath(path: string): string {
|
||||
if (!basePath) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path === basePath) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (path.startsWith(`${basePath}/`)) {
|
||||
return path.slice(basePath.length);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function addLoadingCount(count$: Observable<number>) {
|
||||
count$
|
||||
.pipe(
|
||||
distinctUntilChanged(),
|
||||
|
||||
tap(count => {
|
||||
if (count < 0) {
|
||||
throw new Error(
|
||||
'Observables passed to loadingCount.add() must only emit positive numbers'
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
// use takeUntil() so that we can finish each stream on stop() the same way we do when they complete,
|
||||
// by removing the previous count from the total
|
||||
takeUntil(stop$),
|
||||
endWith(0),
|
||||
startWith(0),
|
||||
pairwise(),
|
||||
map(([prev, next]) => next - prev)
|
||||
)
|
||||
.subscribe({
|
||||
next: delta => {
|
||||
loadingCount$.next(loadingCount$.getValue() + delta);
|
||||
},
|
||||
error: error => {
|
||||
if (fatalErrors) {
|
||||
fatalErrors.add(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getLoadingCount$() {
|
||||
return loadingCount$.pipe(distinctUntilChanged());
|
||||
}
|
||||
|
||||
return {
|
||||
stop,
|
||||
getBasePath,
|
||||
prependBasePath,
|
||||
removeBasePath,
|
||||
fetch,
|
||||
delete: shorthand('DELETE'),
|
||||
get: shorthand('GET'),
|
||||
head: shorthand('HEAD'),
|
||||
options: shorthand('OPTIONS'),
|
||||
patch: shorthand('PATCH'),
|
||||
post: shorthand('POST'),
|
||||
put: shorthand('PUT'),
|
||||
addLoadingCount,
|
||||
getLoadingCount$,
|
||||
};
|
||||
};
|
|
@ -17,5 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { HttpService, HttpSetup, HttpStart } from './http_service';
|
||||
export { HttpService } from './http_service';
|
||||
export { HttpFetchError } from './http_fetch_error';
|
||||
export { HttpServiceBase, HttpSetup, HttpStart } from './types';
|
||||
|
|
|
@ -17,13 +17,36 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { BasePathSetup } from '../base_path';
|
||||
import { Observable } from 'rxjs';
|
||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
||||
import { FatalErrorsSetup } from '../fatal_errors';
|
||||
|
||||
/** @public */
|
||||
export interface HttpServiceBase {
|
||||
stop(): void;
|
||||
getBasePath(): string;
|
||||
prependBasePath(path: string): string;
|
||||
removeBasePath(path: string): string;
|
||||
fetch: HttpHandler;
|
||||
delete: HttpHandler;
|
||||
get: HttpHandler;
|
||||
head: HttpHandler;
|
||||
options: HttpHandler;
|
||||
patch: HttpHandler;
|
||||
post: HttpHandler;
|
||||
put: HttpHandler;
|
||||
addLoadingCount(count$: Observable<number>): void;
|
||||
getLoadingCount$(): Observable<number>;
|
||||
}
|
||||
/** @public */
|
||||
export type HttpSetup = HttpServiceBase;
|
||||
/** @public */
|
||||
export type HttpStart = HttpServiceBase;
|
||||
/** @public */
|
||||
export interface HttpHeadersInit {
|
||||
[name: string]: any;
|
||||
}
|
||||
/** @public */
|
||||
export interface HttpRequestInit {
|
||||
body?: BodyInit | null;
|
||||
cache?: RequestCache;
|
||||
|
@ -39,17 +62,22 @@ export interface HttpRequestInit {
|
|||
signal?: AbortSignal | null;
|
||||
window?: any;
|
||||
}
|
||||
export interface Deps {
|
||||
basePath: BasePathSetup;
|
||||
/** @public */
|
||||
export interface HttpDeps {
|
||||
injectedMetadata: InjectedMetadataSetup;
|
||||
fatalErrors: FatalErrorsSetup;
|
||||
fatalErrors: FatalErrorsSetup | null;
|
||||
}
|
||||
/** @public */
|
||||
export interface HttpFetchQuery {
|
||||
[key: string]: string | number | boolean | undefined;
|
||||
}
|
||||
/** @public */
|
||||
export interface HttpFetchOptions extends HttpRequestInit {
|
||||
query?: HttpFetchQuery;
|
||||
prependBasePath?: boolean;
|
||||
headers?: HttpHeadersInit;
|
||||
}
|
||||
/** @public */
|
||||
export type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise<HttpBody>;
|
||||
/** @public */
|
||||
export type HttpBody = BodyInit | null;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
import { BasePathSetup, BasePathStart } from './base_path';
|
||||
import {
|
||||
ChromeBadge,
|
||||
ChromeBrand,
|
||||
|
@ -46,7 +45,7 @@ import {
|
|||
ChromeStart,
|
||||
} from './chrome';
|
||||
import { FatalErrorsSetup, FatalErrorInfo } from './fatal_errors';
|
||||
import { HttpSetup, HttpStart } from './http';
|
||||
import { HttpServiceBase, HttpSetup, HttpStart } from './http';
|
||||
import { I18nSetup, I18nStart } from './i18n';
|
||||
import { InjectedMetadataSetup, InjectedMetadataStart, LegacyNavLink } from './injected_metadata';
|
||||
import {
|
||||
|
@ -74,8 +73,6 @@ export { CoreContext, CoreSystem } from './core_system';
|
|||
* https://github.com/Microsoft/web-build-tools/issues/1237
|
||||
*/
|
||||
export interface CoreSetup {
|
||||
/** {@link BasePathSetup} */
|
||||
basePath: BasePathSetup;
|
||||
/** {@link ChromeSetup} */
|
||||
chrome: ChromeSetup;
|
||||
/** {@link FatalErrorsSetup} */
|
||||
|
@ -102,8 +99,6 @@ export interface CoreSetup {
|
|||
export interface CoreStart {
|
||||
/** {@link ApplicationStart} */
|
||||
application: Pick<ApplicationStart, 'capabilities'>;
|
||||
/** {@link BasePathStart} */
|
||||
basePath: BasePathStart;
|
||||
/** {@link ChromeStart} */
|
||||
chrome: ChromeStart;
|
||||
/** {@link HttpStart} */
|
||||
|
@ -131,8 +126,7 @@ export interface InternalCoreStart extends CoreStart {
|
|||
export {
|
||||
ApplicationSetup,
|
||||
ApplicationStart,
|
||||
BasePathSetup,
|
||||
BasePathStart,
|
||||
HttpServiceBase,
|
||||
HttpSetup,
|
||||
HttpStart,
|
||||
FatalErrorsSetup,
|
||||
|
|
|
@ -149,7 +149,6 @@ jest.mock('ui/chrome/services/global_nav_state', () => {
|
|||
};
|
||||
});
|
||||
|
||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||
import { chromeServiceMock } from '../chrome/chrome_service.mock';
|
||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
|
@ -162,7 +161,6 @@ import { LegacyPlatformService } from './legacy_service';
|
|||
import { applicationServiceMock } from '../application/application_service.mock';
|
||||
|
||||
const applicationSetup = applicationServiceMock.createSetupContract();
|
||||
const basePathSetup = basePathServiceMock.createSetupContract();
|
||||
const chromeSetup = chromeServiceMock.createSetupContract();
|
||||
const fatalErrorsSetup = fatalErrorsServiceMock.createSetupContract();
|
||||
const httpSetup = httpServiceMock.createSetupContract();
|
||||
|
@ -185,7 +183,6 @@ const defaultSetupDeps = {
|
|||
injectedMetadata: injectedMetadataSetup,
|
||||
notifications: notificationsSetup,
|
||||
http: httpSetup,
|
||||
basePath: basePathSetup,
|
||||
uiSettings: uiSettingsSetup,
|
||||
chrome: chromeSetup,
|
||||
},
|
||||
|
@ -193,10 +190,9 @@ const defaultSetupDeps = {
|
|||
};
|
||||
|
||||
const applicationStart = applicationServiceMock.createStartContract();
|
||||
const basePathStart = basePathServiceMock.createStartContract();
|
||||
const httpStart = httpServiceMock.createStartContract();
|
||||
const chromeStart = chromeServiceMock.createStartContract();
|
||||
const i18nStart = i18nServiceMock.createStartContract();
|
||||
const httpStart = httpServiceMock.createStartContract();
|
||||
const injectedMetadataStart = injectedMetadataServiceMock.createStartContract();
|
||||
const notificationsStart = notificationServiceMock.createStartContract();
|
||||
const overlayStart = overlayServiceMock.createStartContract();
|
||||
|
@ -204,10 +200,9 @@ const overlayStart = overlayServiceMock.createStartContract();
|
|||
const defaultStartDeps = {
|
||||
core: {
|
||||
application: applicationStart,
|
||||
basePath: basePathStart,
|
||||
http: httpStart,
|
||||
chrome: chromeStart,
|
||||
i18n: i18nStart,
|
||||
http: httpStart,
|
||||
injectedMetadata: injectedMetadataStart,
|
||||
notifications: notificationsStart,
|
||||
overlays: overlayStart,
|
||||
|
@ -290,7 +285,7 @@ describe('#setup()', () => {
|
|||
legacyPlatform.setup(defaultSetupDeps);
|
||||
|
||||
expect(mockBasePathInit).toHaveBeenCalledTimes(1);
|
||||
expect(mockBasePathInit).toHaveBeenCalledWith(basePathSetup);
|
||||
expect(mockBasePathInit).toHaveBeenCalledWith(httpSetup);
|
||||
});
|
||||
|
||||
it('passes basePath service to ui/chrome/api/ui_settings', () => {
|
||||
|
|
|
@ -62,7 +62,6 @@ export class LegacyPlatformService {
|
|||
fatalErrors,
|
||||
notifications,
|
||||
http,
|
||||
basePath,
|
||||
uiSettings,
|
||||
chrome,
|
||||
} = core;
|
||||
|
@ -75,7 +74,7 @@ export class LegacyPlatformService {
|
|||
require('ui/kfetch').__newPlatformSetup__(http);
|
||||
require('ui/notify/toasts').__newPlatformSetup__(notifications.toasts);
|
||||
require('ui/chrome/api/loading_count').__newPlatformSetup__(http);
|
||||
require('ui/chrome/api/base_path').__newPlatformSetup__(basePath);
|
||||
require('ui/chrome/api/base_path').__newPlatformSetup__(http);
|
||||
require('ui/chrome/api/ui_settings').__newPlatformSetup__(uiSettings);
|
||||
require('ui/chrome/api/injected_vars').__newPlatformSetup__(injectedMetadata);
|
||||
require('ui/chrome/api/controls').__newPlatformSetup__(chrome);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { basePathServiceMock } from './base_path/base_path_service.mock';
|
||||
export { chromeServiceMock } from './chrome/chrome_service.mock';
|
||||
export { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
|
||||
export { httpServiceMock } from './http/http_service.mock';
|
||||
|
|
|
@ -63,7 +63,6 @@ export function createPluginSetupContext<TSetup, TStart, TPluginsSetup, TPlugins
|
|||
): CoreSetup {
|
||||
return {
|
||||
http: deps.http,
|
||||
basePath: deps.basePath,
|
||||
chrome: deps.chrome,
|
||||
fatalErrors: deps.fatalErrors,
|
||||
i18n: deps.i18n,
|
||||
|
@ -91,9 +90,8 @@ export function createPluginStartContext<TSetup, TStart, TPluginsSetup, TPlugins
|
|||
application: {
|
||||
capabilities: deps.application.capabilities,
|
||||
},
|
||||
chrome: deps.chrome,
|
||||
basePath: deps.basePath,
|
||||
http: deps.http,
|
||||
chrome: deps.chrome,
|
||||
i18n: deps.i18n,
|
||||
notifications: deps.notifications,
|
||||
overlays: deps.overlays,
|
||||
|
|
|
@ -39,10 +39,9 @@ import { overlayServiceMock } from '../overlays/overlay_service.mock';
|
|||
import { chromeServiceMock } from '../chrome/chrome_service.mock';
|
||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { UiSettingsClient } from '../ui_settings';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { UiSettingsClient } from '../ui_settings';
|
||||
import { CoreSetup, CoreStart } from '..';
|
||||
|
||||
export let mockPluginInitializers: Map<PluginName, MockedPluginInitializer>;
|
||||
|
@ -74,11 +73,6 @@ beforeEach(() => {
|
|||
]);
|
||||
return metadata;
|
||||
})(),
|
||||
basePath: (function() {
|
||||
const basePath = basePathServiceMock.createSetupContract();
|
||||
basePath.addToPath.mockImplementation(path => path);
|
||||
return basePath;
|
||||
})(),
|
||||
chrome: chromeServiceMock.createSetupContract(),
|
||||
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
|
||||
http: httpServiceMock.createSetupContract(),
|
||||
|
@ -89,9 +83,8 @@ beforeEach(() => {
|
|||
mockSetupContext = omit(mockSetupDeps, 'application', 'injectedMetadata');
|
||||
mockStartDeps = {
|
||||
application: applicationServiceMock.createStartContract(),
|
||||
basePath: basePathServiceMock.createStartContract(),
|
||||
chrome: chromeServiceMock.createStartContract(),
|
||||
http: httpServiceMock.createStartContract(),
|
||||
chrome: chromeServiceMock.createStartContract(),
|
||||
i18n: i18nServiceMock.createStartContract(),
|
||||
injectedMetadata: injectedMetadataServiceMock.createStartContract(),
|
||||
notifications: notificationServiceMock.createStartContract(),
|
||||
|
@ -171,14 +164,14 @@ test('`PluginsService.setup` fails if any plugin instance does not have a setup
|
|||
);
|
||||
});
|
||||
|
||||
test('`PluginsService.setup` calls loadPluginBundles with basePath and plugins', async () => {
|
||||
test('`PluginsService.setup` calls loadPluginBundles with http and plugins', async () => {
|
||||
const pluginsService = new PluginsService(mockCoreContext);
|
||||
await pluginsService.setup(mockSetupDeps);
|
||||
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledTimes(3);
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.basePath.addToPath, 'pluginA');
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.basePath.addToPath, 'pluginB');
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.basePath.addToPath, 'pluginC');
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.http.prependBasePath, 'pluginA');
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.http.prependBasePath, 'pluginB');
|
||||
expect(mockLoadPluginBundle).toHaveBeenCalledWith(mockSetupDeps.http.prependBasePath, 'pluginC');
|
||||
});
|
||||
|
||||
test('`PluginsService.setup` initalizes plugins with CoreContext', async () => {
|
||||
|
|
|
@ -70,7 +70,7 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
|
|||
);
|
||||
|
||||
// Load plugin bundles
|
||||
await this.loadPluginBundles(deps.basePath.addToPath);
|
||||
await this.loadPluginBundles(deps.http.prependBasePath);
|
||||
|
||||
// Setup each plugin with required and optional plugin contracts
|
||||
const contracts = new Map<string, unknown>();
|
||||
|
|
|
@ -36,16 +36,6 @@ export interface ApplicationStart {
|
|||
mount: (mountHandler: Function) => void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface BasePathSetup {
|
||||
addToPath(path: string): string;
|
||||
get(): string;
|
||||
removeFromPath(path: string): string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type BasePathStart = BasePathSetup;
|
||||
|
||||
// @public
|
||||
export interface Capabilities {
|
||||
[key: string]: Record<string, boolean | Record<string, boolean>>;
|
||||
|
@ -118,8 +108,6 @@ export interface CoreContext {
|
|||
|
||||
// @public
|
||||
export interface CoreSetup {
|
||||
// (undocumented)
|
||||
basePath: BasePathSetup;
|
||||
// (undocumented)
|
||||
chrome: ChromeSetup;
|
||||
// (undocumented)
|
||||
|
@ -139,8 +127,6 @@ export interface CoreStart {
|
|||
// (undocumented)
|
||||
application: Pick<ApplicationStart, 'capabilities'>;
|
||||
// (undocumented)
|
||||
basePath: BasePathStart;
|
||||
// (undocumented)
|
||||
chrome: ChromeStart;
|
||||
// (undocumented)
|
||||
http: HttpStart;
|
||||
|
@ -180,13 +166,45 @@ export interface FatalErrorsSetup {
|
|||
get$: () => Rx.Observable<FatalErrorInfo>;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "HttpService" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type HttpSetup = ReturnType<HttpService['setup']>;
|
||||
export interface HttpServiceBase {
|
||||
// (undocumented)
|
||||
addLoadingCount(count$: Observable<number>): void;
|
||||
// (undocumented)
|
||||
delete: HttpHandler;
|
||||
// Warning: (ae-forgotten-export) The symbol "HttpHandler" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
fetch: HttpHandler;
|
||||
// (undocumented)
|
||||
get: HttpHandler;
|
||||
// (undocumented)
|
||||
getBasePath(): string;
|
||||
// (undocumented)
|
||||
getLoadingCount$(): Observable<number>;
|
||||
// (undocumented)
|
||||
head: HttpHandler;
|
||||
// (undocumented)
|
||||
options: HttpHandler;
|
||||
// (undocumented)
|
||||
patch: HttpHandler;
|
||||
// (undocumented)
|
||||
post: HttpHandler;
|
||||
// (undocumented)
|
||||
prependBasePath(path: string): string;
|
||||
// (undocumented)
|
||||
put: HttpHandler;
|
||||
// (undocumented)
|
||||
removeBasePath(path: string): string;
|
||||
// (undocumented)
|
||||
stop(): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type HttpStart = ReturnType<HttpService['start']>;
|
||||
export type HttpSetup = HttpServiceBase;
|
||||
|
||||
// @public (undocumented)
|
||||
export type HttpStart = HttpServiceBase;
|
||||
|
||||
// @public
|
||||
export interface I18nSetup {
|
||||
|
|
|
@ -8,9 +8,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"bar\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -21,9 +21,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"bar\\":\\"box\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -39,9 +39,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"a\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -52,9 +52,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"d\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -70,9 +70,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"bar\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -83,9 +83,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"box\\":\\"bar\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -101,9 +101,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"bar\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
@ -142,9 +142,9 @@ Array [
|
|||
"body": "{\\"changes\\":{\\"foo\\":\\"bar\\"}}",
|
||||
"credentials": "same-origin",
|
||||
"headers": Object {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json",
|
||||
"content-type": "application/json",
|
||||
"kbn-version": "v9.9.9",
|
||||
"kbn-version": "kibanaVersion",
|
||||
},
|
||||
"method": "POST",
|
||||
},
|
||||
|
|
|
@ -5,11 +5,35 @@ exports[`#setup constructs UiSettingsClient and UiSettingsApi: UiSettingsApi arg
|
|||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"addToPath": [MockFunction],
|
||||
"addLoadingCount": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"loadingCountObservable": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
"delete": [MockFunction],
|
||||
"fetch": [MockFunction],
|
||||
"get": [MockFunction],
|
||||
"removeFromPath": [MockFunction],
|
||||
"getBasePath": [MockFunction],
|
||||
"getLoadingCount$": [MockFunction],
|
||||
"head": [MockFunction],
|
||||
"options": [MockFunction],
|
||||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"prependBasePath": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeBasePath": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"kibanaVersion",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
|
|
|
@ -22,17 +22,18 @@ import fetchMock from 'fetch-mock/es5/client';
|
|||
import * as Rx from 'rxjs';
|
||||
import { takeUntil, toArray } from 'rxjs/operators';
|
||||
|
||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||
import { setup as httpSetup } from '../../../test_utils/public/http_test_setup';
|
||||
import { UiSettingsApi } from './ui_settings_api';
|
||||
|
||||
function setup() {
|
||||
const basePath = basePathServiceMock.createSetupContract();
|
||||
basePath.addToPath.mockImplementation(path => `/foo/bar${path}`);
|
||||
const { http } = httpSetup(injectedMetadata => {
|
||||
injectedMetadata.getBasePath.mockReturnValue('/foo/bar');
|
||||
});
|
||||
|
||||
const uiSettingsApi = new UiSettingsApi(basePath, 'v9.9.9');
|
||||
const uiSettingsApi = new UiSettingsApi(http);
|
||||
|
||||
return {
|
||||
basePath,
|
||||
http,
|
||||
uiSettingsApi,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { BasePathSetup } from '../base_path';
|
||||
import { HttpSetup } from '../http';
|
||||
import { UiSettingsState } from './types';
|
||||
|
||||
export interface UiSettingsApiResponse {
|
||||
|
@ -47,7 +47,7 @@ export class UiSettingsApi {
|
|||
|
||||
private readonly loadingCount$ = new BehaviorSubject(0);
|
||||
|
||||
constructor(private readonly basePath: BasePathSetup, private readonly kibanaVersion: string) {}
|
||||
constructor(private readonly http: HttpSetup) {}
|
||||
|
||||
/**
|
||||
* Adds a key+value that will be sent to the server ASAP. If a request is
|
||||
|
@ -115,6 +115,7 @@ export class UiSettingsApi {
|
|||
|
||||
try {
|
||||
this.sendInProgress = true;
|
||||
|
||||
changes.callback(
|
||||
undefined,
|
||||
await this.sendRequest('POST', '/api/kibana/settings', {
|
||||
|
@ -131,28 +132,24 @@ export class UiSettingsApi {
|
|||
|
||||
/**
|
||||
* Calls window.fetch() with the proper headers and error handling logic.
|
||||
*
|
||||
* TODO: migrate this to kfetch or whatever the new platform equivalent is once it exists
|
||||
*/
|
||||
private async sendRequest(method: string, path: string, body: any) {
|
||||
private async sendRequest(method: string, path: string, body: any): Promise<any> {
|
||||
try {
|
||||
this.loadingCount$.next(this.loadingCount$.getValue() + 1);
|
||||
const response = await fetch(this.basePath.addToPath(path), {
|
||||
|
||||
return await this.http.fetch(path, {
|
||||
method,
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
accept: 'application/json',
|
||||
'content-type': 'application/json',
|
||||
'kbn-version': this.kibanaVersion,
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
|
||||
if (response.status >= 300) {
|
||||
throw new Error(`Request failed with status code: ${response.status}`);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status >= 300) {
|
||||
throw new Error(`Request failed with status code: ${err.response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
throw err;
|
||||
} finally {
|
||||
this.loadingCount$.next(this.loadingCount$.getValue() - 1);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
import { MockUiSettingsApi, MockUiSettingsClient } from './ui_settings_service.test.mocks';
|
||||
|
||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { UiSettingsService } from './ui_settings_service';
|
||||
|
@ -29,7 +28,6 @@ const httpSetup = httpServiceMock.createSetupContract();
|
|||
const defaultDeps = {
|
||||
http: httpSetup,
|
||||
injectedMetadata: injectedMetadataServiceMock.createSetupContract(),
|
||||
basePath: basePathServiceMock.createSetupContract(),
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { BasePathSetup } from '../base_path';
|
||||
import { HttpSetup } from '../http';
|
||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
||||
|
||||
|
@ -27,7 +26,6 @@ import { UiSettingsClient } from './ui_settings_client';
|
|||
interface UiSettingsServiceDeps {
|
||||
http: HttpSetup;
|
||||
injectedMetadata: InjectedMetadataSetup;
|
||||
basePath: BasePathSetup;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -35,8 +33,8 @@ export class UiSettingsService {
|
|||
private uiSettingsApi?: UiSettingsApi;
|
||||
private uiSettingsClient?: UiSettingsClient;
|
||||
|
||||
public setup({ http, injectedMetadata, basePath }: UiSettingsServiceDeps): UiSettingsSetup {
|
||||
this.uiSettingsApi = new UiSettingsApi(basePath, injectedMetadata.getKibanaVersion());
|
||||
public setup({ http, injectedMetadata }: UiSettingsServiceDeps): UiSettingsSetup {
|
||||
this.uiSettingsApi = new UiSettingsApi(http);
|
||||
http.addLoadingCount(this.uiSettingsApi.getLoadingCount$());
|
||||
|
||||
// TODO: Migrate away from legacyMetadata https://github.com/elastic/kibana/issues/22779
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { createKfetch } from 'ui/kfetch/kfetch';
|
||||
import { setup } from 'test_utils/kfetch_test_setup';
|
||||
import { setup } from 'test_utils/http_test_setup';
|
||||
|
||||
const mockIndexPattern = {
|
||||
id: '1234',
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { basePathServiceMock } from '../../../../../core/public/mocks';
|
||||
import { httpServiceMock } from '../../../../../core/public/mocks';
|
||||
import { __newPlatformSetup__, initChromeBasePathApi } from './base_path';
|
||||
|
||||
function initChrome() {
|
||||
|
@ -26,39 +26,43 @@ function initChrome() {
|
|||
return chrome;
|
||||
}
|
||||
|
||||
const newPlatformBasePath = basePathServiceMock.createSetupContract();
|
||||
__newPlatformSetup__(newPlatformBasePath);
|
||||
const newPlatformHttp = httpServiceMock.createSetupContract();
|
||||
__newPlatformSetup__(newPlatformHttp);
|
||||
|
||||
newPlatformHttp.getBasePath.mockImplementation(() => 'gotBasePath');
|
||||
newPlatformHttp.prependBasePath.mockImplementation(() => 'addedToPath');
|
||||
newPlatformHttp.removeBasePath.mockImplementation(() => 'removedFromPath');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('#getBasePath()', () => {
|
||||
it('proxies to newPlatformBasePath.get()', () => {
|
||||
it('proxies to newPlatformHttp.getBasePath()', () => {
|
||||
const chrome = initChrome();
|
||||
expect(newPlatformBasePath.get).not.toHaveBeenCalled();
|
||||
expect(chrome.getBasePath()).toBe('get');
|
||||
expect(newPlatformBasePath.get).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformBasePath.get).toHaveBeenCalledWith();
|
||||
expect(newPlatformHttp.prependBasePath).not.toHaveBeenCalled();
|
||||
expect(chrome.getBasePath()).toBe('gotBasePath');
|
||||
expect(newPlatformHttp.getBasePath).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformHttp.getBasePath).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addBasePath()', () => {
|
||||
it('proxies to newPlatformBasePath.addToPath(path)', () => {
|
||||
it('proxies to newPlatformHttp.prependBasePath(path)', () => {
|
||||
const chrome = initChrome();
|
||||
expect(newPlatformBasePath.addToPath).not.toHaveBeenCalled();
|
||||
expect(chrome.addBasePath('foo/bar')).toBe('addToPath');
|
||||
expect(newPlatformBasePath.addToPath).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformBasePath.addToPath).toHaveBeenCalledWith('foo/bar');
|
||||
expect(newPlatformHttp.prependBasePath).not.toHaveBeenCalled();
|
||||
expect(chrome.addBasePath('foo/bar')).toBe('addedToPath');
|
||||
expect(newPlatformHttp.prependBasePath).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformHttp.prependBasePath).toHaveBeenCalledWith('foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeBasePath', () => {
|
||||
it('proxies to newPlatformBasePath.removeFromPath(path)', () => {
|
||||
it('proxies to newPlatformBasePath.removeBasePath(path)', () => {
|
||||
const chrome = initChrome();
|
||||
expect(newPlatformBasePath.removeFromPath).not.toHaveBeenCalled();
|
||||
expect(chrome.removeBasePath('foo/bar')).toBe('removeFromPath');
|
||||
expect(newPlatformBasePath.removeFromPath).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformBasePath.removeFromPath).toHaveBeenCalledWith('foo/bar');
|
||||
expect(newPlatformHttp.removeBasePath).not.toHaveBeenCalled();
|
||||
expect(chrome.removeBasePath('foo/bar')).toBe('removedFromPath');
|
||||
expect(newPlatformHttp.removeBasePath).toHaveBeenCalledTimes(1);
|
||||
expect(newPlatformHttp.removeBasePath).toHaveBeenCalledWith('foo/bar');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,19 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { BasePathSetup } from '../../../../../core/public';
|
||||
let newPlatformBasePath: BasePathSetup;
|
||||
import { HttpSetup } from '../../../../../core/public';
|
||||
|
||||
export function __newPlatformSetup__(instance: BasePathSetup) {
|
||||
if (newPlatformBasePath) {
|
||||
throw new Error('ui/chrome/api/base_path is already initialized');
|
||||
let newPlatformHttp: HttpSetup;
|
||||
|
||||
export function __newPlatformSetup__(instance: HttpSetup) {
|
||||
if (newPlatformHttp) {
|
||||
throw new Error('ui/chrome/api/http is already initialized');
|
||||
}
|
||||
|
||||
newPlatformBasePath = instance;
|
||||
newPlatformHttp = instance;
|
||||
}
|
||||
|
||||
export function initChromeBasePathApi(chrome: { [key: string]: any }) {
|
||||
chrome.getBasePath = () => newPlatformBasePath.get();
|
||||
chrome.addBasePath = (path: string) => newPlatformBasePath.addToPath(path);
|
||||
chrome.removeBasePath = (path: string) => newPlatformBasePath.removeFromPath(path);
|
||||
chrome.getBasePath = newPlatformHttp.getBasePath.bind(newPlatformHttp);
|
||||
chrome.addBasePath = newPlatformHttp.prependBasePath.bind(newPlatformHttp);
|
||||
chrome.removeBasePath = newPlatformHttp.removeBasePath.bind(newPlatformHttp);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// @ts-ignore
|
||||
import fetchMock from 'fetch-mock/es5/client';
|
||||
import { __newPlatformSetup__, kfetch } from '../kfetch';
|
||||
import { setup } from '../../../../test_utils/public/kfetch_test_setup';
|
||||
import { setup } from '../../../../test_utils/public/http_test_setup';
|
||||
|
||||
import { isAutoCreateIndexError } from './error_auto_create_index';
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import { join } from 'path';
|
|||
import { __newPlatformSetup__, addInterceptor, kfetch, KFetchOptions } from '.';
|
||||
import { Interceptor, resetInterceptors, withDefaultOptions } from './kfetch';
|
||||
import { KFetchError } from './kfetch_error';
|
||||
import { setup } from '../../../../test_utils/public/kfetch_test_setup';
|
||||
import { setup } from '../../../../test_utils/public/http_test_setup';
|
||||
|
||||
describe('kfetch', () => {
|
||||
beforeAll(() => {
|
||||
|
|
|
@ -79,7 +79,7 @@ export const configureAppAngularModule = (angularModule: IModule) => {
|
|||
|
||||
const getEsUrl = (newPlatform: InternalCoreSetup) => {
|
||||
const a = document.createElement('a');
|
||||
a.href = newPlatform.basePath.addToPath('/elasticsearch');
|
||||
a.href = newPlatform.http.prependBasePath('/elasticsearch');
|
||||
const protocolPort = /https/.test(a.protocol) ? 443 : 80;
|
||||
const port = a.port || protocolPort;
|
||||
return {
|
||||
|
|
|
@ -19,20 +19,29 @@
|
|||
|
||||
/* eslint-disable @kbn/eslint/no-restricted-paths */
|
||||
import { HttpService } from '../../core/public/http';
|
||||
import { BasePathService } from '../../core/public/base_path';
|
||||
import { fatalErrorsServiceMock } from '../../core/public/fatal_errors/fatal_errors_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../../core/public/injected_metadata/injected_metadata_service.mock';
|
||||
/* eslint-enable @kbn/eslint/no-restricted-paths */
|
||||
|
||||
export function setup() {
|
||||
const httpService = new HttpService();
|
||||
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
|
||||
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
|
||||
export type SetupTap = (
|
||||
injectedMetadata: ReturnType<typeof injectedMetadataServiceMock.createSetupContract>,
|
||||
fatalErrors: ReturnType<typeof fatalErrorsServiceMock.createSetupContract>
|
||||
) => void;
|
||||
|
||||
const defaultTap: SetupTap = (
|
||||
injectedMetadata: ReturnType<typeof injectedMetadataServiceMock.createSetupContract>
|
||||
) => {
|
||||
injectedMetadata.getBasePath.mockReturnValue('http://localhost/myBase');
|
||||
};
|
||||
|
||||
const basePath = new BasePathService().setup({ injectedMetadata });
|
||||
const http = httpService.setup({ basePath, fatalErrors, injectedMetadata });
|
||||
export function setup(tap: SetupTap = defaultTap) {
|
||||
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
|
||||
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
|
||||
|
||||
return { httpService, fatalErrors, http };
|
||||
tap(injectedMetadata, fatalErrors);
|
||||
|
||||
const httpService = new HttpService();
|
||||
const http = httpService.setup({ fatalErrors, injectedMetadata });
|
||||
|
||||
return { httpService, injectedMetadata, fatalErrors, http };
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue