mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
parent
f33f82a45b
commit
68f77d935f
80 changed files with 1295 additions and 1256 deletions
|
@ -1,37 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [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 |
|
||||
| --- | --- | --- |
|
||||
| [anonymousPaths](./kibana-plugin-public.httpservicebase.anonymouspaths.md) | <code>IAnonymousPaths</code> | APIs for denoting certain paths for not requiring authentication |
|
||||
| [basePath](./kibana-plugin-public.httpservicebase.basepath.md) | <code>IBasePath</code> | APIs for manipulating the basePath on URL segments. |
|
||||
| [delete](./kibana-plugin-public.httpservicebase.delete.md) | <code>HttpHandler</code> | Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [fetch](./kibana-plugin-public.httpservicebase.fetch.md) | <code>HttpHandler</code> | Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [get](./kibana-plugin-public.httpservicebase.get.md) | <code>HttpHandler</code> | Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [head](./kibana-plugin-public.httpservicebase.head.md) | <code>HttpHandler</code> | Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [options](./kibana-plugin-public.httpservicebase.options.md) | <code>HttpHandler</code> | Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [patch](./kibana-plugin-public.httpservicebase.patch.md) | <code>HttpHandler</code> | Makes an HTTP request with the PATCH method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [post](./kibana-plugin-public.httpservicebase.post.md) | <code>HttpHandler</code> | Makes an HTTP request with the POST method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [put](./kibana-plugin-public.httpservicebase.put.md) | <code>HttpHandler</code> | Makes an HTTP request with the PUT method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [addLoadingCount(countSource$)](./kibana-plugin-public.httpservicebase.addloadingcount.md) | Adds a new source of loading counts. Used to show the global loading indicator when sum of all observed counts are more than 0. |
|
||||
| [getLoadingCount$()](./kibana-plugin-public.httpservicebase.getloadingcount_.md) | Get the sum of all loading count sources as a single Observable. |
|
||||
| [intercept(interceptor)](./kibana-plugin-public.httpservicebase.intercept.md) | Adds a new [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) to the global HTTP client. |
|
||||
| [removeAllInterceptors()](./kibana-plugin-public.httpservicebase.removeallinterceptors.md) | Removes all configured interceptors. |
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [removeAllInterceptors](./kibana-plugin-public.httpservicebase.removeallinterceptors.md)
|
||||
|
||||
## HttpServiceBase.removeAllInterceptors() method
|
||||
|
||||
Removes all configured interceptors.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
removeAllInterceptors(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [addLoadingCount](./kibana-plugin-public.httpservicebase.addloadingcount.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [addLoadingCountSource](./kibana-plugin-public.httpsetup.addloadingcountsource.md)
|
||||
|
||||
## HttpServiceBase.addLoadingCount() method
|
||||
## HttpSetup.addLoadingCountSource() method
|
||||
|
||||
Adds a new source of loading counts. Used to show the global loading indicator when sum of all observed counts are more than 0.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
addLoadingCount(countSource$: Observable<number>): void;
|
||||
addLoadingCountSource(countSource$: Observable<number>): void;
|
||||
```
|
||||
|
||||
## Parameters
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [anonymousPaths](./kibana-plugin-public.httpservicebase.anonymouspaths.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [anonymousPaths](./kibana-plugin-public.httpsetup.anonymouspaths.md)
|
||||
|
||||
## HttpServiceBase.anonymousPaths property
|
||||
## HttpSetup.anonymousPaths property
|
||||
|
||||
APIs for denoting certain paths for not requiring authentication
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [basePath](./kibana-plugin-public.httpservicebase.basepath.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [basePath](./kibana-plugin-public.httpsetup.basepath.md)
|
||||
|
||||
## HttpServiceBase.basePath property
|
||||
## HttpSetup.basePath property
|
||||
|
||||
APIs for manipulating the basePath on URL segments.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [delete](./kibana-plugin-public.httpservicebase.delete.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [delete](./kibana-plugin-public.httpsetup.delete.md)
|
||||
|
||||
## HttpServiceBase.delete property
|
||||
## HttpSetup.delete property
|
||||
|
||||
Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [fetch](./kibana-plugin-public.httpservicebase.fetch.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [fetch](./kibana-plugin-public.httpsetup.fetch.md)
|
||||
|
||||
## HttpServiceBase.fetch property
|
||||
## HttpSetup.fetch property
|
||||
|
||||
Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [get](./kibana-plugin-public.httpservicebase.get.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [get](./kibana-plugin-public.httpsetup.get.md)
|
||||
|
||||
## HttpServiceBase.get property
|
||||
## HttpSetup.get property
|
||||
|
||||
Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [getLoadingCount$](./kibana-plugin-public.httpservicebase.getloadingcount_.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [getLoadingCount$](./kibana-plugin-public.httpsetup.getloadingcount_.md)
|
||||
|
||||
## HttpServiceBase.getLoadingCount$() method
|
||||
## HttpSetup.getLoadingCount$() method
|
||||
|
||||
Get the sum of all loading count sources as a single Observable.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [head](./kibana-plugin-public.httpservicebase.head.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [head](./kibana-plugin-public.httpsetup.head.md)
|
||||
|
||||
## HttpServiceBase.head property
|
||||
## HttpSetup.head property
|
||||
|
||||
Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [intercept](./kibana-plugin-public.httpservicebase.intercept.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [intercept](./kibana-plugin-public.httpsetup.intercept.md)
|
||||
|
||||
## HttpServiceBase.intercept() method
|
||||
## HttpSetup.intercept() method
|
||||
|
||||
Adds a new [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) to the global HTTP client.
|
||||
|
|
@ -2,12 +2,35 @@
|
|||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md)
|
||||
|
||||
## HttpSetup type
|
||||
## HttpSetup interface
|
||||
|
||||
See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md)
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpSetup = HttpServiceBase;
|
||||
export interface HttpSetup
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [anonymousPaths](./kibana-plugin-public.httpsetup.anonymouspaths.md) | <code>IAnonymousPaths</code> | APIs for denoting certain paths for not requiring authentication |
|
||||
| [basePath](./kibana-plugin-public.httpsetup.basepath.md) | <code>IBasePath</code> | APIs for manipulating the basePath on URL segments. |
|
||||
| [delete](./kibana-plugin-public.httpsetup.delete.md) | <code>HttpHandler</code> | Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [fetch](./kibana-plugin-public.httpsetup.fetch.md) | <code>HttpHandler</code> | Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [get](./kibana-plugin-public.httpsetup.get.md) | <code>HttpHandler</code> | Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [head](./kibana-plugin-public.httpsetup.head.md) | <code>HttpHandler</code> | Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [options](./kibana-plugin-public.httpsetup.options.md) | <code>HttpHandler</code> | Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [patch](./kibana-plugin-public.httpsetup.patch.md) | <code>HttpHandler</code> | Makes an HTTP request with the PATCH method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [post](./kibana-plugin-public.httpsetup.post.md) | <code>HttpHandler</code> | Makes an HTTP request with the POST method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
| [put](./kibana-plugin-public.httpsetup.put.md) | <code>HttpHandler</code> | Makes an HTTP request with the PUT method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [addLoadingCountSource(countSource$)](./kibana-plugin-public.httpsetup.addloadingcountsource.md) | Adds a new source of loading counts. Used to show the global loading indicator when sum of all observed counts are more than 0. |
|
||||
| [getLoadingCount$()](./kibana-plugin-public.httpsetup.getloadingcount_.md) | Get the sum of all loading count sources as a single Observable. |
|
||||
| [intercept(interceptor)](./kibana-plugin-public.httpsetup.intercept.md) | Adds a new [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) to the global HTTP client. |
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [options](./kibana-plugin-public.httpservicebase.options.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [options](./kibana-plugin-public.httpsetup.options.md)
|
||||
|
||||
## HttpServiceBase.options property
|
||||
## HttpSetup.options property
|
||||
|
||||
Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [patch](./kibana-plugin-public.httpservicebase.patch.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [patch](./kibana-plugin-public.httpsetup.patch.md)
|
||||
|
||||
## HttpServiceBase.patch property
|
||||
## HttpSetup.patch property
|
||||
|
||||
Makes an HTTP request with the PATCH method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [post](./kibana-plugin-public.httpservicebase.post.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [post](./kibana-plugin-public.httpsetup.post.md)
|
||||
|
||||
## HttpServiceBase.post property
|
||||
## HttpSetup.post property
|
||||
|
||||
Makes an HTTP request with the POST method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [put](./kibana-plugin-public.httpservicebase.put.md)
|
||||
[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpSetup](./kibana-plugin-public.httpsetup.md) > [put](./kibana-plugin-public.httpsetup.put.md)
|
||||
|
||||
## HttpServiceBase.put property
|
||||
## HttpSetup.put property
|
||||
|
||||
Makes an HTTP request with the PUT method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options.
|
||||
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
## HttpStart type
|
||||
|
||||
See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md)
|
||||
See [HttpSetup](./kibana-plugin-public.httpsetup.md)
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HttpStart = HttpServiceBase;
|
||||
export declare type HttpStart = HttpSetup;
|
||||
```
|
||||
|
|
|
@ -56,7 +56,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) | |
|
||||
| [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) | An object that may define global interceptor functions for different parts of the request and response lifecycle. See [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md)<!-- -->. |
|
||||
| [HttpRequestInit](./kibana-plugin-public.httprequestinit.md) | Fetch API options available to [HttpHandler](./kibana-plugin-public.httphandler.md)<!-- -->s. |
|
||||
| [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | |
|
||||
| [HttpSetup](./kibana-plugin-public.httpsetup.md) | |
|
||||
| [I18nStart](./kibana-plugin-public.i18nstart.md) | I18nStart.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. |
|
||||
| [IAnonymousPaths](./kibana-plugin-public.ianonymouspaths.md) | APIs for denoting paths as not requiring authentication |
|
||||
| [IBasePath](./kibana-plugin-public.ibasepath.md) | APIs for manipulating the basePath on URL segments. |
|
||||
|
@ -118,8 +118,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [HandlerContextType](./kibana-plugin-public.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md) to represent the type of the context. |
|
||||
| [HandlerFunction](./kibana-plugin-public.handlerfunction.md) | A function that accepts a context object and an optional number of additional arguments. Used for the generic types in [IContextContainer](./kibana-plugin-public.icontextcontainer.md) |
|
||||
| [HandlerParameters](./kibana-plugin-public.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md)<!-- -->, excluding the [HandlerContextType](./kibana-plugin-public.handlercontexttype.md)<!-- -->. |
|
||||
| [HttpSetup](./kibana-plugin-public.httpsetup.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) |
|
||||
| [HttpStart](./kibana-plugin-public.httpstart.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) |
|
||||
| [HttpStart](./kibana-plugin-public.httpstart.md) | See [HttpSetup](./kibana-plugin-public.httpsetup.md) |
|
||||
| [IContextProvider](./kibana-plugin-public.icontextprovider.md) | A function that returns a context value for a specific key of given context type. |
|
||||
| [IToasts](./kibana-plugin-public.itoasts.md) | Methods for adding and removing global toast messages. See [ToastsApi](./kibana-plugin-public.toastsapi.md)<!-- -->. |
|
||||
| [MountPoint](./kibana-plugin-public.mountpoint.md) | A function that should mount DOM content inside the provided container element and return a handler to unmount it. |
|
||||
|
|
|
@ -211,7 +211,7 @@ export class CoreSystem {
|
|||
const injectedMetadata = await this.injectedMetadata.start();
|
||||
const uiSettings = await this.uiSettings.start();
|
||||
const docLinks = await this.docLinks.start({ injectedMetadata });
|
||||
const http = await this.http.start({ injectedMetadata, fatalErrors: this.fatalErrorsSetup });
|
||||
const http = await this.http.start({ injectedMetadata, fatalErrors: this.fatalErrorsSetup! });
|
||||
const savedObjects = await this.savedObjects.start({ http });
|
||||
const i18n = await this.i18n.start();
|
||||
const application = await this.application.start({ http, injectedMetadata });
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`addLoadingCount() adds a fatal error if source observable emits a negative number 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
[Error: Observables passed to loadingCount.add() must only emit positive numbers],
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`addLoadingCount() adds a fatal error if source observables emit an error 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
[Error: foo bar],
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`getLoadingCount$() emits 0 initially, the right count when sources emit their own count, and ends with zero 1`] = `
|
||||
Array [
|
||||
0,
|
||||
100,
|
||||
110,
|
||||
111,
|
||||
11,
|
||||
21,
|
||||
20,
|
||||
0,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`getLoadingCount$() only emits when loading count changes 1`] = `
|
||||
Array [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]
|
||||
`;
|
|
@ -1,107 +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 { AnonymousPaths } from './anonymous_paths';
|
||||
import { BasePath } from './base_path_service';
|
||||
|
||||
describe('#register', () => {
|
||||
it(`allows paths that don't start with /`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('bar');
|
||||
});
|
||||
|
||||
it(`allows paths that end with '/'`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isAnonymous', () => {
|
||||
it('returns true for registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a trailing slash, but call "isAnonymous" with no trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar/');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a trailing slash, but call "isAnonymous" with a trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" without a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" with a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths whose capitalization is different', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/BAR');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for other paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for sub-paths of registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/baz')).toBe(false);
|
||||
});
|
||||
});
|
|
@ -1,53 +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 { IAnonymousPaths, IBasePath } from 'src/core/public';
|
||||
|
||||
export class AnonymousPaths implements IAnonymousPaths {
|
||||
private readonly paths = new Set<string>();
|
||||
|
||||
constructor(private basePath: IBasePath) {}
|
||||
|
||||
public isAnonymous(path: string): boolean {
|
||||
const pathWithoutBasePath = this.basePath.remove(path);
|
||||
return this.paths.has(this.normalizePath(pathWithoutBasePath));
|
||||
}
|
||||
|
||||
public register(path: string) {
|
||||
this.paths.add(this.normalizePath(path));
|
||||
}
|
||||
|
||||
private normalizePath(path: string) {
|
||||
// always lower-case it
|
||||
let normalized = path.toLowerCase();
|
||||
|
||||
// remove the slash from the end
|
||||
if (normalized.endsWith('/')) {
|
||||
normalized = normalized.slice(0, normalized.length - 1);
|
||||
}
|
||||
|
||||
// put a slash at the start
|
||||
if (!normalized.startsWith('/')) {
|
||||
normalized = `/${normalized}`;
|
||||
}
|
||||
|
||||
// it's normalized!!!
|
||||
return normalized;
|
||||
}
|
||||
}
|
109
src/core/public/http/anonymous_paths_service.test.ts
Normal file
109
src/core/public/http/anonymous_paths_service.test.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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 { AnonymousPathsService } from './anonymous_paths_service';
|
||||
import { BasePath } from './base_path';
|
||||
|
||||
describe('#setup()', () => {
|
||||
describe('#register', () => {
|
||||
it(`allows paths that don't start with /`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('bar');
|
||||
});
|
||||
|
||||
it(`allows paths that end with '/'`, () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isAnonymous', () => {
|
||||
it('returns true for registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a trailing slash, but call "isAnonymous" with no trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar/');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a trailing slash, but call "isAnonymous" with a trailing slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered without a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" without a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('when there is no basePath and calling "isAnonymous" with a starting slash, returns true for paths registered with a starting slash', () => {
|
||||
const basePath = new BasePath('/');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true for paths whose capitalization is different', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/BAR');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for other paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/foo')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for sub-paths of registered paths', () => {
|
||||
const basePath = new BasePath('/foo');
|
||||
const anonymousPaths = new AnonymousPathsService().setup({ basePath });
|
||||
anonymousPaths.register('/bar');
|
||||
expect(anonymousPaths.isAnonymous('/foo/bar/baz')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
68
src/core/public/http/anonymous_paths_service.ts
Normal file
68
src/core/public/http/anonymous_paths_service.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 { IAnonymousPaths, IBasePath } from 'src/core/public';
|
||||
import { CoreService } from '../../types';
|
||||
|
||||
interface Deps {
|
||||
basePath: IBasePath;
|
||||
}
|
||||
|
||||
export class AnonymousPathsService implements CoreService<IAnonymousPaths, IAnonymousPaths> {
|
||||
private readonly paths = new Set<string>();
|
||||
|
||||
public setup({ basePath }: Deps) {
|
||||
return {
|
||||
isAnonymous: (path: string): boolean => {
|
||||
const pathWithoutBasePath = basePath.remove(path);
|
||||
return this.paths.has(normalizePath(pathWithoutBasePath));
|
||||
},
|
||||
|
||||
register: (path: string) => {
|
||||
this.paths.add(normalizePath(path));
|
||||
},
|
||||
|
||||
normalizePath,
|
||||
};
|
||||
}
|
||||
|
||||
public start(deps: Deps) {
|
||||
return this.setup(deps);
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
const normalizePath = (path: string) => {
|
||||
// always lower-case it
|
||||
let normalized = path.toLowerCase();
|
||||
|
||||
// remove the slash from the end
|
||||
if (normalized.endsWith('/')) {
|
||||
normalized = normalized.slice(0, normalized.length - 1);
|
||||
}
|
||||
|
||||
// put a slash at the start
|
||||
if (!normalized.startsWith('/')) {
|
||||
normalized = `/${normalized}`;
|
||||
}
|
||||
|
||||
// it's normalized!!!
|
||||
return normalized;
|
||||
};
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { BasePath } from './base_path_service';
|
||||
import { BasePath } from './base_path';
|
||||
|
||||
describe('BasePath', () => {
|
||||
describe('#get()', () => {
|
569
src/core/public/http/fetch.test.ts
Normal file
569
src/core/public/http/fetch.test.ts
Normal file
|
@ -0,0 +1,569 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import fetchMock from 'fetch-mock/es5/client';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
import { Fetch } from './fetch';
|
||||
import { BasePath } from './base_path';
|
||||
import { IHttpResponse } from './types';
|
||||
|
||||
function delay<T>(duration: number) {
|
||||
return new Promise<T>(r => setTimeout(r, duration));
|
||||
}
|
||||
|
||||
describe('Fetch', () => {
|
||||
const fetchInstance = new Fetch({
|
||||
basePath: new BasePath('http://localhost/myBase'),
|
||||
kibanaVersion: 'VERSION',
|
||||
});
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
describe('http requests', () => {
|
||||
it('should use supplied request method', async () => {
|
||||
fetchMock.post('*', {});
|
||||
await fetchInstance.fetch('/my/path', { method: 'POST' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should use supplied Content-Type', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path', { headers: { 'Content-Type': 'CustomContentType' } });
|
||||
|
||||
expect(fetchMock.lastOptions()!.headers).toMatchObject({
|
||||
'content-type': 'CustomContentType',
|
||||
});
|
||||
});
|
||||
|
||||
it('should use supplied pathname and querystring', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path', { query: { a: 'b' } });
|
||||
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path?a=b');
|
||||
});
|
||||
|
||||
it('should use supplied headers', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path', {
|
||||
headers: { myHeader: 'foo' },
|
||||
});
|
||||
|
||||
expect(fetchMock.lastOptions()!.headers).toEqual({
|
||||
'content-type': 'application/json',
|
||||
'kbn-version': 'VERSION',
|
||||
myheader: 'foo',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return response', async () => {
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
const json = await fetchInstance.fetch('/my/path');
|
||||
expect(json).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should prepend url with basepath by default', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path');
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path');
|
||||
});
|
||||
|
||||
it('should not prepend url with basepath when disabled', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('my/path', { prependBasePath: false });
|
||||
expect(fetchMock.lastUrl()).toBe('/my/path');
|
||||
});
|
||||
|
||||
it('should not include undefined query params', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path', { query: { a: undefined } });
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path');
|
||||
});
|
||||
|
||||
it('should make request with defaults', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.fetch('/my/path');
|
||||
|
||||
const lastCall = fetchMock.lastCall();
|
||||
|
||||
expect(lastCall!.request.credentials).toBe('same-origin');
|
||||
expect(lastCall![1]).toMatchObject({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-version': 'VERSION',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose detailed response object when asResponse = true', async () => {
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
|
||||
const response = await fetchInstance.fetch('/my/path', { asResponse: true });
|
||||
|
||||
expect(response.request).toBeInstanceOf(Request);
|
||||
expect(response.response).toBeInstanceOf(Response);
|
||||
expect(response.body).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should reject on network error', async () => {
|
||||
expect.assertions(1);
|
||||
fetchMock.get('*', { status: 500 });
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow(/Internal Server Error/);
|
||||
});
|
||||
|
||||
it('should contain error message when throwing response', async () => {
|
||||
fetchMock.get('*', { status: 404, body: { foo: 'bar' } });
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).rejects.toMatchObject({
|
||||
message: 'Not Found',
|
||||
body: {
|
||||
foo: 'bar',
|
||||
},
|
||||
response: {
|
||||
status: 404,
|
||||
url: 'http://localhost/myBase/my/path',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should support get() helper', async () => {
|
||||
fetchMock.get('*', {});
|
||||
await fetchInstance.get('/my/path', { method: 'POST' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should support head() helper', async () => {
|
||||
fetchMock.head('*', {});
|
||||
await fetchInstance.head('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('HEAD');
|
||||
});
|
||||
|
||||
it('should support post() helper', async () => {
|
||||
fetchMock.post('*', {});
|
||||
await fetchInstance.post('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should support put() helper', async () => {
|
||||
fetchMock.put('*', {});
|
||||
await fetchInstance.put('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('PUT');
|
||||
});
|
||||
|
||||
it('should support patch() helper', async () => {
|
||||
fetchMock.patch('*', {});
|
||||
await fetchInstance.patch('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('PATCH');
|
||||
});
|
||||
|
||||
it('should support delete() helper', async () => {
|
||||
fetchMock.delete('*', {});
|
||||
await fetchInstance.delete('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('DELETE');
|
||||
});
|
||||
|
||||
it('should support options() helper', async () => {
|
||||
fetchMock.mock('*', { method: 'OPTIONS' });
|
||||
await fetchInstance.options('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('OPTIONS');
|
||||
});
|
||||
|
||||
it('should make requests for NDJSON content', async () => {
|
||||
const content = readFileSync(join(__dirname, '_import_objects.ndjson'), {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
const body = new FormData();
|
||||
|
||||
body.append('file', content);
|
||||
fetchMock.post('*', {
|
||||
body: content,
|
||||
headers: { 'Content-Type': 'application/ndjson' },
|
||||
});
|
||||
|
||||
const data = await fetchInstance.post('/my/path', {
|
||||
body,
|
||||
headers: {
|
||||
'Content-Type': undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(data).toBeInstanceOf(Blob);
|
||||
|
||||
const ndjson = await new Response(data).text();
|
||||
|
||||
expect(ndjson).toEqual(content);
|
||||
});
|
||||
});
|
||||
|
||||
describe('interception', () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
fetchInstance.removeAllInterceptors();
|
||||
});
|
||||
|
||||
it('should make request and receive response', async () => {
|
||||
fetchInstance.intercept({});
|
||||
|
||||
const body = await fetchInstance.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should be able to manipulate request instance', async () => {
|
||||
fetchInstance.intercept({
|
||||
request(request) {
|
||||
request.headers.set('Content-Type', 'CustomContentType');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request(request) {
|
||||
return new Request('/my/route', request);
|
||||
},
|
||||
});
|
||||
|
||||
const body = await fetchInstance.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.lastOptions()!.headers).toMatchObject({
|
||||
'content-type': 'CustomContentType',
|
||||
});
|
||||
expect(fetchMock.lastUrl()).toBe('/my/route');
|
||||
});
|
||||
|
||||
it('should call interceptors in correct order', async () => {
|
||||
const order: string[] = [];
|
||||
|
||||
fetchInstance.intercept({
|
||||
request() {
|
||||
order.push('Request 1');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 1');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request() {
|
||||
order.push('Request 2');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 2');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request() {
|
||||
order.push('Request 3');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 3');
|
||||
},
|
||||
});
|
||||
|
||||
const body = await fetchInstance.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
expect(order).toEqual([
|
||||
'Request 3',
|
||||
'Request 2',
|
||||
'Request 1',
|
||||
'Response 1',
|
||||
'Response 2',
|
||||
'Response 3',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during request', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({ request: unusedSpy, response: unusedSpy });
|
||||
fetchInstance.intercept({
|
||||
request(request, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
response: unusedSpy,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request: usedSpy,
|
||||
response: unusedSpy,
|
||||
});
|
||||
|
||||
fetchInstance.fetch('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock.called()).toBe(false);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during response', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({
|
||||
request: usedSpy,
|
||||
response(response, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({ request: usedSpy, response: unusedSpy });
|
||||
fetchInstance.intercept({ request: usedSpy, response: unusedSpy });
|
||||
|
||||
fetchInstance.fetch('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(3);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during responseError', async () => {
|
||||
fetchMock.post('*', 401);
|
||||
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({
|
||||
responseError(response, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({ response: unusedSpy, responseError: unusedSpy });
|
||||
|
||||
fetchInstance.post('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should not fetch if exception occurs during request interception', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({
|
||||
request: unusedSpy,
|
||||
requestError: usedSpy,
|
||||
response: unusedSpy,
|
||||
responseError: unusedSpy,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request() {
|
||||
throw new Error('Interception Error');
|
||||
},
|
||||
response: unusedSpy,
|
||||
responseError: unusedSpy,
|
||||
});
|
||||
fetchInstance.intercept({ request: usedSpy, response: unusedSpy, responseError: unusedSpy });
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow(/Interception Error/);
|
||||
expect(fetchMock.called()).toBe(false);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should succeed if request throws but caught by interceptor', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({
|
||||
request: unusedSpy,
|
||||
requestError({ request }) {
|
||||
return new Request('/my/route', request);
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request() {
|
||||
throw new Error('Interception Error');
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
fetchInstance.intercept({ request: usedSpy, response: usedSpy });
|
||||
|
||||
await expect(fetchInstance.fetch('/my/route')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('should accumulate request information', async () => {
|
||||
const routes = ['alpha', 'beta', 'gamma'];
|
||||
const createRequest = jest.fn(
|
||||
(request: Request) => new Request(`/api/${routes.shift()}`, request)
|
||||
);
|
||||
|
||||
fetchInstance.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
requestError(httpErrorRequest) {
|
||||
return httpErrorRequest.request;
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request(request) {
|
||||
throw new Error('Invalid');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
|
||||
await expect(fetchInstance.fetch('/my/route')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(routes.length).toBe(0);
|
||||
expect(createRequest.mock.calls[0][0].url).toContain('/my/route');
|
||||
expect(createRequest.mock.calls[1][0].url).toContain('/api/alpha');
|
||||
expect(createRequest.mock.calls[2][0].url).toContain('/api/beta');
|
||||
expect(fetchMock.lastCall()!.request.url).toContain('/api/gamma');
|
||||
});
|
||||
|
||||
it('should accumulate response information', async () => {
|
||||
const bodies = ['alpha', 'beta', 'gamma'];
|
||||
const createResponse = jest.fn((httpResponse: IHttpResponse) => ({
|
||||
body: bodies.shift(),
|
||||
}));
|
||||
|
||||
fetchInstance.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
response(httpResponse) {
|
||||
throw new Error('Invalid');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
responseError({ error, ...httpResponse }) {
|
||||
return httpResponse;
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
|
||||
await expect(fetchInstance.fetch('/my/route')).resolves.toEqual('gamma');
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(bodies.length).toBe(0);
|
||||
expect(createResponse.mock.calls[0][0].body).toEqual({ foo: 'bar' });
|
||||
expect(createResponse.mock.calls[1][0].body).toBe('alpha');
|
||||
expect(createResponse.mock.calls[2][0].body).toBe('beta');
|
||||
});
|
||||
|
||||
describe('request availability during interception', () => {
|
||||
it('should be available to responseError when response throws', async () => {
|
||||
let spiedRequest: Request | undefined;
|
||||
|
||||
fetchInstance.intercept({
|
||||
response() {
|
||||
throw new Error('Internal Server Error');
|
||||
},
|
||||
});
|
||||
fetchInstance.intercept({
|
||||
responseError({ request }) {
|
||||
spiedRequest = request;
|
||||
},
|
||||
});
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow();
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(spiedRequest).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('response availability during interception', () => {
|
||||
it('should be available to responseError when network request fails', async () => {
|
||||
fetchMock.restore();
|
||||
fetchMock.get('*', { status: 500 });
|
||||
|
||||
let spiedResponse: Response | undefined;
|
||||
|
||||
fetchInstance.intercept({
|
||||
responseError({ response }) {
|
||||
spiedResponse = response;
|
||||
},
|
||||
});
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).rejects.toThrow();
|
||||
expect(spiedResponse).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should actually halt request interceptors in reverse order', async () => {
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({ request: unusedSpy });
|
||||
fetchInstance.intercept({
|
||||
request(request, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
|
||||
fetchInstance.fetch('/my/path');
|
||||
await delay(500);
|
||||
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should recover from failing request interception via request error interceptor', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
|
||||
fetchInstance.intercept({
|
||||
requestError(httpErrorRequest) {
|
||||
return httpErrorRequest.request;
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
|
||||
fetchInstance.intercept({
|
||||
request(request, controller) {
|
||||
throw new Error('Request Error');
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
|
||||
await expect(fetchInstance.fetch('/my/path')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(usedSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -35,20 +35,30 @@ interface Params {
|
|||
const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/;
|
||||
const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/;
|
||||
|
||||
export class FetchService {
|
||||
export class Fetch {
|
||||
private readonly interceptors = new Set<HttpInterceptor>();
|
||||
|
||||
constructor(private readonly params: Params) {}
|
||||
|
||||
public intercept(interceptor: HttpInterceptor) {
|
||||
this.interceptors.add(interceptor);
|
||||
return () => this.interceptors.delete(interceptor);
|
||||
return () => {
|
||||
this.interceptors.delete(interceptor);
|
||||
};
|
||||
}
|
||||
|
||||
public removeAllInterceptors() {
|
||||
this.interceptors.clear();
|
||||
}
|
||||
|
||||
public readonly delete = this.shorthand('DELETE');
|
||||
public readonly get = this.shorthand('GET');
|
||||
public readonly head = this.shorthand('HEAD');
|
||||
public readonly options = this.shorthand('options');
|
||||
public readonly patch = this.shorthand('PATCH');
|
||||
public readonly post = this.shorthand('POST');
|
||||
public readonly put = this.shorthand('PUT');
|
||||
|
||||
public fetch: HttpHandler = async <TResponseBody>(
|
||||
path: string,
|
||||
options: HttpFetchOptions = {}
|
||||
|
@ -152,4 +162,9 @@ export class FetchService {
|
|||
|
||||
return new HttpResponse({ request, response, body });
|
||||
}
|
||||
|
||||
private shorthand(method: string) {
|
||||
return (path: string, options: HttpFetchOptions = {}) =>
|
||||
this.fetch(path, { ...options, method });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import { HttpService } from './http_service';
|
||||
import { HttpSetup } from './types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { BasePath } from './base_path_service';
|
||||
import { BasePath } from './base_path';
|
||||
|
||||
export type HttpSetupMock = jest.Mocked<HttpSetup> & {
|
||||
basePath: BasePath;
|
||||
|
@ -41,15 +41,13 @@ const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
|
|||
register: jest.fn(),
|
||||
isAnonymous: jest.fn(),
|
||||
},
|
||||
addLoadingCount: jest.fn(),
|
||||
addLoadingCountSource: jest.fn(),
|
||||
getLoadingCount$: jest.fn().mockReturnValue(new BehaviorSubject(0)),
|
||||
stop: jest.fn(),
|
||||
intercept: jest.fn(),
|
||||
removeAllInterceptors: jest.fn(),
|
||||
});
|
||||
|
||||
const createMock = ({ basePath = '' } = {}) => {
|
||||
const mocked: jest.Mocked<Required<HttpService>> = {
|
||||
const mocked: jest.Mocked<PublicMethodsOf<HttpService>> = {
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
|
|
25
src/core/public/http/http_service.test.mocks.ts
Normal file
25
src/core/public/http/http_service.test.mocks.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 { loadingCountServiceMock } from './loading_count_service.mock';
|
||||
|
||||
export const loadingServiceMock = loadingCountServiceMock.create();
|
||||
jest.doMock('./loading_count_service', () => ({
|
||||
LoadingCountService: jest.fn(() => loadingServiceMock),
|
||||
}));
|
|
@ -17,692 +17,22 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import { toArray } from 'rxjs/operators';
|
||||
// @ts-ignore
|
||||
import fetchMock from 'fetch-mock/es5/client';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { setup, SetupTap } from '../../../test_utils/public/http_test_setup';
|
||||
import { IHttpResponse } from './types';
|
||||
|
||||
function delay<T>(duration: number) {
|
||||
return new Promise<T>(r => setTimeout(r, duration));
|
||||
}
|
||||
|
||||
const setupFakeBasePath: SetupTap = injectedMetadata => {
|
||||
injectedMetadata.getBasePath.mockReturnValue('/foo/bar');
|
||||
};
|
||||
|
||||
describe('basePath.get()', () => {
|
||||
it('returns an empty string if no basePath is injected', () => {
|
||||
const { http } = setup(injectedMetadata => {
|
||||
injectedMetadata.getBasePath.mockReturnValue(undefined as any);
|
||||
});
|
||||
|
||||
expect(http.basePath.get()).toBe('');
|
||||
});
|
||||
|
||||
it('returns the injected basePath', () => {
|
||||
const { http } = setup(setupFakeBasePath);
|
||||
|
||||
expect(http.basePath.get()).toBe('/foo/bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('http requests', () => {
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it('should use supplied request method', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.post('*', {});
|
||||
await http.fetch('/my/path', { method: 'POST' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should use supplied Content-Type', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', { headers: { 'Content-Type': 'CustomContentType' } });
|
||||
|
||||
expect(fetchMock.lastOptions()!.headers).toMatchObject({
|
||||
'content-type': 'CustomContentType',
|
||||
});
|
||||
});
|
||||
|
||||
it('should use supplied pathname and querystring', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', { query: { a: 'b' } });
|
||||
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path?a=b');
|
||||
});
|
||||
|
||||
it('should use supplied headers', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', {
|
||||
headers: { myHeader: 'foo' },
|
||||
});
|
||||
|
||||
expect(fetchMock.lastOptions()!.headers).toEqual({
|
||||
'content-type': 'application/json',
|
||||
'kbn-version': 'kibanaVersion',
|
||||
myheader: 'foo',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return response', async () => {
|
||||
const { http } = setup();
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
const json = await http.fetch('/my/path');
|
||||
expect(json).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should prepend url with basepath by default', async () => {
|
||||
const { http } = setup();
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path');
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path');
|
||||
});
|
||||
|
||||
it('should not prepend url with basepath when disabled', async () => {
|
||||
const { http } = setup();
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('my/path', { prependBasePath: false });
|
||||
expect(fetchMock.lastUrl()).toBe('/my/path');
|
||||
});
|
||||
|
||||
it('should not include undefined query params', async () => {
|
||||
const { http } = setup();
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path', { query: { a: undefined } });
|
||||
expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path');
|
||||
});
|
||||
|
||||
it('should make request with defaults', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.fetch('/my/path');
|
||||
|
||||
const lastCall = fetchMock.lastCall();
|
||||
|
||||
expect(lastCall!.request.credentials).toBe('same-origin');
|
||||
expect(lastCall![1]).toMatchObject({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'kbn-version': 'kibanaVersion',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose detailed response object when asResponse = true', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
|
||||
const response = await http.fetch('/my/path', { asResponse: true });
|
||||
|
||||
expect(response.request).toBeInstanceOf(Request);
|
||||
expect(response.response).toBeInstanceOf(Response);
|
||||
expect(response.body).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should reject on network error', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
expect.assertions(1);
|
||||
fetchMock.get('*', { status: 500 });
|
||||
|
||||
await expect(http.fetch('/my/path')).rejects.toThrow(/Internal Server Error/);
|
||||
});
|
||||
|
||||
it('should contain error message when throwing response', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', { status: 404, body: { foo: 'bar' } });
|
||||
|
||||
await expect(http.fetch('/my/path')).rejects.toMatchObject({
|
||||
message: 'Not Found',
|
||||
body: {
|
||||
foo: 'bar',
|
||||
},
|
||||
response: {
|
||||
status: 404,
|
||||
url: 'http://localhost/myBase/my/path',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should support get() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.get('*', {});
|
||||
await http.get('/my/path', { method: 'POST' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should support head() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.head('*', {});
|
||||
await http.head('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('HEAD');
|
||||
});
|
||||
|
||||
it('should support post() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.post('*', {});
|
||||
await http.post('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should support put() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.put('*', {});
|
||||
await http.put('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('PUT');
|
||||
});
|
||||
|
||||
it('should support patch() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.patch('*', {});
|
||||
await http.patch('/my/path', { method: 'GET', body: '{}' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('PATCH');
|
||||
});
|
||||
|
||||
it('should support delete() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.delete('*', {});
|
||||
await http.delete('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('DELETE');
|
||||
});
|
||||
|
||||
it('should support options() helper', async () => {
|
||||
const { http } = setup();
|
||||
|
||||
fetchMock.mock('*', { method: 'OPTIONS' });
|
||||
await http.options('/my/path', { method: 'GET' });
|
||||
|
||||
expect(fetchMock.lastOptions()!.method).toBe('OPTIONS');
|
||||
});
|
||||
|
||||
it('should make requests for NDJSON content', async () => {
|
||||
const { http } = setup();
|
||||
const content = readFileSync(join(__dirname, '_import_objects.ndjson'), { encoding: 'utf-8' });
|
||||
const body = new FormData();
|
||||
|
||||
body.append('file', content);
|
||||
fetchMock.post('*', {
|
||||
body: content,
|
||||
headers: { 'Content-Type': 'application/ndjson' },
|
||||
});
|
||||
|
||||
const data = await http.post('/my/path', {
|
||||
body,
|
||||
headers: {
|
||||
'Content-Type': undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(data).toBeInstanceOf(Blob);
|
||||
|
||||
const ndjson = await new Response(data).text();
|
||||
|
||||
expect(ndjson).toEqual(content);
|
||||
});
|
||||
});
|
||||
|
||||
describe('interception', () => {
|
||||
const { http } = setup();
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.get('*', { foo: 'bar' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
http.removeAllInterceptors();
|
||||
});
|
||||
|
||||
it('should make request and receive response', async () => {
|
||||
http.intercept({});
|
||||
|
||||
const body = await http.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
});
|
||||
|
||||
it('should be able to manipulate request instance', async () => {
|
||||
http.intercept({
|
||||
request(request) {
|
||||
request.headers.set('Content-Type', 'CustomContentType');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
request(request) {
|
||||
return new Request('/my/route', request);
|
||||
},
|
||||
});
|
||||
|
||||
const body = await http.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.lastOptions()!.headers).toMatchObject({
|
||||
'content-type': 'CustomContentType',
|
||||
});
|
||||
expect(fetchMock.lastUrl()).toBe('/my/route');
|
||||
});
|
||||
|
||||
it('should call interceptors in correct order', async () => {
|
||||
const order: string[] = [];
|
||||
|
||||
http.intercept({
|
||||
request() {
|
||||
order.push('Request 1');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 1');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
request() {
|
||||
order.push('Request 2');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 2');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
request() {
|
||||
order.push('Request 3');
|
||||
},
|
||||
response() {
|
||||
order.push('Response 3');
|
||||
},
|
||||
});
|
||||
|
||||
const body = await http.fetch('/my/path');
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(body).toEqual({ foo: 'bar' });
|
||||
expect(order).toEqual([
|
||||
'Request 3',
|
||||
'Request 2',
|
||||
'Request 1',
|
||||
'Response 1',
|
||||
'Response 2',
|
||||
'Response 3',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during request', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({ request: unusedSpy, response: unusedSpy });
|
||||
http.intercept({
|
||||
request(request, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
response: unusedSpy,
|
||||
});
|
||||
http.intercept({
|
||||
request: usedSpy,
|
||||
response: unusedSpy,
|
||||
});
|
||||
|
||||
http.fetch('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMock.called()).toBe(false);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during response', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({
|
||||
request: usedSpy,
|
||||
response(response, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
http.intercept({ request: usedSpy, response: unusedSpy });
|
||||
http.intercept({ request: usedSpy, response: unusedSpy });
|
||||
|
||||
http.fetch('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(3);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should skip remaining interceptors when controller halts during responseError', async () => {
|
||||
fetchMock.post('*', 401);
|
||||
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({
|
||||
responseError(response, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
http.intercept({ response: unusedSpy, responseError: unusedSpy });
|
||||
|
||||
http.post('/my/path').then(unusedSpy, unusedSpy);
|
||||
await delay(1000);
|
||||
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should not fetch if exception occurs during request interception', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({
|
||||
request: unusedSpy,
|
||||
requestError: usedSpy,
|
||||
response: unusedSpy,
|
||||
responseError: unusedSpy,
|
||||
});
|
||||
http.intercept({
|
||||
request() {
|
||||
throw new Error('Interception Error');
|
||||
},
|
||||
response: unusedSpy,
|
||||
responseError: unusedSpy,
|
||||
});
|
||||
http.intercept({ request: usedSpy, response: unusedSpy, responseError: unusedSpy });
|
||||
|
||||
await expect(http.fetch('/my/path')).rejects.toThrow(/Interception Error/);
|
||||
expect(fetchMock.called()).toBe(false);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should succeed if request throws but caught by interceptor', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({
|
||||
request: unusedSpy,
|
||||
requestError({ request }) {
|
||||
return new Request('/my/route', request);
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
http.intercept({
|
||||
request() {
|
||||
throw new Error('Interception Error');
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
http.intercept({ request: usedSpy, response: usedSpy });
|
||||
|
||||
await expect(http.fetch('/my/route')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
expect(usedSpy).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('should accumulate request information', async () => {
|
||||
const routes = ['alpha', 'beta', 'gamma'];
|
||||
const createRequest = jest.fn(
|
||||
(request: Request) => new Request(`/api/${routes.shift()}`, request)
|
||||
);
|
||||
|
||||
http.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
http.intercept({
|
||||
requestError(httpErrorRequest) {
|
||||
return httpErrorRequest.request;
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
request(request) {
|
||||
throw new Error('Invalid');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
http.intercept({
|
||||
request: createRequest,
|
||||
});
|
||||
|
||||
await expect(http.fetch('/my/route')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(routes.length).toBe(0);
|
||||
expect(createRequest.mock.calls[0][0].url).toContain('/my/route');
|
||||
expect(createRequest.mock.calls[1][0].url).toContain('/api/alpha');
|
||||
expect(createRequest.mock.calls[2][0].url).toContain('/api/beta');
|
||||
expect(fetchMock.lastCall()!.request.url).toContain('/api/gamma');
|
||||
});
|
||||
|
||||
it('should accumulate response information', async () => {
|
||||
const bodies = ['alpha', 'beta', 'gamma'];
|
||||
const createResponse = jest.fn((httpResponse: IHttpResponse) => ({
|
||||
body: bodies.shift(),
|
||||
}));
|
||||
|
||||
http.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
http.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
http.intercept({
|
||||
response(httpResponse) {
|
||||
throw new Error('Invalid');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
responseError({ error, ...httpResponse }) {
|
||||
return httpResponse;
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
response: createResponse,
|
||||
});
|
||||
|
||||
await expect(http.fetch('/my/route')).resolves.toEqual('gamma');
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(bodies.length).toBe(0);
|
||||
expect(createResponse.mock.calls[0][0].body).toEqual({ foo: 'bar' });
|
||||
expect(createResponse.mock.calls[1][0].body).toBe('alpha');
|
||||
expect(createResponse.mock.calls[2][0].body).toBe('beta');
|
||||
});
|
||||
|
||||
describe('request availability during interception', () => {
|
||||
it('should be available to responseError when response throws', async () => {
|
||||
let spiedRequest: Request | undefined;
|
||||
|
||||
http.intercept({
|
||||
response() {
|
||||
throw new Error('Internal Server Error');
|
||||
},
|
||||
});
|
||||
http.intercept({
|
||||
responseError({ request }) {
|
||||
spiedRequest = request;
|
||||
},
|
||||
});
|
||||
|
||||
await expect(http.fetch('/my/path')).rejects.toThrow();
|
||||
expect(fetchMock.called()).toBe(true);
|
||||
expect(spiedRequest).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('response availability during interception', () => {
|
||||
it('should be available to responseError when network request fails', async () => {
|
||||
fetchMock.restore();
|
||||
fetchMock.get('*', { status: 500 });
|
||||
|
||||
let spiedResponse: Response | undefined;
|
||||
|
||||
http.intercept({
|
||||
responseError({ response }) {
|
||||
spiedResponse = response;
|
||||
},
|
||||
});
|
||||
|
||||
await expect(http.fetch('/my/path')).rejects.toThrow();
|
||||
expect(spiedResponse).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should actually halt request interceptors in reverse order', async () => {
|
||||
const unusedSpy = jest.fn();
|
||||
|
||||
http.intercept({ request: unusedSpy });
|
||||
http.intercept({
|
||||
request(request, controller) {
|
||||
controller.halt();
|
||||
},
|
||||
});
|
||||
|
||||
http.fetch('/my/path');
|
||||
await delay(500);
|
||||
|
||||
expect(unusedSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should recover from failing request interception via request error interceptor', async () => {
|
||||
const usedSpy = jest.fn();
|
||||
|
||||
http.intercept({
|
||||
requestError(httpErrorRequest) {
|
||||
return httpErrorRequest.request;
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
|
||||
http.intercept({
|
||||
request(request, controller) {
|
||||
throw new Error('Request Error');
|
||||
},
|
||||
response: usedSpy,
|
||||
});
|
||||
|
||||
await expect(http.fetch('/my/path')).resolves.toEqual({ foo: 'bar' });
|
||||
expect(usedSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addLoadingCount()', () => {
|
||||
it('subscribes to passed in sources, unsubscribes on stop', () => {
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const unsubA = jest.fn();
|
||||
const subA = jest.fn().mockReturnValue(unsubA);
|
||||
http.addLoadingCount(new Rx.Observable(subA));
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).not.toHaveBeenCalled();
|
||||
|
||||
const unsubB = jest.fn();
|
||||
const subB = jest.fn().mockReturnValue(unsubB);
|
||||
http.addLoadingCount(new Rx.Observable(subB));
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).not.toHaveBeenCalled();
|
||||
|
||||
import { loadingServiceMock } from './http_service.test.mocks';
|
||||
|
||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||
import { HttpService } from './http_service';
|
||||
|
||||
describe('#stop()', () => {
|
||||
it('calls loadingCount.stop()', () => {
|
||||
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
|
||||
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
|
||||
const httpService = new HttpService();
|
||||
httpService.setup({ fatalErrors, injectedMetadata });
|
||||
httpService.start({ fatalErrors, injectedMetadata });
|
||||
httpService.stop();
|
||||
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).toHaveBeenCalledTimes(1);
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('adds a fatal error if source observables emit an error', async () => {
|
||||
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 } = setup();
|
||||
|
||||
http.addLoadingCount(Rx.of(1, 2, 3, 4, -9));
|
||||
expect(fatalErrors.add.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLoadingCount$()', () => {
|
||||
it('emits 0 initially, the right count when sources emit their own count, and ends with zero', async () => {
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const countA$ = new Rx.Subject<number>();
|
||||
const countB$ = new Rx.Subject<number>();
|
||||
const countC$ = new Rx.Subject<number>();
|
||||
const promise = http
|
||||
.getLoadingCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
http.addLoadingCount(countA$);
|
||||
http.addLoadingCount(countB$);
|
||||
http.addLoadingCount(countC$);
|
||||
|
||||
countA$.next(100);
|
||||
countB$.next(10);
|
||||
countC$.next(1);
|
||||
countA$.complete();
|
||||
countB$.next(20);
|
||||
countC$.complete();
|
||||
countB$.next(0);
|
||||
|
||||
httpService.stop();
|
||||
expect(await promise).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('only emits when loading count changes', async () => {
|
||||
const { httpService, http } = setup();
|
||||
|
||||
const count$ = new Rx.Subject<number>();
|
||||
const promise = http
|
||||
.getLoadingCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
http.addLoadingCount(count$);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(1);
|
||||
count$.next(1);
|
||||
httpService.stop();
|
||||
|
||||
expect(await promise).toMatchSnapshot();
|
||||
expect(loadingServiceMock.stop).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,32 +17,52 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpSetup, HttpStart, HttpServiceBase } from './types';
|
||||
import { setup } from './http_setup';
|
||||
import { HttpSetup, HttpStart } from './types';
|
||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
||||
import { FatalErrorsSetup } from '../fatal_errors';
|
||||
import { BasePath } from './base_path';
|
||||
import { AnonymousPathsService } from './anonymous_paths_service';
|
||||
import { LoadingCountService } from './loading_count_service';
|
||||
import { Fetch } from './fetch';
|
||||
import { CoreService } from '../../types';
|
||||
|
||||
interface HttpDeps {
|
||||
injectedMetadata: InjectedMetadataSetup;
|
||||
fatalErrors: FatalErrorsSetup | null;
|
||||
fatalErrors: FatalErrorsSetup;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class HttpService {
|
||||
private service!: HttpServiceBase;
|
||||
export class HttpService implements CoreService<HttpSetup, HttpStart> {
|
||||
private readonly anonymousPaths = new AnonymousPathsService();
|
||||
private readonly loadingCount = new LoadingCountService();
|
||||
|
||||
public setup(deps: HttpDeps): HttpSetup {
|
||||
this.service = setup(deps.injectedMetadata, deps.fatalErrors);
|
||||
return this.service;
|
||||
public setup({ injectedMetadata, fatalErrors }: HttpDeps): HttpSetup {
|
||||
const kibanaVersion = injectedMetadata.getKibanaVersion();
|
||||
const basePath = new BasePath(injectedMetadata.getBasePath());
|
||||
const fetchService = new Fetch({ basePath, kibanaVersion });
|
||||
const loadingCount = this.loadingCount.setup({ fatalErrors });
|
||||
|
||||
return {
|
||||
basePath,
|
||||
anonymousPaths: this.anonymousPaths.setup({ basePath }),
|
||||
intercept: fetchService.intercept.bind(fetchService),
|
||||
fetch: fetchService.fetch.bind(fetchService),
|
||||
delete: fetchService.delete.bind(fetchService),
|
||||
get: fetchService.get.bind(fetchService),
|
||||
head: fetchService.head.bind(fetchService),
|
||||
options: fetchService.options.bind(fetchService),
|
||||
patch: fetchService.patch.bind(fetchService),
|
||||
post: fetchService.post.bind(fetchService),
|
||||
put: fetchService.put.bind(fetchService),
|
||||
...loadingCount,
|
||||
};
|
||||
}
|
||||
|
||||
public start(deps: HttpDeps): HttpStart {
|
||||
return this.service || this.setup(deps);
|
||||
public start(deps: HttpDeps) {
|
||||
return this.setup(deps);
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.service) {
|
||||
this.service.stop();
|
||||
}
|
||||
this.loadingCount.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,123 +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 { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import {
|
||||
distinctUntilChanged,
|
||||
endWith,
|
||||
map,
|
||||
pairwise,
|
||||
startWith,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
||||
import { FatalErrorsSetup } from '../fatal_errors';
|
||||
import { HttpFetchOptions, HttpServiceBase } from './types';
|
||||
import { HttpInterceptController } from './http_intercept_controller';
|
||||
import { HttpInterceptHaltError } from './http_intercept_halt_error';
|
||||
import { BasePath } from './base_path_service';
|
||||
import { AnonymousPaths } from './anonymous_paths';
|
||||
import { FetchService } from './fetch';
|
||||
|
||||
export function checkHalt(controller: HttpInterceptController, error?: Error) {
|
||||
if (error instanceof HttpInterceptHaltError) {
|
||||
throw error;
|
||||
} else if (controller.halted) {
|
||||
throw new HttpInterceptHaltError();
|
||||
}
|
||||
}
|
||||
|
||||
export const setup = (
|
||||
injectedMetadata: InjectedMetadataSetup,
|
||||
fatalErrors: FatalErrorsSetup | null
|
||||
): HttpServiceBase => {
|
||||
const loadingCount$ = new BehaviorSubject(0);
|
||||
const stop$ = new Subject();
|
||||
const kibanaVersion = injectedMetadata.getKibanaVersion();
|
||||
const basePath = new BasePath(injectedMetadata.getBasePath());
|
||||
const anonymousPaths = new AnonymousPaths(basePath);
|
||||
|
||||
const fetchService = new FetchService({ basePath, kibanaVersion });
|
||||
|
||||
function shorthand(method: string) {
|
||||
return (path: string, options: HttpFetchOptions = {}) =>
|
||||
fetchService.fetch(path, { ...options, method });
|
||||
}
|
||||
|
||||
function stop() {
|
||||
stop$.next();
|
||||
loadingCount$.complete();
|
||||
}
|
||||
|
||||
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,
|
||||
basePath,
|
||||
anonymousPaths,
|
||||
intercept: fetchService.intercept.bind(fetchService),
|
||||
removeAllInterceptors: fetchService.removeAllInterceptors.bind(fetchService),
|
||||
fetch: fetchService.fetch.bind(fetchService),
|
||||
delete: shorthand('DELETE'),
|
||||
get: shorthand('GET'),
|
||||
head: shorthand('HEAD'),
|
||||
options: shorthand('OPTIONS'),
|
||||
patch: shorthand('PATCH'),
|
||||
post: shorthand('POST'),
|
||||
put: shorthand('PUT'),
|
||||
addLoadingCount,
|
||||
getLoadingCount$,
|
||||
};
|
||||
};
|
50
src/core/public/http/loading_count_service.mock.ts
Normal file
50
src/core/public/http/loading_count_service.mock.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 { LoadingCountSetup, LoadingCountService } from './loading_count_service';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
const createSetupContractMock = () => {
|
||||
const setupContract: jest.Mocked<LoadingCountSetup> = {
|
||||
addLoadingCountSource: jest.fn(),
|
||||
getLoadingCount$: jest.fn(),
|
||||
};
|
||||
setupContract.getLoadingCount$.mockReturnValue(new BehaviorSubject(0));
|
||||
return setupContract;
|
||||
};
|
||||
|
||||
type LoadingCountServiceContract = PublicMethodsOf<LoadingCountService>;
|
||||
const createServiceMock = () => {
|
||||
const mocked: jest.Mocked<LoadingCountServiceContract> = {
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
};
|
||||
|
||||
mocked.setup.mockReturnValue(createSetupContractMock());
|
||||
mocked.start.mockReturnValue(createSetupContractMock());
|
||||
|
||||
return mocked;
|
||||
};
|
||||
|
||||
export const loadingCountServiceMock = {
|
||||
create: createServiceMock,
|
||||
createSetupContract: createSetupContractMock,
|
||||
createStartContract: createSetupContractMock,
|
||||
};
|
152
src/core/public/http/loading_count_service.test.ts
Normal file
152
src/core/public/http/loading_count_service.test.ts
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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 { Observable, throwError, of, Subject } from 'rxjs';
|
||||
import { toArray } from 'rxjs/operators';
|
||||
|
||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||
import { LoadingCountService } from './loading_count_service';
|
||||
|
||||
describe('LoadingCountService', () => {
|
||||
const setup = () => {
|
||||
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
|
||||
const service = new LoadingCountService();
|
||||
const loadingCount = service.setup({ fatalErrors });
|
||||
return { fatalErrors, loadingCount, service };
|
||||
};
|
||||
|
||||
describe('addLoadingCountSource()', () => {
|
||||
it('subscribes to passed in sources, unsubscribes on stop', () => {
|
||||
const { service, loadingCount } = setup();
|
||||
|
||||
const unsubA = jest.fn();
|
||||
const subA = jest.fn().mockReturnValue(unsubA);
|
||||
loadingCount.addLoadingCountSource(new Observable(subA));
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).not.toHaveBeenCalled();
|
||||
|
||||
const unsubB = jest.fn();
|
||||
const subB = jest.fn().mockReturnValue(unsubB);
|
||||
loadingCount.addLoadingCountSource(new Observable(subB));
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).not.toHaveBeenCalled();
|
||||
|
||||
service.stop();
|
||||
|
||||
expect(subA).toHaveBeenCalledTimes(1);
|
||||
expect(unsubA).toHaveBeenCalledTimes(1);
|
||||
expect(subB).toHaveBeenCalledTimes(1);
|
||||
expect(unsubB).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('adds a fatal error if source observables emit an error', () => {
|
||||
const { loadingCount, fatalErrors } = setup();
|
||||
|
||||
loadingCount.addLoadingCountSource(throwError(new Error('foo bar')));
|
||||
expect(fatalErrors.add.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
[Error: foo bar],
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('adds a fatal error if source observable emits a negative number', () => {
|
||||
const { loadingCount, fatalErrors } = setup();
|
||||
|
||||
loadingCount.addLoadingCountSource(of(1, 2, 3, 4, -9));
|
||||
expect(fatalErrors.add.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
[Error: Observables passed to loadingCount.add() must only emit positive numbers],
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLoadingCount$()', () => {
|
||||
it('emits 0 initially, the right count when sources emit their own count, and ends with zero', async () => {
|
||||
const { service, loadingCount } = setup();
|
||||
|
||||
const countA$ = new Subject<number>();
|
||||
const countB$ = new Subject<number>();
|
||||
const countC$ = new Subject<number>();
|
||||
const promise = loadingCount
|
||||
.getLoadingCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
loadingCount.addLoadingCountSource(countA$);
|
||||
loadingCount.addLoadingCountSource(countB$);
|
||||
loadingCount.addLoadingCountSource(countC$);
|
||||
|
||||
countA$.next(100);
|
||||
countB$.next(10);
|
||||
countC$.next(1);
|
||||
countA$.complete();
|
||||
countB$.next(20);
|
||||
countC$.complete();
|
||||
countB$.next(0);
|
||||
|
||||
service.stop();
|
||||
expect(await promise).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
0,
|
||||
100,
|
||||
110,
|
||||
111,
|
||||
11,
|
||||
21,
|
||||
20,
|
||||
0,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('only emits when loading count changes', async () => {
|
||||
const { service, loadingCount } = setup();
|
||||
|
||||
const count$ = new Subject<number>();
|
||||
const promise = loadingCount
|
||||
.getLoadingCount$()
|
||||
.pipe(toArray())
|
||||
.toPromise();
|
||||
|
||||
loadingCount.addLoadingCountSource(count$);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(0);
|
||||
count$.next(1);
|
||||
count$.next(1);
|
||||
service.stop();
|
||||
|
||||
expect(await promise).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
93
src/core/public/http/loading_count_service.ts
Normal file
93
src/core/public/http/loading_count_service.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 { FatalErrorsSetup } from '../fatal_errors';
|
||||
import { CoreService } from '../../types';
|
||||
|
||||
/** @public */
|
||||
export interface LoadingCountSetup {
|
||||
addLoadingCountSource(countSource$: Observable<number>): void;
|
||||
|
||||
getLoadingCount$(): Observable<number>;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link LoadingCountSetup}.
|
||||
* @public
|
||||
*/
|
||||
export type LoadingCountStart = LoadingCountSetup;
|
||||
|
||||
/** @internal */
|
||||
export class LoadingCountService implements CoreService<LoadingCountSetup, LoadingCountStart> {
|
||||
private readonly stop$ = new Subject();
|
||||
private readonly loadingCount$ = new BehaviorSubject(0);
|
||||
|
||||
public setup({ fatalErrors }: { fatalErrors: FatalErrorsSetup }) {
|
||||
return {
|
||||
getLoadingCount$: () => this.loadingCount$.pipe(distinctUntilChanged()),
|
||||
addLoadingCountSource: (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(this.stop$),
|
||||
endWith(0),
|
||||
startWith(0),
|
||||
pairwise(),
|
||||
map(([prev, next]) => next - prev)
|
||||
)
|
||||
.subscribe({
|
||||
next: delta => {
|
||||
this.loadingCount$.next(this.loadingCount$.getValue() + delta);
|
||||
},
|
||||
error: error => fatalErrors.add(error),
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public start({ fatalErrors }: { fatalErrors: FatalErrorsSetup }) {
|
||||
return this.setup({ fatalErrors });
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.stop$.next();
|
||||
this.loadingCount$.complete();
|
||||
}
|
||||
}
|
|
@ -20,10 +20,7 @@
|
|||
import { Observable } from 'rxjs';
|
||||
|
||||
/** @public */
|
||||
export interface HttpServiceBase {
|
||||
/** @internal */
|
||||
stop(): void;
|
||||
|
||||
export interface HttpSetup {
|
||||
/**
|
||||
* APIs for manipulating the basePath on URL segments.
|
||||
*/
|
||||
|
@ -41,11 +38,6 @@ export interface HttpServiceBase {
|
|||
*/
|
||||
intercept(interceptor: HttpInterceptor): () => void;
|
||||
|
||||
/**
|
||||
* Removes all configured interceptors.
|
||||
*/
|
||||
removeAllInterceptors(): void;
|
||||
|
||||
/** Makes an HTTP request. Defaults to a GET request unless overriden. See {@link HttpHandler} for options. */
|
||||
fetch: HttpHandler;
|
||||
/** Makes an HTTP request with the DELETE method. See {@link HttpHandler} for options. */
|
||||
|
@ -68,7 +60,7 @@ export interface HttpServiceBase {
|
|||
* more than 0.
|
||||
* @param countSource$ an Observable to subscribe to for loading count updates.
|
||||
*/
|
||||
addLoadingCount(countSource$: Observable<number>): void;
|
||||
addLoadingCountSource(countSource$: Observable<number>): void;
|
||||
|
||||
/**
|
||||
* Get the sum of all loading count sources as a single Observable.
|
||||
|
@ -76,6 +68,12 @@ export interface HttpServiceBase {
|
|||
getLoadingCount$(): Observable<number>;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link HttpSetup}
|
||||
* @public
|
||||
*/
|
||||
export type HttpStart = HttpSetup;
|
||||
|
||||
/**
|
||||
* APIs for manipulating the basePath on URL segments.
|
||||
* @public
|
||||
|
@ -112,18 +110,6 @@ export interface IAnonymousPaths {
|
|||
register(path: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link HttpServiceBase}
|
||||
* @public
|
||||
*/
|
||||
export type HttpSetup = HttpServiceBase;
|
||||
|
||||
/**
|
||||
* See {@link HttpServiceBase}
|
||||
* @public
|
||||
*/
|
||||
export type HttpStart = HttpServiceBase;
|
||||
|
||||
/** @public */
|
||||
export interface HttpHeadersInit {
|
||||
[name: string]: any;
|
||||
|
|
|
@ -122,7 +122,6 @@ export {
|
|||
} from './saved_objects';
|
||||
|
||||
export {
|
||||
HttpServiceBase,
|
||||
HttpHeadersInit,
|
||||
HttpRequestInit,
|
||||
HttpFetchOptions,
|
||||
|
|
|
@ -544,8 +544,8 @@ export interface HttpRequestInit {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpServiceBase {
|
||||
addLoadingCount(countSource$: Observable<number>): void;
|
||||
export interface HttpSetup {
|
||||
addLoadingCountSource(countSource$: Observable<number>): void;
|
||||
anonymousPaths: IAnonymousPaths;
|
||||
basePath: IBasePath;
|
||||
delete: HttpHandler;
|
||||
|
@ -558,16 +558,10 @@ export interface HttpServiceBase {
|
|||
patch: HttpHandler;
|
||||
post: HttpHandler;
|
||||
put: HttpHandler;
|
||||
removeAllInterceptors(): void;
|
||||
// @internal (undocumented)
|
||||
stop(): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type HttpSetup = HttpServiceBase;
|
||||
|
||||
// @public
|
||||
export type HttpStart = HttpServiceBase;
|
||||
export type HttpStart = HttpSetup;
|
||||
|
||||
// @public
|
||||
export interface I18nStart {
|
||||
|
@ -877,7 +871,7 @@ export interface SavedObjectsBulkUpdateOptions {
|
|||
// @public
|
||||
export class SavedObjectsClient {
|
||||
// @internal
|
||||
constructor(http: HttpServiceBase);
|
||||
constructor(http: HttpSetup);
|
||||
bulkCreate: (objects?: SavedObjectsBulkCreateObject<SavedObjectAttributes>[], options?: SavedObjectsBulkCreateOptions) => Promise<SavedObjectsBatchResponse<SavedObjectAttributes>>;
|
||||
bulkGet: (objects?: {
|
||||
id: string;
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
} from '../../../legacy/ui/public/error_auto_create_index/error_auto_create_index';
|
||||
import { SimpleSavedObject } from './simple_saved_object';
|
||||
import { HttpFetchOptions, HttpServiceBase } from '../http';
|
||||
import { HttpFetchOptions, HttpSetup } from '../http';
|
||||
|
||||
type SavedObjectsFindOptions = Omit<SavedObjectFindOptionsServer, 'namespace' | 'sortOrder'>;
|
||||
|
||||
|
@ -158,7 +158,7 @@ export type SavedObjectsClientContract = PublicMethodsOf<SavedObjectsClient>;
|
|||
* @public
|
||||
*/
|
||||
export class SavedObjectsClient {
|
||||
private http: HttpServiceBase;
|
||||
private http: HttpSetup;
|
||||
private batchQueue: BatchQueueEntry[];
|
||||
|
||||
/**
|
||||
|
@ -194,7 +194,7 @@ export class SavedObjectsClient {
|
|||
);
|
||||
|
||||
/** @internal */
|
||||
constructor(http: HttpServiceBase) {
|
||||
constructor(http: HttpSetup) {
|
||||
this.http = http;
|
||||
this.batchQueue = [];
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ describe('#stop', () => {
|
|||
it('stops the uiSettingsClient and uiSettingsApi', async () => {
|
||||
const service = new UiSettingsService();
|
||||
let loadingCount$: Rx.Observable<unknown>;
|
||||
defaultDeps.http.addLoadingCount.mockImplementation(obs$ => (loadingCount$ = obs$));
|
||||
defaultDeps.http.addLoadingCountSource.mockImplementation(obs$ => (loadingCount$ = obs$));
|
||||
const client = service.setup(defaultDeps);
|
||||
|
||||
service.stop();
|
||||
|
|
|
@ -38,7 +38,7 @@ export class UiSettingsService {
|
|||
|
||||
public setup({ http, injectedMetadata }: UiSettingsServiceDeps): IUiSettingsClient {
|
||||
this.uiSettingsApi = new UiSettingsApi(http);
|
||||
http.addLoadingCount(this.uiSettingsApi.getLoadingCount$());
|
||||
http.addLoadingCountSource(this.uiSettingsApi.getLoadingCount$());
|
||||
|
||||
// TODO: Migrate away from legacyMetadata https://github.com/elastic/kibana/issues/22779
|
||||
const legacyMetadata = injectedMetadata.getLegacyMetadata();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/** @internal */
|
||||
export interface CoreService<TSetup = void, TStart = void> {
|
||||
setup(...params: any[]): Promise<TSetup>;
|
||||
start(...params: any[]): Promise<TStart>;
|
||||
stop(): Promise<void>;
|
||||
setup(...params: any[]): TSetup | Promise<TSetup>;
|
||||
start(...params: any[]): TStart | Promise<TStart>;
|
||||
stop(): void | Promise<void>;
|
||||
}
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from '../../../../../../../../core/public';
|
||||
import { HttpSetup } from '../../../../../../../../core/public';
|
||||
import { IndexPatternCreationConfig, UrlHandler, IndexPatternCreationOption } from './config';
|
||||
|
||||
export class IndexPatternCreationManager {
|
||||
private configs: IndexPatternCreationConfig[];
|
||||
|
||||
constructor(private readonly httpClient: HttpServiceBase) {
|
||||
constructor(private readonly httpClient: HttpSetup) {
|
||||
this.configs = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from '../../../../../../../core/public';
|
||||
import { HttpSetup } from '../../../../../../../core/public';
|
||||
import { IndexPatternCreationManager, IndexPatternCreationConfig } from './creation';
|
||||
import { IndexPatternListManager, IndexPatternListConfig } from './list';
|
||||
|
||||
interface SetupDependencies {
|
||||
httpClient: HttpServiceBase;
|
||||
httpClient: HttpSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@ const newPlatformHttp = npSetup.core.http;
|
|||
|
||||
export function initLoadingCountApi(chrome) {
|
||||
const manualCount$ = new Rx.BehaviorSubject(0);
|
||||
newPlatformHttp.addLoadingCount(manualCount$);
|
||||
newPlatformHttp.addLoadingCountSource(manualCount$);
|
||||
|
||||
chrome.loadingCount = new (class ChromeLoadingCountApi {
|
||||
/**
|
||||
|
|
|
@ -173,7 +173,7 @@ const capture$httpLoadingCount = (newPlatform: CoreStart) => (
|
|||
$rootScope: IRootScopeService,
|
||||
$http: IHttpService
|
||||
) => {
|
||||
newPlatform.http.addLoadingCount(
|
||||
newPlatform.http.addLoadingCountSource(
|
||||
new Rx.Observable(observer => {
|
||||
const unwatch = $rootScope.$watch(() => {
|
||||
const reqs = $http.pendingRequests || [];
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
import { IndexPatterns } from './index_patterns';
|
||||
import { SavedObjectsClientContract, IUiSettingsClient, HttpServiceBase } from 'kibana/public';
|
||||
import { SavedObjectsClientContract, IUiSettingsClient, HttpSetup } from 'kibana/public';
|
||||
|
||||
jest.mock('./index_pattern', () => {
|
||||
class IndexPattern {
|
||||
|
@ -49,7 +49,7 @@ describe('IndexPatterns', () => {
|
|||
beforeEach(() => {
|
||||
const savedObjectsClient = {} as SavedObjectsClientContract;
|
||||
const uiSettings = {} as IUiSettingsClient;
|
||||
const http = {} as HttpServiceBase;
|
||||
const http = {} as HttpSetup;
|
||||
|
||||
indexPatterns = new IndexPatterns(uiSettings, savedObjectsClient, http);
|
||||
});
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
SavedObjectsClientContract,
|
||||
SimpleSavedObject,
|
||||
IUiSettingsClient,
|
||||
HttpServiceBase,
|
||||
HttpStart,
|
||||
} from 'src/core/public';
|
||||
|
||||
import { createIndexPatternCache } from './_pattern_cache';
|
||||
|
@ -39,7 +39,7 @@ export class IndexPatterns {
|
|||
constructor(
|
||||
config: IUiSettingsClient,
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
http: HttpServiceBase
|
||||
http: HttpStart
|
||||
) {
|
||||
this.apiClient = new IndexPatternsApiClient(http);
|
||||
this.config = config;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from 'src/core/public';
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
import { indexPatterns } from '../';
|
||||
|
||||
const API_BASE_URL: string = `/api/index_patterns/`;
|
||||
|
@ -33,9 +33,9 @@ export interface GetFieldsOptions {
|
|||
export type IIndexPatternsApiClient = PublicMethodsOf<IndexPatternsApiClient>;
|
||||
|
||||
export class IndexPatternsApiClient {
|
||||
private http: HttpServiceBase;
|
||||
private http: HttpSetup;
|
||||
|
||||
constructor(http: HttpServiceBase) {
|
||||
constructor(http: HttpSetup) {
|
||||
this.http = http;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
|
||||
import { memoize } from 'lodash';
|
||||
|
||||
import { IUiSettingsClient, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, HttpSetup } from 'src/core/public';
|
||||
import { IGetSuggestions } from './types';
|
||||
import { IFieldType } from '../../common';
|
||||
|
||||
export function getSuggestionsProvider(
|
||||
uiSettings: IUiSettingsClient,
|
||||
http: HttpServiceBase
|
||||
http: HttpSetup
|
||||
): IGetSuggestions {
|
||||
const requestSuggestions = memoize(
|
||||
(
|
||||
|
|
|
@ -299,7 +299,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -320,8 +320,6 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
@ -920,7 +918,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -941,8 +939,6 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
@ -1529,7 +1525,7 @@ exports[`QueryStringInput Should pass the query language to the language switche
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -1550,8 +1546,6 @@ exports[`QueryStringInput Should pass the query language to the language switche
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
@ -2147,7 +2141,7 @@ exports[`QueryStringInput Should pass the query language to the language switche
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -2168,8 +2162,6 @@ exports[`QueryStringInput Should pass the query language to the language switche
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
@ -2756,7 +2748,7 @@ exports[`QueryStringInput Should render the given query 1`] = `
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -2777,8 +2769,6 @@ exports[`QueryStringInput Should render the given query 1`] = `
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
@ -3374,7 +3364,7 @@ exports[`QueryStringInput Should render the given query 1`] = `
|
|||
},
|
||||
},
|
||||
"http": Object {
|
||||
"addLoadingCount": [MockFunction],
|
||||
"addLoadingCountSource": [MockFunction],
|
||||
"anonymousPaths": Object {
|
||||
"isAnonymous": [MockFunction],
|
||||
"register": [MockFunction],
|
||||
|
@ -3395,8 +3385,6 @@ exports[`QueryStringInput Should render the given query 1`] = `
|
|||
"patch": [MockFunction],
|
||||
"post": [MockFunction],
|
||||
"put": [MockFunction],
|
||||
"removeAllInterceptors": [MockFunction],
|
||||
"stop": [MockFunction],
|
||||
},
|
||||
"i18n": Object {
|
||||
"Context": [MockFunction],
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
|
||||
import { HttpServiceBase, HttpFetchQuery } from '../../../../../src/core/public';
|
||||
import { HttpSetup, HttpFetchQuery } from '../../../../../src/core/public';
|
||||
|
||||
export interface SendRequestConfig {
|
||||
path: string;
|
||||
|
@ -48,7 +48,7 @@ export interface UseRequestResponse {
|
|||
}
|
||||
|
||||
export const sendRequest = async (
|
||||
httpClient: HttpServiceBase,
|
||||
httpClient: HttpSetup,
|
||||
{ path, method, body, query }: SendRequestConfig
|
||||
): Promise<SendRequestResponse> => {
|
||||
try {
|
||||
|
@ -67,7 +67,7 @@ export const sendRequest = async (
|
|||
};
|
||||
|
||||
export const useRequest = (
|
||||
httpClient: HttpServiceBase,
|
||||
httpClient: HttpSetup,
|
||||
{
|
||||
path,
|
||||
method,
|
||||
|
|
|
@ -21,7 +21,7 @@ import { take, tap, toArray } from 'rxjs/operators';
|
|||
import { interval, race } from 'rxjs';
|
||||
import sinon, { stub } from 'sinon';
|
||||
import moment from 'moment';
|
||||
import { HttpServiceBase } from 'src/core/public';
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
import { NEWSFEED_HASH_SET_STORAGE_KEY, NEWSFEED_LAST_FETCH_STORAGE_KEY } from '../../constants';
|
||||
import { ApiItem, NewsfeedItem, NewsfeedPluginInjectedConfig } from '../../types';
|
||||
import { NewsfeedApiDriver, getApi } from './api';
|
||||
|
@ -444,7 +444,7 @@ describe('getApi', () => {
|
|||
const mockHttpGet = jest.fn();
|
||||
let httpMock = ({
|
||||
fetch: mockHttpGet,
|
||||
} as unknown) as HttpServiceBase;
|
||||
} as unknown) as HttpSetup;
|
||||
const getHttpMockWithItems = (mockApiItems: ApiItem[]) => (
|
||||
arg1: string,
|
||||
arg2: { method: string }
|
||||
|
@ -478,7 +478,7 @@ describe('getApi', () => {
|
|||
};
|
||||
httpMock = ({
|
||||
fetch: mockHttpGet,
|
||||
} as unknown) as HttpServiceBase;
|
||||
} as unknown) as HttpSetup;
|
||||
});
|
||||
|
||||
it('creates a result', done => {
|
||||
|
|
|
@ -21,7 +21,7 @@ import * as Rx from 'rxjs';
|
|||
import moment from 'moment';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { catchError, filter, mergeMap, tap } from 'rxjs/operators';
|
||||
import { HttpServiceBase } from 'src/core/public';
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
import {
|
||||
NEWSFEED_FALLBACK_LANGUAGE,
|
||||
NEWSFEED_LAST_FETCH_STORAGE_KEY,
|
||||
|
@ -77,7 +77,7 @@ export class NewsfeedApiDriver {
|
|||
return { previous: old, current: updatedHashes };
|
||||
}
|
||||
|
||||
fetchNewsfeedItems(http: HttpServiceBase, config: ApiConfig): Rx.Observable<FetchResult> {
|
||||
fetchNewsfeedItems(http: HttpSetup, config: ApiConfig): Rx.Observable<FetchResult> {
|
||||
const urlPath = config.pathTemplate.replace('{VERSION}', this.kibanaVersion);
|
||||
const fullUrl = config.urlRoot + urlPath;
|
||||
|
||||
|
@ -166,7 +166,7 @@ export class NewsfeedApiDriver {
|
|||
* Computes hasNew value from new item hashes saved in localStorage
|
||||
*/
|
||||
export function getApi(
|
||||
http: HttpServiceBase,
|
||||
http: HttpSetup,
|
||||
config: NewsfeedPluginInjectedConfig['newsfeed'],
|
||||
kibanaVersion: string
|
||||
): Rx.Observable<void | FetchResult> {
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
Plugin,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
HttpServiceBase,
|
||||
HttpSetup,
|
||||
} from '../../../core/public';
|
||||
|
||||
interface PublicConfigType {
|
||||
|
@ -41,7 +41,7 @@ export interface UsageCollectionSetup {
|
|||
METRIC_TYPE: typeof METRIC_TYPE;
|
||||
}
|
||||
|
||||
export function isUnauthenticated(http: HttpServiceBase) {
|
||||
export function isUnauthenticated(http: HttpSetup) {
|
||||
const { anonymousPaths } = http;
|
||||
return anonymousPaths.isAnonymous(window.location.pathname);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
|
||||
import { Reporter, Storage } from '@kbn/analytics';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
|
||||
interface AnalyicsReporterConfig {
|
||||
localStorage: Storage;
|
||||
debug: boolean;
|
||||
fetch: HttpServiceBase;
|
||||
fetch: HttpSetup;
|
||||
}
|
||||
|
||||
export function createReporter(config: AnalyicsReporterConfig): Reporter {
|
||||
|
|
|
@ -10,7 +10,7 @@ import uuid from 'uuid';
|
|||
import * as rest from '../../../../../services/rest/watcher';
|
||||
import { createErrorGroupWatch } from '../createErrorGroupWatch';
|
||||
import { esResponse } from './esResponse';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
|
||||
// disable html escaping since this is also disabled in watcher\s mustache implementation
|
||||
mustache.escape = value => value;
|
||||
|
@ -30,7 +30,7 @@ describe('createErrorGroupWatch', () => {
|
|||
jest.spyOn(uuid, 'v4').mockReturnValue(Buffer.from('mocked-uuid'));
|
||||
|
||||
createWatchResponse = await createErrorGroupWatch({
|
||||
http: {} as HttpServiceBase,
|
||||
http: {} as HttpSetup,
|
||||
emails: ['my@email.dk', 'mySecond@email.dk'],
|
||||
schedule: {
|
||||
daily: {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { isEmpty } from 'lodash';
|
||||
import url from 'url';
|
||||
import uuid from 'uuid';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import {
|
||||
ERROR_CULPRIT,
|
||||
ERROR_EXC_HANDLED,
|
||||
|
@ -35,7 +35,7 @@ export interface Schedule {
|
|||
}
|
||||
|
||||
interface Arguments {
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
emails: string[];
|
||||
schedule: Schedule;
|
||||
serviceName: string;
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
import { mockNow } from '../../utils/testHelpers';
|
||||
import { clearCache, callApi } from '../rest/callApi';
|
||||
import { SessionStorageMock } from './SessionStorageMock';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
|
||||
type HttpMock = HttpServiceBase & {
|
||||
get: jest.SpyInstance<HttpServiceBase['get']>;
|
||||
type HttpMock = HttpSetup & {
|
||||
get: jest.SpyInstance<HttpSetup['get']>;
|
||||
};
|
||||
|
||||
describe('callApi', () => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import * as callApiExports from '../rest/callApi';
|
||||
import { createCallApmApi, APMClient } from '../rest/createCallApmApi';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
|
||||
const callApi = jest
|
||||
.spyOn(callApiExports, 'callApi')
|
||||
|
@ -15,7 +15,7 @@ const callApi = jest
|
|||
describe('callApmApi', () => {
|
||||
let callApmApi: APMClient;
|
||||
beforeEach(() => {
|
||||
callApmApi = createCallApmApi({} as HttpServiceBase);
|
||||
callApmApi = createCallApmApi({} as HttpSetup);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { isString, startsWith } from 'lodash';
|
||||
import LRU from 'lru-cache';
|
||||
import hash from 'object-hash';
|
||||
import { HttpServiceBase, HttpFetchOptions } from 'kibana/public';
|
||||
import { HttpSetup, HttpFetchOptions } from 'kibana/public';
|
||||
|
||||
export type FetchOptions = Omit<HttpFetchOptions, 'body'> & {
|
||||
pathname: string;
|
||||
|
@ -42,7 +42,7 @@ export function clearCache() {
|
|||
export type CallApi = typeof callApi;
|
||||
|
||||
export async function callApi<T = void>(
|
||||
http: HttpServiceBase,
|
||||
http: HttpSetup,
|
||||
fetchOptions: FetchOptions
|
||||
): Promise<T> {
|
||||
const cacheKey = getCacheKey(fetchOptions);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import { callApi, FetchOptions } from './callApi';
|
||||
import { APMAPI } from '../../../server/routes/create_apm_api';
|
||||
import { Client } from '../../../server/routes/typings';
|
||||
|
@ -17,7 +17,7 @@ export type APMClientOptions = Omit<FetchOptions, 'query' | 'body'> & {
|
|||
};
|
||||
};
|
||||
|
||||
export const createCallApmApi = (http: HttpServiceBase) =>
|
||||
export const createCallApmApi = (http: HttpSetup) =>
|
||||
((options: APMClientOptions) => {
|
||||
const { pathname, params = {}, ...opts } = options;
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import { createCallApmApi } from './createCallApmApi';
|
||||
|
||||
export const createStaticIndexPattern = async (http: HttpServiceBase) => {
|
||||
export const createStaticIndexPattern = async (http: HttpSetup) => {
|
||||
const callApmApi = createCallApmApi(http);
|
||||
return await callApmApi({
|
||||
method: 'POST',
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import {
|
||||
PROCESSOR_EVENT,
|
||||
SERVICE_NAME,
|
||||
|
@ -32,7 +32,7 @@ interface StartedMLJobApiResponse {
|
|||
jobs: MlResponseItem[];
|
||||
}
|
||||
|
||||
async function getTransactionIndices(http: HttpServiceBase) {
|
||||
async function getTransactionIndices(http: HttpSetup) {
|
||||
const callApmApi: APMClient = createCallApmApi(http);
|
||||
const indices = await callApmApi({
|
||||
method: 'GET',
|
||||
|
@ -48,7 +48,7 @@ export async function startMLJob({
|
|||
}: {
|
||||
serviceName: string;
|
||||
transactionType: string;
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
}) {
|
||||
const transactionIndices = await getTransactionIndices(http);
|
||||
const groups = ['apm', serviceName.toLowerCase()];
|
||||
|
@ -90,7 +90,7 @@ export async function getHasMLJob({
|
|||
}: {
|
||||
serviceName: string;
|
||||
transactionType: string;
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
}) {
|
||||
try {
|
||||
await callApi<MLJobApiResponse>(http, {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import { callApi } from './callApi';
|
||||
|
||||
export async function createWatch({
|
||||
|
@ -12,7 +12,7 @@ export async function createWatch({
|
|||
watch,
|
||||
http
|
||||
}: {
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
id: string;
|
||||
watch: any;
|
||||
}) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpStart } from 'kibana/public';
|
||||
import { callApi } from './callApi';
|
||||
|
||||
export interface LicenseApiResponse {
|
||||
|
@ -38,7 +38,7 @@ export interface LicenseApiResponse {
|
|||
};
|
||||
}
|
||||
|
||||
export async function loadLicense(http: HttpServiceBase) {
|
||||
export async function loadLicense(http: HttpStart) {
|
||||
return callApi<LicenseApiResponse>(http, {
|
||||
pathname: `/api/xpack/v1/info`
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ export interface LoadingIndicatorInterface {
|
|||
|
||||
const loadingCount$ = new Rx.BehaviorSubject(0);
|
||||
|
||||
export const initLoadingIndicator = (addLoadingCount: CoreStart['http']['addLoadingCount']) =>
|
||||
export const initLoadingIndicator = (addLoadingCount: CoreStart['http']['addLoadingCountSource']) =>
|
||||
addLoadingCount(loadingCount$);
|
||||
|
||||
export const loadingIndicator = {
|
||||
|
|
|
@ -77,7 +77,7 @@ export class CanvasPlugin
|
|||
initLocationProvider(core, plugins);
|
||||
initStore(core, plugins);
|
||||
initClipboard(plugins.__LEGACY.storage);
|
||||
initLoadingIndicator(core.http.addLoadingCount);
|
||||
initLoadingIndicator(core.http.addLoadingCountSource);
|
||||
|
||||
const CanvasRootController = CanvasRootControllerFactory(core, plugins);
|
||||
plugins.__LEGACY.setRootController('canvas', CanvasRootController);
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpServiceBase } from '../../../../../../../src/core/public';
|
||||
import { HttpSetup } from '../../../../../../../src/core/public';
|
||||
|
||||
class HttpService {
|
||||
private client: any;
|
||||
|
||||
public init(httpClient: HttpServiceBase): void {
|
||||
public init(httpClient: HttpSetup): void {
|
||||
this.client = httpClient;
|
||||
}
|
||||
|
||||
public get httpClient(): HttpServiceBase {
|
||||
public get httpClient(): HttpSetup {
|
||||
return this.client;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { DropHandler, DragContextState } from '../../drag_drop';
|
||||
import { createMockedDragDropContext } from '../mocks';
|
||||
import { mountWithIntl as mount, shallowWithIntl as shallow } from 'test_utils/enzyme_helpers';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { IndexPatternPrivateState } from '../types';
|
||||
import { documentField } from '../document_field';
|
||||
|
@ -138,7 +138,7 @@ describe('IndexPatternDimensionPanel', () => {
|
|||
storage: {} as IStorageWrapper,
|
||||
uiSettings: {} as IUiSettingsClient,
|
||||
savedObjectsClient: {} as SavedObjectsClientContract,
|
||||
http: {} as HttpServiceBase,
|
||||
http: {} as HttpSetup,
|
||||
};
|
||||
|
||||
jest.clearAllMocks();
|
||||
|
|
|
@ -8,7 +8,7 @@ import _ from 'lodash';
|
|||
import React, { memo, useMemo } from 'react';
|
||||
import { EuiButtonIcon } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { DatasourceDimensionPanelProps, StateSetter } from '../../types';
|
||||
import { IndexPatternColumn, OperationType } from '../indexpattern';
|
||||
|
@ -29,7 +29,7 @@ export type IndexPatternDimensionPanelProps = DatasourceDimensionPanelProps & {
|
|||
storage: IStorageWrapper;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
layerId: string;
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
uniqueLabel: string;
|
||||
dateRange: DateRange;
|
||||
};
|
||||
|
|
|
@ -6,11 +6,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import {
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectAttributes,
|
||||
HttpServiceBase,
|
||||
} from 'src/core/public';
|
||||
import { SavedObjectsClientContract, SavedObjectAttributes, HttpSetup } from 'src/core/public';
|
||||
import { SimpleSavedObject } from 'src/core/public';
|
||||
import { StateSetter } from '../types';
|
||||
import {
|
||||
|
@ -233,7 +229,7 @@ export async function syncExistingFields({
|
|||
}: {
|
||||
dateRange: DateRange;
|
||||
indexPatterns: Array<{ title: string; timeFieldName?: string | null }>;
|
||||
fetchJson: HttpServiceBase['get'];
|
||||
fetchJson: HttpSetup['get'];
|
||||
setState: SetState;
|
||||
}) {
|
||||
const emptinessInfo = await Promise.all(
|
||||
|
|
|
@ -9,7 +9,7 @@ import { DateHistogramIndexPatternColumn } from './date_histogram';
|
|||
import { dateHistogramOperation } from '.';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { createMockedIndexPattern } from '../../mocks';
|
||||
import { IndexPatternPrivateState } from '../../types';
|
||||
|
@ -36,7 +36,7 @@ const defaultOptions = {
|
|||
fromDate: 'now-1y',
|
||||
toDate: 'now',
|
||||
},
|
||||
http: {} as HttpServiceBase,
|
||||
http: {} as HttpSetup,
|
||||
};
|
||||
|
||||
describe('date_histogram', () => {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { termsOperation } from './terms';
|
||||
import { cardinalityOperation } from './cardinality';
|
||||
|
@ -47,7 +47,7 @@ export interface ParamEditorProps<C extends BaseIndexPatternColumn> {
|
|||
uiSettings: IUiSettingsClient;
|
||||
storage: IStorageWrapper;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
http: HttpServiceBase;
|
||||
http: HttpSetup;
|
||||
dateRange: DateRange;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EuiRange, EuiSelect } from '@elastic/eui';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpServiceBase } from 'src/core/public';
|
||||
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'src/core/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { createMockedIndexPattern } from '../../mocks';
|
||||
import { TermsIndexPatternColumn } from './terms';
|
||||
|
@ -21,7 +21,7 @@ const defaultProps = {
|
|||
uiSettings: {} as IUiSettingsClient,
|
||||
savedObjectsClient: {} as SavedObjectsClientContract,
|
||||
dateRange: { fromDate: 'now-1d', toDate: 'now' },
|
||||
http: {} as HttpServiceBase,
|
||||
http: {} as HttpSetup,
|
||||
};
|
||||
|
||||
describe('terms', () => {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
trackSuggestionEvent,
|
||||
} from './factory';
|
||||
import { coreMock } from 'src/core/public/mocks';
|
||||
import { HttpServiceBase } from 'kibana/public';
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
@ -31,7 +31,7 @@ const createMockStorage = () => {
|
|||
|
||||
describe('Lens UI telemetry', () => {
|
||||
let storage: jest.Mocked<IStorageWrapper>;
|
||||
let http: jest.Mocked<HttpServiceBase>;
|
||||
let http: jest.Mocked<HttpSetup>;
|
||||
let dateSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { HttpServiceBase } from 'src/core/public';
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
|
||||
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
||||
import { BASE_API_URL } from '../../common';
|
||||
|
@ -44,10 +44,10 @@ export class LensReportManager {
|
|||
private suggestionEvents: Record<string, Record<string, number>> = {};
|
||||
|
||||
private storage: IStorageWrapper;
|
||||
private http: HttpServiceBase;
|
||||
private http: HttpSetup;
|
||||
private timer: ReturnType<typeof setInterval>;
|
||||
|
||||
constructor({ storage, http }: { storage: IStorageWrapper; http: HttpServiceBase }) {
|
||||
constructor({ storage, http }: { storage: IStorageWrapper; http: HttpSetup }) {
|
||||
this.storage = storage;
|
||||
this.http = http;
|
||||
|
||||
|
|
4
x-pack/plugins/reporting/index.d.ts
vendored
4
x-pack/plugins/reporting/index.d.ts
vendored
|
@ -7,7 +7,7 @@
|
|||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
HttpServiceBase,
|
||||
HttpSetup,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
NotificationsStart,
|
||||
|
@ -16,7 +16,7 @@ import {
|
|||
export type JobId = string;
|
||||
export type JobStatus = 'completed' | 'pending' | 'processing' | 'failed';
|
||||
|
||||
export type HttpService = HttpServiceBase;
|
||||
export type HttpService = HttpSetup;
|
||||
export type NotificationsService = NotificationsStart;
|
||||
|
||||
export interface SourceJob {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import sinon, { stub } from 'sinon';
|
||||
import { HttpServiceBase, NotificationsStart } from '../../../../../src/core/public';
|
||||
import { HttpSetup, NotificationsStart } from '../../../../../src/core/public';
|
||||
import { SourceJob, JobSummary, HttpService } from '../../index.d';
|
||||
import { JobQueue } from './job_queue';
|
||||
import { ReportingNotifierStreamHandler } from './stream_handler';
|
||||
|
@ -57,7 +57,7 @@ const httpMock: HttpService = ({
|
|||
basePath: {
|
||||
prepend: stub(),
|
||||
},
|
||||
} as unknown) as HttpServiceBase;
|
||||
} as unknown) as HttpSetup;
|
||||
|
||||
const mockShowDanger = stub();
|
||||
const mockShowSuccess = stub();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue