diff --git a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb._data-test-subj_.md b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb._data-test-subj_.md deleted file mode 100644 index 8cdfafb7c8d91..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb._data-test-subj_.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) > ["data-test-subj"](./kibana-plugin-public.chromebreadcrumb._data-test-subj_.md) - -## ChromeBreadcrumb."data-test-subj" property - -Signature: - -```typescript -'data-test-subj'?: string; -``` diff --git a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.href.md b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.href.md deleted file mode 100644 index b40f19c99f668..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.href.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) > [href](./kibana-plugin-public.chromebreadcrumb.href.md) - -## ChromeBreadcrumb.href property - -Signature: - -```typescript -href?: string; -``` diff --git a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.md b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.md index 883300f96753a..9350b56ce5f60 100644 --- a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.md +++ b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.md @@ -2,21 +2,11 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) -## ChromeBreadcrumb interface +## ChromeBreadcrumb type Signature: ```typescript -export interface ChromeBreadcrumb +export declare type ChromeBreadcrumb = EuiBreadcrumb; ``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| ["data-test-subj"](./kibana-plugin-public.chromebreadcrumb._data-test-subj_.md) | string | | -| [href](./kibana-plugin-public.chromebreadcrumb.href.md) | string | | -| [onClick](./kibana-plugin-public.chromebreadcrumb.onclick.md) | MouseEventHandler<HTMLButtonElement> | | -| [text](./kibana-plugin-public.chromebreadcrumb.text.md) | string | | - diff --git a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.onclick.md b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.onclick.md deleted file mode 100644 index 1e0ae36e893a1..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.onclick.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) > [onClick](./kibana-plugin-public.chromebreadcrumb.onclick.md) - -## ChromeBreadcrumb.onClick property - -Signature: - -```typescript -onClick?: MouseEventHandler; -``` diff --git a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.text.md b/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.text.md deleted file mode 100644 index fa7e3804576e3..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.chromebreadcrumb.text.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) > [text](./kibana-plugin-public.chromebreadcrumb.text.md) - -## ChromeBreadcrumb.text property - -Signature: - -```typescript -text: string; -``` diff --git a/docs/development/core/public/kibana-plugin-public.contextsetup.md b/docs/development/core/public/kibana-plugin-public.contextsetup.md index d9c158fcaae05..2b67c7cdaf0e1 100644 --- a/docs/development/core/public/kibana-plugin-public.contextsetup.md +++ b/docs/development/core/public/kibana-plugin-public.contextsetup.md @@ -91,18 +91,17 @@ export interface VizRenderContext { } export type VizRenderer = (context: VizRenderContext, domElement: HTMLElement) => () => void; +// When a renderer is bound via `contextContainer.createHandler` this is the type that will be returned. +type BoundVizRenderer = (domElement: HTMLElement) => () => void; class VizRenderingPlugin { - private readonly vizRenderers = new Map () => void)>(); + private readonly contextContainer?: IContextContainer; + private readonly vizRenderers = new Map(); constructor(private readonly initContext: PluginInitializerContext) {} setup(core) { - this.contextContainer = core.context.createContextContainer< - VizRenderContext, - ReturnType, - [HTMLElement] - >(); + this.contextContainer = core.context.createContextContainer(); return { registerContext: this.contextContainer.registerContext, diff --git a/docs/development/core/public/kibana-plugin-public.errortoastoptions.md b/docs/development/core/public/kibana-plugin-public.errortoastoptions.md index 135418632ac98..1755e6cbde919 100644 --- a/docs/development/core/public/kibana-plugin-public.errortoastoptions.md +++ b/docs/development/core/public/kibana-plugin-public.errortoastoptions.md @@ -4,6 +4,8 @@ ## ErrorToastOptions interface +Options available for [IToasts](./kibana-plugin-public.itoasts.md) APIs. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httperrorresponse.error.md b/docs/development/core/public/kibana-plugin-public.httperrorresponse.error.md index cb82a1f37f84e..59eee87cb70ba 100644 --- a/docs/development/core/public/kibana-plugin-public.httperrorresponse.error.md +++ b/docs/development/core/public/kibana-plugin-public.httperrorresponse.error.md @@ -7,5 +7,5 @@ Signature: ```typescript -error: Error | HttpFetchError; +error: Error | IHttpFetchError; ``` diff --git a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md index 0495195328fa2..1955bb57c50bf 100644 --- a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md +++ b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md @@ -16,7 +16,7 @@ export interface HttpErrorResponse | Property | Type | Description | | --- | --- | --- | | [body](./kibana-plugin-public.httperrorresponse.body.md) | HttpBody | | -| [error](./kibana-plugin-public.httperrorresponse.error.md) | Error | HttpFetchError | | +| [error](./kibana-plugin-public.httperrorresponse.error.md) | Error | IHttpFetchError | | | [request](./kibana-plugin-public.httperrorresponse.request.md) | Request | | | [response](./kibana-plugin-public.httperrorresponse.response.md) | Response | | diff --git a/docs/development/core/public/kibana-plugin-public.httpfetcherror._constructor_.md b/docs/development/core/public/kibana-plugin-public.httpfetcherror._constructor_.md deleted file mode 100644 index f7e057415715a..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpfetcherror._constructor_.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) > [(constructor)](./kibana-plugin-public.httpfetcherror._constructor_.md) - -## HttpFetchError.(constructor) - -Constructs a new instance of the `HttpFetchError` class - -Signature: - -```typescript -constructor(message: string, request: Request, response?: Response | undefined, body?: any); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| message | string | | -| request | Request | | -| response | Response | undefined | | -| body | any | | - diff --git a/docs/development/core/public/kibana-plugin-public.httpfetcherror.md b/docs/development/core/public/kibana-plugin-public.httpfetcherror.md deleted file mode 100644 index 70f2edfc7d201..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpfetcherror.md +++ /dev/null @@ -1,27 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) - -## HttpFetchError class - - -Signature: - -```typescript -export declare class HttpFetchError extends Error -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(message, request, response, body)](./kibana-plugin-public.httpfetcherror._constructor_.md) | | Constructs a new instance of the HttpFetchError class | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [body](./kibana-plugin-public.httpfetcherror.body.md) | | any | | -| [request](./kibana-plugin-public.httpfetcherror.request.md) | | Request | | -| [response](./kibana-plugin-public.httpfetcherror.response.md) | | Response | undefined | | - diff --git a/docs/development/core/public/kibana-plugin-public.httpfetcherror.response.md b/docs/development/core/public/kibana-plugin-public.httpfetcherror.response.md deleted file mode 100644 index 404d1b7c7abc0..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpfetcherror.response.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) > [response](./kibana-plugin-public.httpfetcherror.response.md) - -## HttpFetchError.response property - -Signature: - -```typescript -readonly response?: Response | undefined; -``` diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.headers.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.headers.md index 2fb4c448fe237..232b7d3da3af4 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.headers.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.headers.md @@ -4,6 +4,8 @@ ## HttpFetchOptions.headers property +Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md). + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md index 93fabb053871a..eca29b37425e9 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md @@ -4,6 +4,7 @@ ## HttpFetchOptions interface +All options that may be used with a [HttpHandler](./kibana-plugin-public.httphandler.md). Signature: @@ -15,7 +16,7 @@ export interface HttpFetchOptions extends HttpRequestInit | Property | Type | Description | | --- | --- | --- | -| [headers](./kibana-plugin-public.httpfetchoptions.headers.md) | HttpHeadersInit | | -| [prependBasePath](./kibana-plugin-public.httpfetchoptions.prependbasepath.md) | boolean | | -| [query](./kibana-plugin-public.httpfetchoptions.query.md) | HttpFetchQuery | | +| [headers](./kibana-plugin-public.httpfetchoptions.headers.md) | HttpHeadersInit | Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md). | +| [prependBasePath](./kibana-plugin-public.httpfetchoptions.prependbasepath.md) | boolean | Whether or not the request should automatically prepend the basePath. Defaults to true. | +| [query](./kibana-plugin-public.httpfetchoptions.query.md) | HttpFetchQuery | The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md). | diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.prependbasepath.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.prependbasepath.md index 5fff6c3518b56..0a6a8e195e565 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.prependbasepath.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.prependbasepath.md @@ -4,6 +4,8 @@ ## HttpFetchOptions.prependBasePath property +Whether or not the request should automatically prepend the basePath. Defaults to `true`. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.query.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.query.md index 2c24a3a3a548d..0f8d6ba83e772 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.query.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.query.md @@ -4,6 +4,8 @@ ## HttpFetchOptions.query property +The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md). + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httphandler.md b/docs/development/core/public/kibana-plugin-public.httphandler.md index 8bc9c3302252f..80fd1ea2e5761 100644 --- a/docs/development/core/public/kibana-plugin-public.httphandler.md +++ b/docs/development/core/public/kibana-plugin-public.httphandler.md @@ -4,6 +4,7 @@ ## HttpHandler type +A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. Signature: diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halt.md b/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halt.md deleted file mode 100644 index 36983d90cf8f4..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halt.md +++ /dev/null @@ -1,15 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpInterceptController](./kibana-plugin-public.httpinterceptcontroller.md) > [halt](./kibana-plugin-public.httpinterceptcontroller.halt.md) - -## HttpInterceptController.halt() method - -Signature: - -```typescript -halt(): void; -``` -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halted.md b/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halted.md deleted file mode 100644 index 18e380c0786bf..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.halted.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpInterceptController](./kibana-plugin-public.httpinterceptcontroller.md) > [halted](./kibana-plugin-public.httpinterceptcontroller.halted.md) - -## HttpInterceptController.halted property - -Signature: - -```typescript -readonly halted: boolean; -``` diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.md b/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.md deleted file mode 100644 index 03b91fde69cc3..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptcontroller.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpInterceptController](./kibana-plugin-public.httpinterceptcontroller.md) - -## HttpInterceptController class - -Signature: - -```typescript -export declare class HttpInterceptController -``` - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [halted](./kibana-plugin-public.httpinterceptcontroller.halted.md) | | boolean | | - -## Methods - -| Method | Modifiers | Description | -| --- | --- | --- | -| [halt()](./kibana-plugin-public.httpinterceptcontroller.halt.md) | | | - diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.md index c694151701ffb..cf7288a492ebb 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.md @@ -4,6 +4,7 @@ ## HttpInterceptor interface +An object that may define global interceptor functions for different parts of the request and response lifecycle. See [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md). Signature: @@ -15,8 +16,8 @@ export interface HttpInterceptor | Method | Description | | --- | --- | -| [request(request, controller)](./kibana-plugin-public.httpinterceptor.request.md) | | -| [requestError(httpErrorRequest, controller)](./kibana-plugin-public.httpinterceptor.requesterror.md) | | -| [response(httpResponse, controller)](./kibana-plugin-public.httpinterceptor.response.md) | | -| [responseError(httpErrorResponse, controller)](./kibana-plugin-public.httpinterceptor.responseerror.md) | | +| [request(request, controller)](./kibana-plugin-public.httpinterceptor.request.md) | Define an interceptor to be executed before a request is sent. | +| [requestError(httpErrorRequest, controller)](./kibana-plugin-public.httpinterceptor.requesterror.md) | Define an interceptor to be executed if a request interceptor throws an error or returns a rejected Promise. | +| [response(httpResponse, controller)](./kibana-plugin-public.httpinterceptor.response.md) | Define an interceptor to be executed after a response is received. | +| [responseError(httpErrorResponse, controller)](./kibana-plugin-public.httpinterceptor.responseerror.md) | Define an interceptor to be executed if a response interceptor throws an error or returns a rejected Promise. | diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.request.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.request.md index 0e57cf8dc51f9..4254e4aa8950c 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.request.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.request.md @@ -4,10 +4,12 @@ ## HttpInterceptor.request() method +Define an interceptor to be executed before a request is sent. + Signature: ```typescript -request?(request: Request, controller: HttpInterceptController): Promise | Request | void; +request?(request: Request, controller: IHttpInterceptController): Promise | Request | void; ``` ## Parameters @@ -15,7 +17,7 @@ request?(request: Request, controller: HttpInterceptController): PromiseRequest | | -| controller | HttpInterceptController | | +| controller | IHttpInterceptController | | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.requesterror.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.requesterror.md index 5c95e15697c35..af9b8641e7473 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.requesterror.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.requesterror.md @@ -4,10 +4,12 @@ ## HttpInterceptor.requestError() method +Define an interceptor to be executed if a request interceptor throws an error or returns a rejected Promise. + Signature: ```typescript -requestError?(httpErrorRequest: HttpErrorRequest, controller: HttpInterceptController): Promise | Request | void; +requestError?(httpErrorRequest: HttpErrorRequest, controller: IHttpInterceptController): Promise | Request | void; ``` ## Parameters @@ -15,7 +17,7 @@ requestError?(httpErrorRequest: HttpErrorRequest, controller: HttpInterceptContr | Parameter | Type | Description | | --- | --- | --- | | httpErrorRequest | HttpErrorRequest | | -| controller | HttpInterceptController | | +| controller | IHttpInterceptController | | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md index 01609eb2bbac7..6f4205f3362fe 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md @@ -4,10 +4,12 @@ ## HttpInterceptor.response() method +Define an interceptor to be executed after a response is received. + Signature: ```typescript -response?(httpResponse: HttpResponse, controller: HttpInterceptController): Promise | HttpResponse | void; +response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise | HttpResponse | void; ``` ## Parameters @@ -15,7 +17,7 @@ response?(httpResponse: HttpResponse, controller: HttpInterceptController): Prom | Parameter | Type | Description | | --- | --- | --- | | httpResponse | HttpResponse | | -| controller | HttpInterceptController | | +| controller | IHttpInterceptController | | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md index 71e0f11205d7b..1e7cd5e61186e 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md @@ -4,10 +4,12 @@ ## HttpInterceptor.responseError() method +Define an interceptor to be executed if a response interceptor throws an error or returns a rejected Promise. + Signature: ```typescript -responseError?(httpErrorResponse: HttpErrorResponse, controller: HttpInterceptController): Promise | HttpResponse | void; +responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | HttpResponse | void; ``` ## Parameters @@ -15,7 +17,7 @@ responseError?(httpErrorResponse: HttpErrorResponse, controller: HttpInterceptCo | Parameter | Type | Description | | --- | --- | --- | | httpErrorResponse | HttpErrorResponse | | -| controller | HttpInterceptController | | +| controller | IHttpInterceptController | | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.body.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.body.md index ecf8343ab529c..44b33c9917543 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.body.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.body.md @@ -4,6 +4,8 @@ ## HttpRequestInit.body property +A BodyInit object or null to set request's body. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.cache.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.cache.md index 813639b51f814..0f9dff3887ccf 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.cache.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.cache.md @@ -4,6 +4,8 @@ ## HttpRequestInit.cache property +The cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.credentials.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.credentials.md index 26e86722a8219..93c624cd1980c 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.credentials.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.credentials.md @@ -4,6 +4,8 @@ ## HttpRequestInit.credentials property +The credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.headers.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.headers.md index 2e5f86ebe38ef..0f885ed0df1a3 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.headers.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.headers.md @@ -4,6 +4,8 @@ ## HttpRequestInit.headers property +[HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.integrity.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.integrity.md index 9d8b3644aa9d7..7bb1665fdfcbe 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.integrity.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.integrity.md @@ -4,6 +4,8 @@ ## HttpRequestInit.integrity property +Subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.keepalive.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.keepalive.md index bb1a50c280dce..ba256188ce338 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.keepalive.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.keepalive.md @@ -4,6 +4,8 @@ ## HttpRequestInit.keepalive property +Whether or not request can outlive the global in which it was created. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.md index 89fa6d5379581..1271e039b0713 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.md @@ -4,6 +4,7 @@ ## HttpRequestInit interface +Fetch API options available to [HttpHandler](./kibana-plugin-public.httphandler.md)s. Signature: @@ -15,17 +16,17 @@ export interface HttpRequestInit | Property | Type | Description | | --- | --- | --- | -| [body](./kibana-plugin-public.httprequestinit.body.md) | BodyInit | null | | -| [cache](./kibana-plugin-public.httprequestinit.cache.md) | RequestCache | | -| [credentials](./kibana-plugin-public.httprequestinit.credentials.md) | RequestCredentials | | -| [headers](./kibana-plugin-public.httprequestinit.headers.md) | HttpHeadersInit | | -| [integrity](./kibana-plugin-public.httprequestinit.integrity.md) | string | | -| [keepalive](./kibana-plugin-public.httprequestinit.keepalive.md) | boolean | | -| [method](./kibana-plugin-public.httprequestinit.method.md) | string | | -| [mode](./kibana-plugin-public.httprequestinit.mode.md) | RequestMode | | -| [redirect](./kibana-plugin-public.httprequestinit.redirect.md) | RequestRedirect | | -| [referrer](./kibana-plugin-public.httprequestinit.referrer.md) | string | | -| [referrerPolicy](./kibana-plugin-public.httprequestinit.referrerpolicy.md) | ReferrerPolicy | | -| [signal](./kibana-plugin-public.httprequestinit.signal.md) | AbortSignal | null | | -| [window](./kibana-plugin-public.httprequestinit.window.md) | any | | +| [body](./kibana-plugin-public.httprequestinit.body.md) | BodyInit | null | A BodyInit object or null to set request's body. | +| [cache](./kibana-plugin-public.httprequestinit.cache.md) | RequestCache | The cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. | +| [credentials](./kibana-plugin-public.httprequestinit.credentials.md) | RequestCredentials | The credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. | +| [headers](./kibana-plugin-public.httprequestinit.headers.md) | HttpHeadersInit | [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) | +| [integrity](./kibana-plugin-public.httprequestinit.integrity.md) | string | Subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. | +| [keepalive](./kibana-plugin-public.httprequestinit.keepalive.md) | boolean | Whether or not request can outlive the global in which it was created. | +| [method](./kibana-plugin-public.httprequestinit.method.md) | string | HTTP method, which is "GET" by default. | +| [mode](./kibana-plugin-public.httprequestinit.mode.md) | RequestMode | The mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs. | +| [redirect](./kibana-plugin-public.httprequestinit.redirect.md) | RequestRedirect | The redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. | +| [referrer](./kibana-plugin-public.httprequestinit.referrer.md) | string | The referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and "about:client" when defaulting to the global's default. This is used during fetching to determine the value of the Referer header of the request being made. | +| [referrerPolicy](./kibana-plugin-public.httprequestinit.referrerpolicy.md) | ReferrerPolicy | The referrer policy associated with request. This is used during fetching to compute the value of the request's referrer. | +| [signal](./kibana-plugin-public.httprequestinit.signal.md) | AbortSignal | null | Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. | +| [window](./kibana-plugin-public.httprequestinit.window.md) | null | Can only be null. Used to disassociate request from any Window. | diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.method.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.method.md index 2aab899405576..c3465ae75521d 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.method.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.method.md @@ -4,6 +4,8 @@ ## HttpRequestInit.method property +HTTP method, which is "GET" by default. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.mode.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.mode.md index 611671331ee58..5ba625318eb27 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.mode.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.mode.md @@ -4,6 +4,8 @@ ## HttpRequestInit.mode property +The mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.redirect.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.redirect.md index 6795e99d370f3..b2554812fadf9 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.redirect.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.redirect.md @@ -4,6 +4,8 @@ ## HttpRequestInit.redirect property +The redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.referrer.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.referrer.md index 60e249cc9cf1d..56c9bcb4afaa9 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.referrer.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.referrer.md @@ -4,6 +4,8 @@ ## HttpRequestInit.referrer property +The referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and "about:client" when defaulting to the global's default. This is used during fetching to determine the value of the `Referer` header of the request being made. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.referrerpolicy.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.referrerpolicy.md index 3f92ee021f9cc..07231203c0030 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.referrerpolicy.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.referrerpolicy.md @@ -4,6 +4,8 @@ ## HttpRequestInit.referrerPolicy property +The referrer policy associated with request. This is used during fetching to compute the value of the request's referrer. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.signal.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.signal.md index 8657c6b7a1242..b0e863eaa804f 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.signal.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.signal.md @@ -4,6 +4,8 @@ ## HttpRequestInit.signal property +Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httprequestinit.window.md b/docs/development/core/public/kibana-plugin-public.httprequestinit.window.md index aec7fad7e3927..1a6d740065423 100644 --- a/docs/development/core/public/kibana-plugin-public.httprequestinit.window.md +++ b/docs/development/core/public/kibana-plugin-public.httprequestinit.window.md @@ -4,8 +4,10 @@ ## HttpRequestInit.window property +Can only be null. Used to disassociate request from any Window. + Signature: ```typescript -window?: any; +window?: null; ``` diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.addloadingcount.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.addloadingcount.md index 0dc64a3f75443..e984fea48625d 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.addloadingcount.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.addloadingcount.md @@ -4,17 +4,19 @@ ## HttpServiceBase.addLoadingCount() 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. + Signature: ```typescript -addLoadingCount(count$: Observable): void; +addLoadingCount(countSource$: Observable): void; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| count$ | Observable<number> | | +| countSource$ | Observable<number> | | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.basepath.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.basepath.md index 6794199dc9dbd..6c5f690a5c607 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.basepath.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.basepath.md @@ -4,12 +4,10 @@ ## HttpServiceBase.basePath property +APIs for manipulating the basePath on URL segments. + Signature: ```typescript -basePath: { - get: () => string; - prepend: (url: string) => string; - remove: (url: string) => string; - }; +basePath: IBasePath; ``` diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.delete.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.delete.md index 55e67a50b156f..73022ef4f2946 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.delete.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.delete.md @@ -4,6 +4,8 @@ ## HttpServiceBase.delete property +Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.fetch.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.fetch.md index 92936230149b6..3a1ae4892a3dd 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.fetch.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.fetch.md @@ -4,6 +4,8 @@ ## HttpServiceBase.fetch property +Makes an HTTP request. Defaults to a GET request unless overriden. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.get.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.get.md index d4b9a3810a497..a61b3dd140e50 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.get.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.get.md @@ -4,6 +4,8 @@ ## HttpServiceBase.get property +Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.getloadingcount_.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.getloadingcount_.md index 5b04c3327fd49..0b2129330cd01 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.getloadingcount_.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.getloadingcount_.md @@ -4,6 +4,8 @@ ## HttpServiceBase.getLoadingCount$() method +Get the sum of all loading count sources as a single Observable. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.head.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.head.md index 78546d0fbb4f3..4624d95f03bf3 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.head.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.head.md @@ -4,6 +4,8 @@ ## HttpServiceBase.head property +Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.intercept.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.intercept.md index 805884a21d18f..8cf5bf813df09 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.intercept.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.intercept.md @@ -4,6 +4,8 @@ ## HttpServiceBase.intercept() method +Adds a new [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) to the global HTTP client. + Signature: ```typescript @@ -20,3 +22,5 @@ intercept(interceptor: HttpInterceptor): () => void; `() => void` +a function for removing the attached interceptor. + diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.md index 71ddb6dee20a8..a1eef3db42b7d 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.md @@ -15,23 +15,22 @@ export interface HttpServiceBase | Property | Type | Description | | --- | --- | --- | -| [basePath](./kibana-plugin-public.httpservicebase.basepath.md) | {
get: () => string;
prepend: (url: string) => string;
remove: (url: string) => string;
} | | -| [delete](./kibana-plugin-public.httpservicebase.delete.md) | HttpHandler | | -| [fetch](./kibana-plugin-public.httpservicebase.fetch.md) | HttpHandler | | -| [get](./kibana-plugin-public.httpservicebase.get.md) | HttpHandler | | -| [head](./kibana-plugin-public.httpservicebase.head.md) | HttpHandler | | -| [options](./kibana-plugin-public.httpservicebase.options.md) | HttpHandler | | -| [patch](./kibana-plugin-public.httpservicebase.patch.md) | HttpHandler | | -| [post](./kibana-plugin-public.httpservicebase.post.md) | HttpHandler | | -| [put](./kibana-plugin-public.httpservicebase.put.md) | HttpHandler | | +| [basePath](./kibana-plugin-public.httpservicebase.basepath.md) | IBasePath | APIs for manipulating the basePath on URL segments. | +| [delete](./kibana-plugin-public.httpservicebase.delete.md) | HttpHandler | Makes an HTTP request with the DELETE method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [fetch](./kibana-plugin-public.httpservicebase.fetch.md) | HttpHandler | 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) | HttpHandler | Makes an HTTP request with the GET method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [head](./kibana-plugin-public.httpservicebase.head.md) | HttpHandler | Makes an HTTP request with the HEAD method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [options](./kibana-plugin-public.httpservicebase.options.md) | HttpHandler | Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [patch](./kibana-plugin-public.httpservicebase.patch.md) | HttpHandler | Makes an HTTP request with the PATCH method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [post](./kibana-plugin-public.httpservicebase.post.md) | HttpHandler | Makes an HTTP request with the POST method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | +| [put](./kibana-plugin-public.httpservicebase.put.md) | HttpHandler | Makes an HTTP request with the PUT method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. | ## Methods | Method | Description | | --- | --- | -| [addLoadingCount(count$)](./kibana-plugin-public.httpservicebase.addloadingcount.md) | | -| [getLoadingCount$()](./kibana-plugin-public.httpservicebase.getloadingcount_.md) | | -| [intercept(interceptor)](./kibana-plugin-public.httpservicebase.intercept.md) | | -| [removeAllInterceptors()](./kibana-plugin-public.httpservicebase.removeallinterceptors.md) | | -| [stop()](./kibana-plugin-public.httpservicebase.stop.md) | | +| [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. | diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.options.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.options.md index 6579a92f695a4..0820beb2752f2 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.options.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.options.md @@ -4,6 +4,8 @@ ## HttpServiceBase.options property +Makes an HTTP request with the OPTIONS method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.patch.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.patch.md index 3b81f2f863376..00e1ffc0e16bf 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.patch.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.patch.md @@ -4,6 +4,8 @@ ## HttpServiceBase.patch property +Makes an HTTP request with the PATCH method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.post.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.post.md index b990fd1458c33..3771a7c910895 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.post.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.post.md @@ -4,6 +4,8 @@ ## HttpServiceBase.post property +Makes an HTTP request with the POST method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.put.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.put.md index 3f41c6c21fec6..6e43aafa916bc 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.put.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.put.md @@ -4,6 +4,8 @@ ## HttpServiceBase.put property +Makes an HTTP request with the PUT method. See [HttpHandler](./kibana-plugin-public.httphandler.md) for options. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.removeallinterceptors.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.removeallinterceptors.md index 405baf458e516..0432ec29a22b6 100644 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.removeallinterceptors.md +++ b/docs/development/core/public/kibana-plugin-public.httpservicebase.removeallinterceptors.md @@ -4,6 +4,8 @@ ## HttpServiceBase.removeAllInterceptors() method +Removes all configured interceptors. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.httpservicebase.stop.md b/docs/development/core/public/kibana-plugin-public.httpservicebase.stop.md deleted file mode 100644 index 2a2323dbdda16..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpservicebase.stop.md +++ /dev/null @@ -1,15 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) > [stop](./kibana-plugin-public.httpservicebase.stop.md) - -## HttpServiceBase.stop() method - -Signature: - -```typescript -stop(): void; -``` -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-public.httpsetup.md b/docs/development/core/public/kibana-plugin-public.httpsetup.md index cc8ae6ab6aac1..7ef037ea7abd1 100644 --- a/docs/development/core/public/kibana-plugin-public.httpsetup.md +++ b/docs/development/core/public/kibana-plugin-public.httpsetup.md @@ -4,6 +4,7 @@ ## HttpSetup type +See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) Signature: diff --git a/docs/development/core/public/kibana-plugin-public.httpstart.md b/docs/development/core/public/kibana-plugin-public.httpstart.md index f70c08a1bde50..bb9247c63897a 100644 --- a/docs/development/core/public/kibana-plugin-public.httpstart.md +++ b/docs/development/core/public/kibana-plugin-public.httpstart.md @@ -4,6 +4,7 @@ ## HttpStart type +See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) Signature: diff --git a/docs/development/core/public/kibana-plugin-public.ibasepath.get.md b/docs/development/core/public/kibana-plugin-public.ibasepath.get.md new file mode 100644 index 0000000000000..08ca3afee11f7 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ibasepath.get.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IBasePath](./kibana-plugin-public.ibasepath.md) > [get](./kibana-plugin-public.ibasepath.get.md) + +## IBasePath.get property + +Gets the `basePath` string. + +Signature: + +```typescript +get: () => string; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ibasepath.md b/docs/development/core/public/kibana-plugin-public.ibasepath.md new file mode 100644 index 0000000000000..de392d45c4493 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ibasepath.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IBasePath](./kibana-plugin-public.ibasepath.md) + +## IBasePath interface + +APIs for manipulating the basePath on URL segments. + +Signature: + +```typescript +export interface IBasePath +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [get](./kibana-plugin-public.ibasepath.get.md) | () => string | Gets the basePath string. | +| [prepend](./kibana-plugin-public.ibasepath.prepend.md) | (url: string) => string | Prepends path with the basePath. | +| [remove](./kibana-plugin-public.ibasepath.remove.md) | (url: string) => string | Removes the prepended basePath from the path. | + diff --git a/docs/development/core/public/kibana-plugin-public.ibasepath.prepend.md b/docs/development/core/public/kibana-plugin-public.ibasepath.prepend.md new file mode 100644 index 0000000000000..48b909aa2f7a8 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ibasepath.prepend.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IBasePath](./kibana-plugin-public.ibasepath.md) > [prepend](./kibana-plugin-public.ibasepath.prepend.md) + +## IBasePath.prepend property + +Prepends `path` with the basePath. + +Signature: + +```typescript +prepend: (url: string) => string; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ibasepath.remove.md b/docs/development/core/public/kibana-plugin-public.ibasepath.remove.md new file mode 100644 index 0000000000000..6af8564420830 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ibasepath.remove.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IBasePath](./kibana-plugin-public.ibasepath.md) > [remove](./kibana-plugin-public.ibasepath.remove.md) + +## IBasePath.remove property + +Removes the prepended basePath from the `path`. + +Signature: + +```typescript +remove: (url: string) => string; +``` diff --git a/docs/development/core/public/kibana-plugin-public.httpfetcherror.body.md b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.body.md similarity index 53% rename from docs/development/core/public/kibana-plugin-public.httpfetcherror.body.md rename to docs/development/core/public/kibana-plugin-public.ihttpfetcherror.body.md index c373603b03569..2a5f3a68635b8 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetcherror.body.md +++ b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.body.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) > [body](./kibana-plugin-public.httpfetcherror.body.md) +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) > [body](./kibana-plugin-public.ihttpfetcherror.body.md) -## HttpFetchError.body property +## IHttpFetchError.body property Signature: diff --git a/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.md b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.md new file mode 100644 index 0000000000000..f33688affe8d5 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) + +## IHttpFetchError interface + + +Signature: + +```typescript +export interface IHttpFetchError extends Error +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [body](./kibana-plugin-public.ihttpfetcherror.body.md) | any | | +| [request](./kibana-plugin-public.ihttpfetcherror.request.md) | Request | | +| [response](./kibana-plugin-public.ihttpfetcherror.response.md) | Response | | + diff --git a/docs/development/core/public/kibana-plugin-public.httpfetcherror.request.md b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.request.md similarity index 52% rename from docs/development/core/public/kibana-plugin-public.httpfetcherror.request.md rename to docs/development/core/public/kibana-plugin-public.ihttpfetcherror.request.md index bd469952806a2..bbb1432f13bfb 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetcherror.request.md +++ b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.request.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) > [request](./kibana-plugin-public.httpfetcherror.request.md) +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) > [request](./kibana-plugin-public.ihttpfetcherror.request.md) -## HttpFetchError.request property +## IHttpFetchError.request property Signature: diff --git a/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.response.md b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.response.md new file mode 100644 index 0000000000000..c5efc1cc3858c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpfetcherror.response.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) > [response](./kibana-plugin-public.ihttpfetcherror.response.md) + +## IHttpFetchError.response property + +Signature: + +```typescript +readonly response?: Response; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halt.md b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halt.md new file mode 100644 index 0000000000000..6bd3e2e397b91 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halt.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) > [halt](./kibana-plugin-public.ihttpinterceptcontroller.halt.md) + +## IHttpInterceptController.halt() method + +Halt the request Promise chain and do not process further interceptors or response handlers. + +Signature: + +```typescript +halt(): void; +``` +Returns: + +`void` + diff --git a/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halted.md b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halted.md new file mode 100644 index 0000000000000..2e61e8da56e6f --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.halted.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) > [halted](./kibana-plugin-public.ihttpinterceptcontroller.halted.md) + +## IHttpInterceptController.halted property + +Whether or not this chain has been halted. + +Signature: + +```typescript +halted: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.md b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.md new file mode 100644 index 0000000000000..b07d9fceb91f0 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpinterceptcontroller.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) + +## IHttpInterceptController interface + +Used to halt a request Promise chain in a [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md). + +Signature: + +```typescript +export interface IHttpInterceptController +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [halted](./kibana-plugin-public.ihttpinterceptcontroller.halted.md) | boolean | Whether or not this chain has been halted. | + +## Methods + +| Method | Description | +| --- | --- | +| [halt()](./kibana-plugin-public.ihttpinterceptcontroller.halt.md) | Halt the request Promise chain and do not process further interceptors or response handlers. | + diff --git a/docs/development/core/public/kibana-plugin-public.itoasts.md b/docs/development/core/public/kibana-plugin-public.itoasts.md new file mode 100644 index 0000000000000..2a6d454e2194a --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.itoasts.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IToasts](./kibana-plugin-public.itoasts.md) + +## IToasts type + +Methods for adding and removing global toast messages. See [ToastsApi](./kibana-plugin-public.toastsapi.md). + +Signature: + +```typescript +export declare type IToasts = Pick; +``` diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md index 1e1a4f38a7c6f..3adf68ffb35a8 100644 --- a/docs/development/core/public/kibana-plugin-public.md +++ b/docs/development/core/public/kibana-plugin-public.md @@ -14,11 +14,9 @@ The plugin integrates with the core system via lifecycle events: `setup` | Class | Description | | --- | --- | -| [HttpFetchError](./kibana-plugin-public.httpfetcherror.md) | | -| [HttpInterceptController](./kibana-plugin-public.httpinterceptcontroller.md) | | | [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state. The client-side SavedObjectsClient is a thin convenience library around the SavedObjects HTTP API for interacting with Saved Objects. | | [SimpleSavedObject](./kibana-plugin-public.simplesavedobject.md) | This class is a very simple wrapper for SavedObjects loaded from the server with the [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md).It provides basic functionality for creating/saving/deleting saved objects, but doesn't include any type-specific implementations. | -| [ToastsApi](./kibana-plugin-public.toastsapi.md) | | +| [ToastsApi](./kibana-plugin-public.toastsapi.md) | Methods for adding and removing global toast messages. | | [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) | | ## Interfaces @@ -34,7 +32,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | | [ChromeBadge](./kibana-plugin-public.chromebadge.md) | | | [ChromeBrand](./kibana-plugin-public.chromebrand.md) | | -| [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | | | [ChromeNavControl](./kibana-plugin-public.chromenavcontrol.md) | | | [ChromeNavControls](./kibana-plugin-public.chromenavcontrols.md) | [APIs](./kibana-plugin-public.chromenavcontrols.md) for registering new controls to be displayed in the navigation bar. | | [ChromeNavLink](./kibana-plugin-public.chromenavlink.md) | | @@ -47,27 +44,30 @@ The plugin integrates with the core system via lifecycle events: `setup` | [CoreStart](./kibana-plugin-public.corestart.md) | Core services exposed to the Plugin start lifecycle | | [DocLinksStart](./kibana-plugin-public.doclinksstart.md) | | | [EnvironmentMode](./kibana-plugin-public.environmentmode.md) | | -| [ErrorToastOptions](./kibana-plugin-public.errortoastoptions.md) | | +| [ErrorToastOptions](./kibana-plugin-public.errortoastoptions.md) | Options available for [IToasts](./kibana-plugin-public.itoasts.md) APIs. | | [FatalErrorInfo](./kibana-plugin-public.fatalerrorinfo.md) | Represents the message and stack of a fatal Error | | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. | | [HttpErrorRequest](./kibana-plugin-public.httperrorrequest.md) | | | [HttpErrorResponse](./kibana-plugin-public.httperrorresponse.md) | | -| [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) | | +| [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) | All options that may be used with a [HttpHandler](./kibana-plugin-public.httphandler.md). | | [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md) | | | [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) | | -| [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) | | -| [HttpRequestInit](./kibana-plugin-public.httprequestinit.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. | | [HttpResponse](./kibana-plugin-public.httpresponse.md) | | | [HttpServiceBase](./kibana-plugin-public.httpservicebase.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. | +| [IBasePath](./kibana-plugin-public.ibasepath.md) | APIs for manipulating the basePath on URL segments. | | [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | An object that handles registration of context providers and configuring handlers with context. | +| [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) | | +| [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) | Used to halt a request Promise chain in a [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md). | | [LegacyCoreSetup](./kibana-plugin-public.legacycoresetup.md) | Setup interface exposed to the legacy platform via the ui/new_platform module. | | [LegacyCoreStart](./kibana-plugin-public.legacycorestart.md) | Start interface exposed to the legacy platform via the ui/new_platform module. | | [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) | | | [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | | | [NotificationsStart](./kibana-plugin-public.notificationsstart.md) | | | [OverlayBannersStart](./kibana-plugin-public.overlaybannersstart.md) | | -| [OverlayRef](./kibana-plugin-public.overlayref.md) | | +| [OverlayRef](./kibana-plugin-public.overlayref.md) | Returned by [OverlayStart](./kibana-plugin-public.overlaystart.md) methods for closing a mounted overlay. | | [OverlayStart](./kibana-plugin-public.overlaystart.md) | | | [PackageInfo](./kibana-plugin-public.packageinfo.md) | | | [Plugin](./kibana-plugin-public.plugin.md) | The interface that should be returned by a PluginInitializer. | @@ -92,16 +92,18 @@ The plugin integrates with the core system via lifecycle events: `setup` | Type Alias | Description | | --- | --- | | [AppUnmount](./kibana-plugin-public.appunmount.md) | A function called when an application should be unmounted from the page. This function should be synchronous. | +| [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | | | [ChromeHelpExtension](./kibana-plugin-public.chromehelpextension.md) | | | [ChromeNavLinkUpdateableFields](./kibana-plugin-public.chromenavlinkupdateablefields.md) | | | [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). | | [HttpBody](./kibana-plugin-public.httpbody.md) | | -| [HttpHandler](./kibana-plugin-public.httphandler.md) | | -| [HttpSetup](./kibana-plugin-public.httpsetup.md) | | -| [HttpStart](./kibana-plugin-public.httpstart.md) | | +| [HttpHandler](./kibana-plugin-public.httphandler.md) | A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. | +| [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) | | [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). | | [OverlayBannerMount](./kibana-plugin-public.overlaybannermount.md) | A function that will mount the banner inside the provided element. | | [OverlayBannerUnmount](./kibana-plugin-public.overlaybannerunmount.md) | A function that will unmount the banner from the element. | | [PluginInitializer](./kibana-plugin-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | @@ -110,6 +112,9 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectAttribute](./kibana-plugin-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-public.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-public.savedobjectattribute.md) | | [SavedObjectsClientContract](./kibana-plugin-public.savedobjectsclientcontract.md) | SavedObjectsClientContract as implemented by the [SavedObjectsClient](./kibana-plugin-public.savedobjectsclient.md) | -| [ToastInput](./kibana-plugin-public.toastinput.md) | | +| [ToastInput](./kibana-plugin-public.toastinput.md) | Inputs for [IToasts](./kibana-plugin-public.itoasts.md) APIs. | +| [ToastInputFields](./kibana-plugin-public.toastinputfields.md) | Allowed fields for [ToastInput](./kibana-plugin-public.toastinput.md). | +| [ToastsSetup](./kibana-plugin-public.toastssetup.md) | [IToasts](./kibana-plugin-public.itoasts.md) | +| [ToastsStart](./kibana-plugin-public.toastsstart.md) | [IToasts](./kibana-plugin-public.itoasts.md) | | [UiSettingsClientContract](./kibana-plugin-public.uisettingsclientcontract.md) | [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) | diff --git a/docs/development/core/public/kibana-plugin-public.notificationssetup.md b/docs/development/core/public/kibana-plugin-public.notificationssetup.md index 7d9dd2e89f851..c03abf9d01dca 100644 --- a/docs/development/core/public/kibana-plugin-public.notificationssetup.md +++ b/docs/development/core/public/kibana-plugin-public.notificationssetup.md @@ -15,5 +15,5 @@ export interface NotificationsSetup | Property | Type | Description | | --- | --- | --- | -| [toasts](./kibana-plugin-public.notificationssetup.toasts.md) | ToastsSetup | | +| [toasts](./kibana-plugin-public.notificationssetup.toasts.md) | ToastsSetup | [ToastsSetup](./kibana-plugin-public.toastssetup.md) | diff --git a/docs/development/core/public/kibana-plugin-public.notificationssetup.toasts.md b/docs/development/core/public/kibana-plugin-public.notificationssetup.toasts.md index c44ec9ca93e65..dd613a959061e 100644 --- a/docs/development/core/public/kibana-plugin-public.notificationssetup.toasts.md +++ b/docs/development/core/public/kibana-plugin-public.notificationssetup.toasts.md @@ -4,6 +4,8 @@ ## NotificationsSetup.toasts property +[ToastsSetup](./kibana-plugin-public.toastssetup.md) + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.notificationsstart.md b/docs/development/core/public/kibana-plugin-public.notificationsstart.md index acab2d6884418..56a1ce2095742 100644 --- a/docs/development/core/public/kibana-plugin-public.notificationsstart.md +++ b/docs/development/core/public/kibana-plugin-public.notificationsstart.md @@ -15,5 +15,5 @@ export interface NotificationsStart | Property | Type | Description | | --- | --- | --- | -| [toasts](./kibana-plugin-public.notificationsstart.toasts.md) | ToastsStart | | +| [toasts](./kibana-plugin-public.notificationsstart.toasts.md) | ToastsStart | [ToastsStart](./kibana-plugin-public.toastsstart.md) | diff --git a/docs/development/core/public/kibana-plugin-public.notificationsstart.toasts.md b/docs/development/core/public/kibana-plugin-public.notificationsstart.toasts.md index db2be3dad8351..9d2c685946fda 100644 --- a/docs/development/core/public/kibana-plugin-public.notificationsstart.toasts.md +++ b/docs/development/core/public/kibana-plugin-public.notificationsstart.toasts.md @@ -4,6 +4,8 @@ ## NotificationsStart.toasts property +[ToastsStart](./kibana-plugin-public.toastsstart.md) + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.overlayref.md b/docs/development/core/public/kibana-plugin-public.overlayref.md index ba573ccf10bbe..e71415280e4d2 100644 --- a/docs/development/core/public/kibana-plugin-public.overlayref.md +++ b/docs/development/core/public/kibana-plugin-public.overlayref.md @@ -4,6 +4,8 @@ ## OverlayRef interface +Returned by [OverlayStart](./kibana-plugin-public.overlaystart.md) methods for closing a mounted overlay. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.toastinput.md b/docs/development/core/public/kibana-plugin-public.toastinput.md index 8e798697fa6c0..75f12b3d94561 100644 --- a/docs/development/core/public/kibana-plugin-public.toastinput.md +++ b/docs/development/core/public/kibana-plugin-public.toastinput.md @@ -4,6 +4,7 @@ ## ToastInput type +Inputs for [IToasts](./kibana-plugin-public.itoasts.md) APIs. Signature: diff --git a/docs/development/core/public/kibana-plugin-public.toastinputfields.md b/docs/development/core/public/kibana-plugin-public.toastinputfields.md new file mode 100644 index 0000000000000..ffcf9e5c6dea2 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.toastinputfields.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ToastInputFields](./kibana-plugin-public.toastinputfields.md) + +## ToastInputFields type + +Allowed fields for [ToastInput](./kibana-plugin-public.toastinput.md). + +Signature: + +```typescript +export declare type ToastInputFields = Pick>; +``` + +## Remarks + +`id` cannot be specified. + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.add.md b/docs/development/core/public/kibana-plugin-public.toastsapi.add.md index a59c11d0d5f53..8e9648031f0e2 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.add.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.add.md @@ -4,6 +4,8 @@ ## ToastsApi.add() method +Adds a new toast to current array of toast. + Signature: ```typescript @@ -14,9 +16,11 @@ add(toastOrTitle: ToastInput): Toast; | Parameter | Type | Description | | --- | --- | --- | -| toastOrTitle | ToastInput | | +| toastOrTitle | ToastInput | a [ToastInput](./kibana-plugin-public.toastinput.md) | Returns: `Toast` +a + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.adddanger.md b/docs/development/core/public/kibana-plugin-public.toastsapi.adddanger.md index 3f9e6b1c389da..28e596f0c09e3 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.adddanger.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.adddanger.md @@ -4,6 +4,8 @@ ## ToastsApi.addDanger() method +Adds a new toast pre-configured with the danger color and alert icon. + Signature: ```typescript @@ -14,9 +16,11 @@ addDanger(toastOrTitle: ToastInput): Toast; | Parameter | Type | Description | | --- | --- | --- | -| toastOrTitle | ToastInput | | +| toastOrTitle | ToastInput | a [ToastInput](./kibana-plugin-public.toastinput.md) | Returns: `Toast` +a + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.adderror.md b/docs/development/core/public/kibana-plugin-public.toastsapi.adderror.md index 10aaf50ebab4d..c8a48b3fa46c9 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.adderror.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.adderror.md @@ -4,6 +4,8 @@ ## ToastsApi.addError() method +Adds a new toast that displays an exception message with a button to open the full stacktrace in a modal. + Signature: ```typescript @@ -14,10 +16,12 @@ addError(error: Error, options: ErrorToastOptions): Toast; | Parameter | Type | Description | | --- | --- | --- | -| error | Error | | -| options | ErrorToastOptions | | +| error | Error | an Error instance. | +| options | ErrorToastOptions | [ErrorToastOptions](./kibana-plugin-public.errortoastoptions.md) | Returns: `Toast` +a + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.addsuccess.md b/docs/development/core/public/kibana-plugin-public.toastsapi.addsuccess.md index 5aff3229b3c81..0e01dc1364d07 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.addsuccess.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.addsuccess.md @@ -4,6 +4,8 @@ ## ToastsApi.addSuccess() method +Adds a new toast pre-configured with the success color and check icon. + Signature: ```typescript @@ -14,9 +16,11 @@ addSuccess(toastOrTitle: ToastInput): Toast; | Parameter | Type | Description | | --- | --- | --- | -| toastOrTitle | ToastInput | | +| toastOrTitle | ToastInput | a [ToastInput](./kibana-plugin-public.toastinput.md) | Returns: `Toast` +a + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.addwarning.md b/docs/development/core/public/kibana-plugin-public.toastsapi.addwarning.md index 3b68f0b7fe22a..0e236f2737b12 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.addwarning.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.addwarning.md @@ -4,6 +4,8 @@ ## ToastsApi.addWarning() method +Adds a new toast pre-configured with the warning color and help icon. + Signature: ```typescript @@ -14,9 +16,11 @@ addWarning(toastOrTitle: ToastInput): Toast; | Parameter | Type | Description | | --- | --- | --- | -| toastOrTitle | ToastInput | | +| toastOrTitle | ToastInput | a [ToastInput](./kibana-plugin-public.toastinput.md) | Returns: `Toast` +a + diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.get_.md b/docs/development/core/public/kibana-plugin-public.toastsapi.get_.md index 1761fa21b70e8..48e4fdc7a2ec0 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.get_.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.get_.md @@ -4,6 +4,8 @@ ## ToastsApi.get$() method +Observable of the toast messages to show to the user. + Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.md b/docs/development/core/public/kibana-plugin-public.toastsapi.md index 1d5e0382d9465..e47f6d5c8ac59 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.md @@ -4,11 +4,12 @@ ## ToastsApi class +Methods for adding and removing global toast messages. Signature: ```typescript -export declare class ToastsApi +export declare class ToastsApi implements IToasts ``` ## Constructors @@ -21,12 +22,11 @@ export declare class ToastsApi | Method | Modifiers | Description | | --- | --- | --- | -| [add(toastOrTitle)](./kibana-plugin-public.toastsapi.add.md) | | | -| [addDanger(toastOrTitle)](./kibana-plugin-public.toastsapi.adddanger.md) | | | -| [addError(error, options)](./kibana-plugin-public.toastsapi.adderror.md) | | | -| [addSuccess(toastOrTitle)](./kibana-plugin-public.toastsapi.addsuccess.md) | | | -| [addWarning(toastOrTitle)](./kibana-plugin-public.toastsapi.addwarning.md) | | | -| [get$()](./kibana-plugin-public.toastsapi.get_.md) | | | -| [registerOverlays(overlays)](./kibana-plugin-public.toastsapi.registeroverlays.md) | | | -| [remove(toast)](./kibana-plugin-public.toastsapi.remove.md) | | | +| [add(toastOrTitle)](./kibana-plugin-public.toastsapi.add.md) | | Adds a new toast to current array of toast. | +| [addDanger(toastOrTitle)](./kibana-plugin-public.toastsapi.adddanger.md) | | Adds a new toast pre-configured with the danger color and alert icon. | +| [addError(error, options)](./kibana-plugin-public.toastsapi.adderror.md) | | Adds a new toast that displays an exception message with a button to open the full stacktrace in a modal. | +| [addSuccess(toastOrTitle)](./kibana-plugin-public.toastsapi.addsuccess.md) | | Adds a new toast pre-configured with the success color and check icon. | +| [addWarning(toastOrTitle)](./kibana-plugin-public.toastsapi.addwarning.md) | | Adds a new toast pre-configured with the warning color and help icon. | +| [get$()](./kibana-plugin-public.toastsapi.get_.md) | | Observable of the toast messages to show to the user. | +| [remove(toast)](./kibana-plugin-public.toastsapi.remove.md) | | Removes a toast from the current array of toasts if present. | diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.registeroverlays.md b/docs/development/core/public/kibana-plugin-public.toastsapi.registeroverlays.md deleted file mode 100644 index 31601e9b215bc..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.registeroverlays.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ToastsApi](./kibana-plugin-public.toastsapi.md) > [registerOverlays](./kibana-plugin-public.toastsapi.registeroverlays.md) - -## ToastsApi.registerOverlays() method - -Signature: - -```typescript -registerOverlays(overlays: OverlayStart): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| overlays | OverlayStart | | - -Returns: - -`void` - diff --git a/docs/development/core/public/kibana-plugin-public.toastsapi.remove.md b/docs/development/core/public/kibana-plugin-public.toastsapi.remove.md index 822677a42b630..5025c83a666c8 100644 --- a/docs/development/core/public/kibana-plugin-public.toastsapi.remove.md +++ b/docs/development/core/public/kibana-plugin-public.toastsapi.remove.md @@ -4,6 +4,8 @@ ## ToastsApi.remove() method +Removes a toast from the current array of toasts if present. + Signature: ```typescript @@ -14,7 +16,7 @@ remove(toast: Toast): void; | Parameter | Type | Description | | --- | --- | --- | -| toast | Toast | | +| toast | Toast | a returned by | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.toastssetup.md b/docs/development/core/public/kibana-plugin-public.toastssetup.md new file mode 100644 index 0000000000000..e06dd7f7093bb --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.toastssetup.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ToastsSetup](./kibana-plugin-public.toastssetup.md) + +## ToastsSetup type + +[IToasts](./kibana-plugin-public.itoasts.md) + +Signature: + +```typescript +export declare type ToastsSetup = IToasts; +``` diff --git a/docs/development/core/public/kibana-plugin-public.toastsstart.md b/docs/development/core/public/kibana-plugin-public.toastsstart.md new file mode 100644 index 0000000000000..6e090dcdc64fb --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.toastsstart.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ToastsStart](./kibana-plugin-public.toastsstart.md) + +## ToastsStart type + +[IToasts](./kibana-plugin-public.itoasts.md) + +Signature: + +```typescript +export declare type ToastsStart = IToasts; +``` diff --git a/docs/development/core/server/kibana-plugin-server.assistanceapiresponse.md b/docs/development/core/server/kibana-plugin-server.assistanceapiresponse.md index 8e8dfb07ca08a..398fe62ce2479 100644 --- a/docs/development/core/server/kibana-plugin-server.assistanceapiresponse.md +++ b/docs/development/core/server/kibana-plugin-server.assistanceapiresponse.md @@ -4,6 +4,7 @@ ## AssistanceAPIResponse interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.assistantapiclientparams.md b/docs/development/core/server/kibana-plugin-server.assistantapiclientparams.md index eb03b943a30ef..cf7ca56c8a75e 100644 --- a/docs/development/core/server/kibana-plugin-server.assistantapiclientparams.md +++ b/docs/development/core/server/kibana-plugin-server.assistantapiclientparams.md @@ -4,6 +4,7 @@ ## AssistantAPIClientParams interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.authenticated.md b/docs/development/core/server/kibana-plugin-server.authenticated.md new file mode 100644 index 0000000000000..d955f1f32f1f7 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.authenticated.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [Authenticated](./kibana-plugin-server.authenticated.md) + +## Authenticated interface + + +Signature: + +```typescript +export interface Authenticated extends AuthResultParams +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./kibana-plugin-server.authenticated.type.md) | AuthResultType.authenticated | | + diff --git a/docs/development/core/server/kibana-plugin-server.authenticated.type.md b/docs/development/core/server/kibana-plugin-server.authenticated.type.md new file mode 100644 index 0000000000000..08a73e812d157 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.authenticated.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [Authenticated](./kibana-plugin-server.authenticated.md) > [type](./kibana-plugin-server.authenticated.type.md) + +## Authenticated.type property + +Signature: + +```typescript +type: AuthResultType.authenticated; +``` diff --git a/docs/development/core/server/kibana-plugin-server.authenticationhandler.md b/docs/development/core/server/kibana-plugin-server.authenticationhandler.md index ced5cfd9413ec..ff60e6e811ed6 100644 --- a/docs/development/core/server/kibana-plugin-server.authenticationhandler.md +++ b/docs/development/core/server/kibana-plugin-server.authenticationhandler.md @@ -4,9 +4,10 @@ ## AuthenticationHandler type +See [AuthToolkit](./kibana-plugin-server.authtoolkit.md). Signature: ```typescript -export declare type AuthenticationHandler = (request: KibanaRequest, response: LifecycleResponseFactory, toolkit: AuthToolkit) => AuthResult | KibanaResponse | Promise; +export declare type AuthenticationHandler = (request: KibanaRequest, response: LifecycleResponseFactory, toolkit: AuthToolkit) => AuthResult | IKibanaResponse | Promise; ``` diff --git a/docs/development/core/server/kibana-plugin-server.authresult.md b/docs/development/core/server/kibana-plugin-server.authresult.md new file mode 100644 index 0000000000000..5d1bdbc8e7118 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.authresult.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [AuthResult](./kibana-plugin-server.authresult.md) + +## AuthResult type + + +Signature: + +```typescript +export declare type AuthResult = Authenticated; +``` diff --git a/docs/development/core/server/kibana-plugin-server.authresulttype.md b/docs/development/core/server/kibana-plugin-server.authresulttype.md new file mode 100644 index 0000000000000..e8962cb14d198 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.authresulttype.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [AuthResultType](./kibana-plugin-server.authresulttype.md) + +## AuthResultType enum + + +Signature: + +```typescript +export declare enum AuthResultType +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| authenticated | "authenticated" | | + diff --git a/docs/development/core/server/kibana-plugin-server.basepath.md b/docs/development/core/server/kibana-plugin-server.basepath.md index bfa1ea02aec17..da833c71bf93b 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.md @@ -17,8 +17,8 @@ export declare class BasePath | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [get](./kibana-plugin-server.basepath.get.md) | | (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown>) => string | returns basePath value, specific for an incoming request. | -| [prepend](./kibana-plugin-server.basepath.prepend.md) | | (path: string) => string | returns a new basePath value, prefixed with passed url. | -| [remove](./kibana-plugin-server.basepath.remove.md) | | (path: string) => string | returns a new basePath value, cleaned up from passed url. | +| [prepend](./kibana-plugin-server.basepath.prepend.md) | | (path: string) => string | Prepends path with the basePath. | +| [remove](./kibana-plugin-server.basepath.remove.md) | | (path: string) => string | Removes the prepended basePath from the path. | | [serverBasePath](./kibana-plugin-server.basepath.serverbasepath.md) | | string | returns the server's basePathSee [BasePath.get](./kibana-plugin-server.basepath.get.md) for getting the basePath value for a specific request | | [set](./kibana-plugin-server.basepath.set.md) | | (request: LegacyRequest | KibanaRequest<unknown, unknown, unknown>, requestSpecificBasePath: string) => void | sets basePath value, specific for an incoming request. | diff --git a/docs/development/core/server/kibana-plugin-server.basepath.prepend.md b/docs/development/core/server/kibana-plugin-server.basepath.prepend.md index 113e8d9bf4880..9a615dfe80f32 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.prepend.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.prepend.md @@ -4,7 +4,7 @@ ## BasePath.prepend property -returns a new `basePath` value, prefixed with passed `url`. +Prepends `path` with the basePath. Signature: diff --git a/docs/development/core/server/kibana-plugin-server.basepath.remove.md b/docs/development/core/server/kibana-plugin-server.basepath.remove.md index c5f1092d2969d..8fcfbc2b921d3 100644 --- a/docs/development/core/server/kibana-plugin-server.basepath.remove.md +++ b/docs/development/core/server/kibana-plugin-server.basepath.remove.md @@ -4,7 +4,7 @@ ## BasePath.remove property -returns a new `basePath` value, cleaned up from passed `url`. +Removes the prepended basePath from the `path`. Signature: diff --git a/docs/development/core/server/kibana-plugin-server.clusterclient.asscoped.md b/docs/development/core/server/kibana-plugin-server.clusterclient.asscoped.md index f87fc34bdc45f..ed7d028a1ec8a 100644 --- a/docs/development/core/server/kibana-plugin-server.clusterclient.asscoped.md +++ b/docs/development/core/server/kibana-plugin-server.clusterclient.asscoped.md @@ -4,7 +4,7 @@ ## ClusterClient.asScoped() method -Creates an instance of `ScopedClusterClient` based on the configuration the current cluster client that exposes additional `callAsCurrentUser` method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. +Creates an instance of [IScopedClusterClient](./kibana-plugin-server.iscopedclusterclient.md) based on the configuration the current cluster client that exposes additional `callAsCurrentUser` method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. Signature: @@ -16,7 +16,7 @@ asScoped(request?: KibanaRequest | LegacyRequest | FakeRequest): IScopedClusterC | Parameter | Type | Description | | --- | --- | --- | -| request | KibanaRequest | LegacyRequest | FakeRequest | Request the ScopedClusterClient instance will be scoped to. Supports request optionality, Legacy.Request & FakeRequest for BWC with LegacyPlatform | +| request | KibanaRequest | LegacyRequest | FakeRequest | Request the IScopedClusterClient instance will be scoped to. Supports request optionality, Legacy.Request & FakeRequest for BWC with LegacyPlatform | Returns: diff --git a/docs/development/core/server/kibana-plugin-server.clusterclient.callasinternaluser.md b/docs/development/core/server/kibana-plugin-server.clusterclient.callasinternaluser.md index 74003189c765d..7afb6afa4bc3b 100644 --- a/docs/development/core/server/kibana-plugin-server.clusterclient.callasinternaluser.md +++ b/docs/development/core/server/kibana-plugin-server.clusterclient.callasinternaluser.md @@ -4,7 +4,7 @@ ## ClusterClient.callAsInternalUser property -Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. +Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-server.apicaller.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.clusterclient.md b/docs/development/core/server/kibana-plugin-server.clusterclient.md index 6288bc0a07c11..5fdda7ef3e499 100644 --- a/docs/development/core/server/kibana-plugin-server.clusterclient.md +++ b/docs/development/core/server/kibana-plugin-server.clusterclient.md @@ -24,12 +24,12 @@ export declare class ClusterClient implements IClusterClient | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [callAsInternalUser](./kibana-plugin-server.clusterclient.callasinternaluser.md) | | APICaller | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. | +| [callAsInternalUser](./kibana-plugin-server.clusterclient.callasinternaluser.md) | | APICaller | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-server.apicaller.md). | ## Methods | Method | Modifiers | Description | | --- | --- | --- | -| [asScoped(request)](./kibana-plugin-server.clusterclient.asscoped.md) | | Creates an instance of ScopedClusterClient based on the configuration the current cluster client that exposes additional callAsCurrentUser method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. | +| [asScoped(request)](./kibana-plugin-server.clusterclient.asscoped.md) | | Creates an instance of [IScopedClusterClient](./kibana-plugin-server.iscopedclusterclient.md) based on the configuration the current cluster client that exposes additional callAsCurrentUser method scoped to the provided req. Consumers shouldn't worry about closing scoped client instances, these will be automatically closed as soon as the original cluster client isn't needed anymore and closed. | | [close()](./kibana-plugin-server.clusterclient.close.md) | | Closes the cluster client. After that client cannot be used and one should create a new client instance to be able to interact with Elasticsearch API. | diff --git a/docs/development/core/server/kibana-plugin-server.contextsetup.md b/docs/development/core/server/kibana-plugin-server.contextsetup.md index 0b4f5aa5d403b..67504faf0534a 100644 --- a/docs/development/core/server/kibana-plugin-server.contextsetup.md +++ b/docs/development/core/server/kibana-plugin-server.contextsetup.md @@ -91,18 +91,17 @@ export interface VizRenderContext { } export type VizRenderer = (context: VizRenderContext, domElement: HTMLElement) => () => void; +// When a renderer is bound via `contextContainer.createHandler` this is the type that will be returned. +type BoundVizRenderer = (domElement: HTMLElement) => () => void; class VizRenderingPlugin { - private readonly vizRenderers = new Map () => void)>(); + private readonly contextContainer?: IContextContainer; + private readonly vizRenderers = new Map(); constructor(private readonly initContext: PluginInitializerContext) {} setup(core) { - this.contextContainer = core.context.createContextContainer< - VizRenderContext, - ReturnType, - [HTMLElement] - >(); + this.contextContainer = core.context.createContextContainer(); return { registerContext: this.contextContainer.registerContext, diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.context.md b/docs/development/core/server/kibana-plugin-server.coresetup.context.md index e98cd6a0d04e1..63c37eec70b05 100644 --- a/docs/development/core/server/kibana-plugin-server.coresetup.context.md +++ b/docs/development/core/server/kibana-plugin-server.coresetup.context.md @@ -4,10 +4,10 @@ ## CoreSetup.context property +[ContextSetup](./kibana-plugin-server.contextsetup.md) + Signature: ```typescript -context: { - createContextContainer: ContextSetup['createContextContainer']; - }; +context: ContextSetup; ``` diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.elasticsearch.md b/docs/development/core/server/kibana-plugin-server.coresetup.elasticsearch.md index dfe1839babdad..9498e0223350d 100644 --- a/docs/development/core/server/kibana-plugin-server.coresetup.elasticsearch.md +++ b/docs/development/core/server/kibana-plugin-server.coresetup.elasticsearch.md @@ -4,12 +4,10 @@ ## CoreSetup.elasticsearch property +[ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) + Signature: ```typescript -elasticsearch: { - adminClient$: Observable; - dataClient$: Observable; - createClient: (type: string, clientConfig?: Partial) => IClusterClient; - }; +elasticsearch: ElasticsearchServiceSetup; ``` diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.http.md b/docs/development/core/server/kibana-plugin-server.coresetup.http.md index 8474f4ef940dc..09b12bca7b275 100644 --- a/docs/development/core/server/kibana-plugin-server.coresetup.http.md +++ b/docs/development/core/server/kibana-plugin-server.coresetup.http.md @@ -4,17 +4,10 @@ ## CoreSetup.http property +[HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) + Signature: ```typescript -http: { - createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory']; - registerOnPreAuth: HttpServiceSetup['registerOnPreAuth']; - registerAuth: HttpServiceSetup['registerAuth']; - registerOnPostAuth: HttpServiceSetup['registerOnPostAuth']; - basePath: HttpServiceSetup['basePath']; - isTlsEnabled: HttpServiceSetup['isTlsEnabled']; - registerRouteHandlerContext: (name: T, provider: RequestHandlerContextProvider) => RequestHandlerContextContainer; - createRouter: () => IRouter; - }; +http: HttpServiceSetup; ``` diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.md b/docs/development/core/server/kibana-plugin-server.coresetup.md index a53f807d001bd..a6dda69fd154e 100644 --- a/docs/development/core/server/kibana-plugin-server.coresetup.md +++ b/docs/development/core/server/kibana-plugin-server.coresetup.md @@ -16,7 +16,7 @@ export interface CoreSetup | Property | Type | Description | | --- | --- | --- | -| [context](./kibana-plugin-server.coresetup.context.md) | {
createContextContainer: ContextSetup['createContextContainer'];
} | | -| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | {
adminClient$: Observable<IClusterClient>;
dataClient$: Observable<IClusterClient>;
createClient: (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => IClusterClient;
} | | -| [http](./kibana-plugin-server.coresetup.http.md) | {
createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory'];
registerOnPreAuth: HttpServiceSetup['registerOnPreAuth'];
registerAuth: HttpServiceSetup['registerAuth'];
registerOnPostAuth: HttpServiceSetup['registerOnPostAuth'];
basePath: HttpServiceSetup['basePath'];
isTlsEnabled: HttpServiceSetup['isTlsEnabled'];
registerRouteHandlerContext: <T extends keyof RequestHandlerContext>(name: T, provider: RequestHandlerContextProvider<T>) => RequestHandlerContextContainer;
createRouter: () => IRouter;
} | | +| [context](./kibana-plugin-server.coresetup.context.md) | ContextSetup | [ContextSetup](./kibana-plugin-server.contextsetup.md) | +| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | ElasticsearchServiceSetup | [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) | +| [http](./kibana-plugin-server.coresetup.http.md) | HttpServiceSetup | [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) | diff --git a/docs/development/core/server/kibana-plugin-server.deprecationapiclientparams.md b/docs/development/core/server/kibana-plugin-server.deprecationapiclientparams.md index 3dfe6b181a3d3..47af79ae464b2 100644 --- a/docs/development/core/server/kibana-plugin-server.deprecationapiclientparams.md +++ b/docs/development/core/server/kibana-plugin-server.deprecationapiclientparams.md @@ -4,6 +4,7 @@ ## DeprecationAPIClientParams interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.deprecationapiresponse.md b/docs/development/core/server/kibana-plugin-server.deprecationapiresponse.md index 8ebe61f4efaa5..5a2954d10c161 100644 --- a/docs/development/core/server/kibana-plugin-server.deprecationapiresponse.md +++ b/docs/development/core/server/kibana-plugin-server.deprecationapiresponse.md @@ -4,6 +4,7 @@ ## DeprecationAPIResponse interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.deprecationinfo.md b/docs/development/core/server/kibana-plugin-server.deprecationinfo.md index 21c10bde26378..c27f5d3404c22 100644 --- a/docs/development/core/server/kibana-plugin-server.deprecationinfo.md +++ b/docs/development/core/server/kibana-plugin-server.deprecationinfo.md @@ -4,6 +4,7 @@ ## DeprecationInfo interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearcherror.md b/docs/development/core/server/kibana-plugin-server.elasticsearcherror.md index a1d15704d5e1c..9d9e21c44760c 100644 --- a/docs/development/core/server/kibana-plugin-server.elasticsearcherror.md +++ b/docs/development/core/server/kibana-plugin-server.elasticsearcherror.md @@ -4,6 +4,7 @@ ## ElasticsearchError interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md index 31cf07ac66a46..b5bfc68d3ca0c 100644 --- a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md +++ b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md @@ -4,6 +4,14 @@ ## ElasticsearchServiceSetup.adminClient$ property +Observable of clients for the `admin` cluster. Observable emits when Elasticsearch config changes on the Kibana server. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). + + +```js +const client = await elasticsearch.adminClient$.pipe(take(1)).toPromise(); + +``` + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.createclient.md b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.createclient.md index 34d04d26e9654..3d26f2d4cec88 100644 --- a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.createclient.md +++ b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.createclient.md @@ -4,7 +4,7 @@ ## ElasticsearchServiceSetup.createClient property -Create application specific Elasticsearch cluster API client with customized config. +Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md index 240dff2e53635..9411f2f6b8694 100644 --- a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md +++ b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md @@ -4,6 +4,14 @@ ## ElasticsearchServiceSetup.dataClient$ property +Observable of clients for the `data` cluster. Observable emits when Elasticsearch config changes on the Kibana server. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). + + +```js +const client = await elasticsearch.dataClient$.pipe(take(1)).toPromise(); + +``` + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.legacy.md b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.legacy.md deleted file mode 100644 index 6040b407dd415..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.legacy.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) > [legacy](./kibana-plugin-server.elasticsearchservicesetup.legacy.md) - -## ElasticsearchServiceSetup.legacy property - -Signature: - -```typescript -readonly legacy: { - readonly config$: Observable; - }; -``` diff --git a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.md b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.md index 9c3b92a88fe07..e3d151cdc0d8b 100644 --- a/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.md +++ b/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.md @@ -15,8 +15,17 @@ export interface ElasticsearchServiceSetup | Property | Type | Description | | --- | --- | --- | -| [adminClient$](./kibana-plugin-server.elasticsearchservicesetup.adminclient_.md) | Observable<IClusterClient> | | -| [createClient](./kibana-plugin-server.elasticsearchservicesetup.createclient.md) | (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => IClusterClient | Create application specific Elasticsearch cluster API client with customized config. | -| [dataClient$](./kibana-plugin-server.elasticsearchservicesetup.dataclient_.md) | Observable<IClusterClient> | | -| [legacy](./kibana-plugin-server.elasticsearchservicesetup.legacy.md) | {
readonly config$: Observable<ElasticsearchConfig>;
} | | +| [adminClient$](./kibana-plugin-server.elasticsearchservicesetup.adminclient_.md) | Observable<IClusterClient> | Observable of clients for the admin cluster. Observable emits when Elasticsearch config changes on the Kibana server. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). +```js +const client = await elasticsearch.adminClient$.pipe(take(1)).toPromise(); + +``` + | +| [createClient](./kibana-plugin-server.elasticsearchservicesetup.createclient.md) | (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => IClusterClient | Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). | +| [dataClient$](./kibana-plugin-server.elasticsearchservicesetup.dataclient_.md) | Observable<IClusterClient> | Observable of clients for the data cluster. Observable emits when Elasticsearch config changes on the Kibana server. See [IClusterClient](./kibana-plugin-server.iclusterclient.md). +```js +const client = await elasticsearch.dataClient$.pipe(take(1)).toPromise(); + +``` + | diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.auth.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.auth.md deleted file mode 100644 index e39c3c6316768..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.auth.md +++ /dev/null @@ -1,15 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [auth](./kibana-plugin-server.httpserversetup.auth.md) - -## HttpServerSetup.auth property - -Signature: - -```typescript -auth: { - get: GetAuthState; - isAuthenticated: IsAuthenticated; - getAuthHeaders: GetAuthHeaders; - }; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.basepath.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.basepath.md deleted file mode 100644 index 173262de10494..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.basepath.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [basePath](./kibana-plugin-server.httpserversetup.basepath.md) - -## HttpServerSetup.basePath property - -[BasePath](./kibana-plugin-server.basepath.md) - -Signature: - -```typescript -basePath: IBasePath; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.md deleted file mode 100644 index 7a126383116e7..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.md +++ /dev/null @@ -1,93 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) - -## HttpServerSetup interface - -Kibana HTTP Service provides own abstraction for work with HTTP stack. Plugins don't have direct access to `hapi` server and its primitives anymore. Moreover, plugins shouldn't rely on the fact that HTTP Service uses one or another library under the hood. This gives the platform flexibility to upgrade or changing our internal HTTP stack without breaking plugins. If the HTTP Service lacks functionality you need, we are happy to discuss and support your needs. - -Signature: - -```typescript -export interface HttpServerSetup -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [auth](./kibana-plugin-server.httpserversetup.auth.md) | {
get: GetAuthState;
isAuthenticated: IsAuthenticated;
getAuthHeaders: GetAuthHeaders;
} | | -| [basePath](./kibana-plugin-server.httpserversetup.basepath.md) | IBasePath | [BasePath](./kibana-plugin-server.basepath.md) | -| [createCookieSessionStorageFactory](./kibana-plugin-server.httpserversetup.createcookiesessionstoragefactory.md) | <T>(cookieOptions: SessionStorageCookieOptions<T>) => Promise<SessionStorageFactory<T>> | Creates cookie based session storage factory [SessionStorageFactory](./kibana-plugin-server.sessionstoragefactory.md) | -| [isTlsEnabled](./kibana-plugin-server.httpserversetup.istlsenabled.md) | boolean | Flag showing whether a server was configured to use TLS connection. | -| [registerAuth](./kibana-plugin-server.httpserversetup.registerauth.md) | (handler: AuthenticationHandler) => void | To define custom authentication and/or authorization mechanism for incoming requests. A handler should return a state to associate with the incoming request. The state can be retrieved later via http.auth.get(..) Only one AuthenticationHandler can be registered. | -| [registerOnPostAuth](./kibana-plugin-server.httpserversetup.registeronpostauth.md) | (handler: OnPostAuthHandler) => void | To define custom logic to perform for incoming requests. Runs the handler after Auth interceptor did make sure a user has access to the requested resource. The auth state is available at stage via http.auth.get(..) Can register any number of registerOnPreAuth, which are called in sequence (from the first registered to the last). | -| [registerOnPreAuth](./kibana-plugin-server.httpserversetup.registeronpreauth.md) | (handler: OnPreAuthHandler) => void | To define custom logic to perform for incoming requests. Runs the handler before Auth interceptor performs a check that user has access to requested resources, so it's the only place when you can forward a request to another URL right on the server. Can register any number of registerOnPostAuth, which are called in sequence (from the first registered to the last). | -| [registerRouter](./kibana-plugin-server.httpserversetup.registerrouter.md) | (router: IRouter) => void | Add all the routes registered with router to HTTP server request listeners. | -| [server](./kibana-plugin-server.httpserversetup.server.md) | Server | | - -## Example - -To handle an incoming request in your plugin you should: - Create a `Router` instance. Router is already configured to use `plugin-id` to prefix path segment for your routes. - -```ts -const router = httpSetup.createRouter(); - -``` -- Use `@kbn/config-schema` package to create a schema to validate the request `params`, `query`, and `body`. Every incoming request will be validated against the created schema. If validation failed, the request is rejected with `400` status and `Bad request` error without calling the route's handler. To opt out of validating the request, specify `false`. - -```ts -import { schema, TypeOf } from '@kbn/config-schema'; -const validate = { - params: schema.object({ - id: schema.string(), - }), -}; - -``` -- Declare a function to respond to incoming request. The function will receive `request` object containing request details: url, headers, matched route, as well as validated `params`, `query`, `body`. And `response` object instructing HTTP server to create HTTP response with information sent back to the client as the response body, headers, and HTTP status. Unlike, `hapi` route handler in the Legacy platform, any exception raised during the handler call will generate `500 Server error` response and log error details for further investigation. See below for returning custom error responses. - -```ts -const handler = async (context: RequestHandlerContext, request: KibanaRequest, response: ResponseFactory) => { - const data = await findObject(request.params.id); - // creates a command to respond with 'not found' error - if (!data) return response.notFound(); - // creates a command to send found data to the client and set response headers - return response.ok({ - body: data, - headers: { - 'content-type': 'application/json' - } - }); -} - -``` -- Register route handler for GET request to 'my-app/path/{id}' path - -```ts -import { schema, TypeOf } from '@kbn/config-schema'; -const router = httpSetup.createRouter(); - -const validate = { - params: schema.object({ - id: schema.string(), - }), -}; - -router.get({ - path: 'path/{id}', - validate -}, -async (context, request, response) => { - const data = await findObject(request.params.id); - if (!data) return response.notFound(); - return response.ok({ - body: data, - headers: { - 'content-type': 'application/json' - } - }); -}); - -``` - diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.registerauth.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.registerauth.md deleted file mode 100644 index 6e63e0996a63a..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.registerauth.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [registerAuth](./kibana-plugin-server.httpserversetup.registerauth.md) - -## HttpServerSetup.registerAuth property - -To define custom authentication and/or authorization mechanism for incoming requests. A handler should return a state to associate with the incoming request. The state can be retrieved later via http.auth.get(..) Only one AuthenticationHandler can be registered. - -Signature: - -```typescript -registerAuth: (handler: AuthenticationHandler) => void; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpostauth.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpostauth.md deleted file mode 100644 index c74a67da350ec..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpostauth.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [registerOnPostAuth](./kibana-plugin-server.httpserversetup.registeronpostauth.md) - -## HttpServerSetup.registerOnPostAuth property - -To define custom logic to perform for incoming requests. Runs the handler after Auth interceptor did make sure a user has access to the requested resource. The auth state is available at stage via http.auth.get(..) Can register any number of registerOnPreAuth, which are called in sequence (from the first registered to the last). - -Signature: - -```typescript -registerOnPostAuth: (handler: OnPostAuthHandler) => void; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpreauth.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpreauth.md deleted file mode 100644 index f6efa1c1dd73c..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.registeronpreauth.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [registerOnPreAuth](./kibana-plugin-server.httpserversetup.registeronpreauth.md) - -## HttpServerSetup.registerOnPreAuth property - -To define custom logic to perform for incoming requests. Runs the handler before Auth interceptor performs a check that user has access to requested resources, so it's the only place when you can forward a request to another URL right on the server. Can register any number of registerOnPostAuth, which are called in sequence (from the first registered to the last). - -Signature: - -```typescript -registerOnPreAuth: (handler: OnPreAuthHandler) => void; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.registerrouter.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.registerrouter.md deleted file mode 100644 index 32daa650f8d5d..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.registerrouter.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [registerRouter](./kibana-plugin-server.httpserversetup.registerrouter.md) - -## HttpServerSetup.registerRouter property - -Add all the routes registered with `router` to HTTP server request listeners. - -Signature: - -```typescript -registerRouter: (router: IRouter) => void; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.server.md b/docs/development/core/server/kibana-plugin-server.httpserversetup.server.md deleted file mode 100644 index a137eba7c8a5a..0000000000000 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.server.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [server](./kibana-plugin-server.httpserversetup.server.md) - -## HttpServerSetup.server property - -Signature: - -```typescript -server: Server; -``` diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md new file mode 100644 index 0000000000000..61390773bd726 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [basePath](./kibana-plugin-server.httpservicesetup.basepath.md) + +## HttpServiceSetup.basePath property + +Access or manipulate the Kibana base path See [IBasePath](./kibana-plugin-server.ibasepath.md). + +Signature: + +```typescript +basePath: IBasePath; +``` diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.createcookiesessionstoragefactory.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md similarity index 61% rename from docs/development/core/server/kibana-plugin-server.httpserversetup.createcookiesessionstoragefactory.md rename to docs/development/core/server/kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md index 3dc01a52a2f58..4771836bea477 100644 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.createcookiesessionstoragefactory.md +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [createCookieSessionStorageFactory](./kibana-plugin-server.httpserversetup.createcookiesessionstoragefactory.md) +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [createCookieSessionStorageFactory](./kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md) -## HttpServerSetup.createCookieSessionStorageFactory property +## HttpServiceSetup.createCookieSessionStorageFactory property Creates cookie based session storage factory [SessionStorageFactory](./kibana-plugin-server.sessionstoragefactory.md) diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md new file mode 100644 index 0000000000000..6431589c55bd1 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [createRouter](./kibana-plugin-server.httpservicesetup.createrouter.md) + +## HttpServiceSetup.createRouter property + +Provides ability to declare a handler function for a particular path and HTTP request method. + +Signature: + +```typescript +createRouter: () => IRouter; +``` + +## Remarks + +Each route can have only one handler function, which is executed when the route is matched. See the [IRouter](./kibana-plugin-server.irouter.md) documentation for more information. + +## Example + + +```ts +const router = createRouter(); +// handler is called when '${my-plugin-id}/path' resource is requested with `GET` method +router.get({ path: '/path', validate: false }, (context, req, res) => res.ok({ content: 'ok' })); + +``` + diff --git a/docs/development/core/server/kibana-plugin-server.httpserversetup.istlsenabled.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.istlsenabled.md similarity index 56% rename from docs/development/core/server/kibana-plugin-server.httpserversetup.istlsenabled.md rename to docs/development/core/server/kibana-plugin-server.httpservicesetup.istlsenabled.md index 6961d4feeb7c7..06a99e8bf3013 100644 --- a/docs/development/core/server/kibana-plugin-server.httpserversetup.istlsenabled.md +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.istlsenabled.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) > [isTlsEnabled](./kibana-plugin-server.httpserversetup.istlsenabled.md) +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [isTlsEnabled](./kibana-plugin-server.httpservicesetup.istlsenabled.md) -## HttpServerSetup.isTlsEnabled property +## HttpServiceSetup.isTlsEnabled property Flag showing whether a server was configured to use TLS connection. diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md index eec63cf5c8093..d943ad53af843 100644 --- a/docs/development/core/server/kibana-plugin-server.httpservicesetup.md +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.md @@ -2,14 +2,91 @@ [Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) -## HttpServiceSetup type +## HttpServiceSetup interface +Kibana HTTP Service provides own abstraction for work with HTTP stack. Plugins don't have direct access to `hapi` server and its primitives anymore. Moreover, plugins shouldn't rely on the fact that HTTP Service uses one or another library under the hood. This gives the platform flexibility to upgrade or changing our internal HTTP stack without breaking plugins. If the HTTP Service lacks functionality you need, we are happy to discuss and support your needs. Signature: ```typescript -export declare type HttpServiceSetup = Omit & { - createRouter: (path: string, plugin?: PluginOpaqueId) => IRouter; - registerRouteHandlerContext: (pluginOpaqueId: PluginOpaqueId, contextName: T, provider: RequestHandlerContextProvider) => RequestHandlerContextContainer; +export interface HttpServiceSetup +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [basePath](./kibana-plugin-server.httpservicesetup.basepath.md) | IBasePath | Access or manipulate the Kibana base path See [IBasePath](./kibana-plugin-server.ibasepath.md). | +| [createCookieSessionStorageFactory](./kibana-plugin-server.httpservicesetup.createcookiesessionstoragefactory.md) | <T>(cookieOptions: SessionStorageCookieOptions<T>) => Promise<SessionStorageFactory<T>> | Creates cookie based session storage factory [SessionStorageFactory](./kibana-plugin-server.sessionstoragefactory.md) | +| [createRouter](./kibana-plugin-server.httpservicesetup.createrouter.md) | () => IRouter | Provides ability to declare a handler function for a particular path and HTTP request method. | +| [isTlsEnabled](./kibana-plugin-server.httpservicesetup.istlsenabled.md) | boolean | Flag showing whether a server was configured to use TLS connection. | +| [registerAuth](./kibana-plugin-server.httpservicesetup.registerauth.md) | (handler: AuthenticationHandler) => void | To define custom authentication and/or authorization mechanism for incoming requests. | +| [registerOnPostAuth](./kibana-plugin-server.httpservicesetup.registeronpostauth.md) | (handler: OnPostAuthHandler) => void | To define custom logic to perform for incoming requests. | +| [registerOnPreAuth](./kibana-plugin-server.httpservicesetup.registeronpreauth.md) | (handler: OnPreAuthHandler) => void | To define custom logic to perform for incoming requests. | +| [registerRouteHandlerContext](./kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md) | <T extends keyof RequestHandlerContext>(contextName: T, provider: RequestHandlerContextProvider<T>) => RequestHandlerContextContainer | Register a context provider for a route handler. | + +## Example + +To handle an incoming request in your plugin you should: - Create a `Router` instance. Router is already configured to use `plugin-id` to prefix path segment for your routes. + +```ts +const router = httpSetup.createRouter(); + +``` +- Use `@kbn/config-schema` package to create a schema to validate the request `params`, `query`, and `body`. Every incoming request will be validated against the created schema. If validation failed, the request is rejected with `400` status and `Bad request` error without calling the route's handler. To opt out of validating the request, specify `false`. + +```ts +import { schema, TypeOf } from '@kbn/config-schema'; +const validate = { + params: schema.object({ + id: schema.string(), + }), +}; + +``` +- Declare a function to respond to incoming request. The function will receive `request` object containing request details: url, headers, matched route, as well as validated `params`, `query`, `body`. And `response` object instructing HTTP server to create HTTP response with information sent back to the client as the response body, headers, and HTTP status. Unlike, `hapi` route handler in the Legacy platform, any exception raised during the handler call will generate `500 Server error` response and log error details for further investigation. See below for returning custom error responses. + +```ts +const handler = async (context: RequestHandlerContext, request: KibanaRequest, response: ResponseFactory) => { + const data = await findObject(request.params.id); + // creates a command to respond with 'not found' error + if (!data) return response.notFound(); + // creates a command to send found data to the client and set response headers + return response.ok({ + body: data, + headers: { + 'content-type': 'application/json' + } + }); +} + +``` +- Register route handler for GET request to 'my-app/path/{id}' path + +```ts +import { schema, TypeOf } from '@kbn/config-schema'; +const router = httpSetup.createRouter(); + +const validate = { + params: schema.object({ + id: schema.string(), + }), }; + +router.get({ + path: 'path/{id}', + validate +}, +async (context, request, response) => { + const data = await findObject(request.params.id); + if (!data) return response.notFound(); + return response.ok({ + body: data, + headers: { + 'content-type': 'application/json' + } + }); +}); + ``` + diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerauth.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerauth.md new file mode 100644 index 0000000000000..be3da1ca1131f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerauth.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [registerAuth](./kibana-plugin-server.httpservicesetup.registerauth.md) + +## HttpServiceSetup.registerAuth property + +To define custom authentication and/or authorization mechanism for incoming requests. + +Signature: + +```typescript +registerAuth: (handler: AuthenticationHandler) => void; +``` + +## Remarks + +A handler should return a state to associate with the incoming request. The state can be retrieved later via http.auth.get(..) Only one AuthenticationHandler can be registered. See [AuthenticationHandler](./kibana-plugin-server.authenticationhandler.md). + diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpostauth.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpostauth.md new file mode 100644 index 0000000000000..a3f875c999af1 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpostauth.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [registerOnPostAuth](./kibana-plugin-server.httpservicesetup.registeronpostauth.md) + +## HttpServiceSetup.registerOnPostAuth property + +To define custom logic to perform for incoming requests. + +Signature: + +```typescript +registerOnPostAuth: (handler: OnPostAuthHandler) => void; +``` + +## Remarks + +Runs the handler after Auth interceptor did make sure a user has access to the requested resource. The auth state is available at stage via http.auth.get(..) Can register any number of registerOnPreAuth, which are called in sequence (from the first registered to the last). See [OnPostAuthHandler](./kibana-plugin-server.onpostauthhandler.md). + diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreauth.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreauth.md new file mode 100644 index 0000000000000..4c7b688619319 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registeronpreauth.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [registerOnPreAuth](./kibana-plugin-server.httpservicesetup.registeronpreauth.md) + +## HttpServiceSetup.registerOnPreAuth property + +To define custom logic to perform for incoming requests. + +Signature: + +```typescript +registerOnPreAuth: (handler: OnPreAuthHandler) => void; +``` + +## Remarks + +Runs the handler before Auth interceptor performs a check that user has access to requested resources, so it's the only place when you can forward a request to another URL right on the server. Can register any number of registerOnPostAuth, which are called in sequence (from the first registered to the last). See [OnPreAuthHandler](./kibana-plugin-server.onpreauthhandler.md). + diff --git a/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md new file mode 100644 index 0000000000000..339f2eb329c7b --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md @@ -0,0 +1,37 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) > [registerRouteHandlerContext](./kibana-plugin-server.httpservicesetup.registerroutehandlercontext.md) + +## HttpServiceSetup.registerRouteHandlerContext property + +Register a context provider for a route handler. + +Signature: + +```typescript +registerRouteHandlerContext: (contextName: T, provider: RequestHandlerContextProvider) => RequestHandlerContextContainer; +``` + +## Example + + +```ts + // my-plugin.ts + deps.http.registerRouteHandlerContext( + 'myApp', + (context, req) => { + async function search (id: string) { + return await context.elasticsearch.adminClient.callAsInternalUser('endpoint', id); + } + return { search }; + } + ); + +// my-route-handler.ts + router.get({ path: '/', validate: false }, async (context, req, res) => { + const response = await context.myApp.search(...); + return res.ok(response); + }); + +``` + diff --git a/docs/development/core/server/kibana-plugin-server.ikibanaresponse.md b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.md new file mode 100644 index 0000000000000..4971d6eb97a28 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IKibanaResponse](./kibana-plugin-server.ikibanaresponse.md) + +## IKibanaResponse interface + +A response data object, expected to returned as a result of [RequestHandler](./kibana-plugin-server.requesthandler.md) execution + +Signature: + +```typescript +export interface IKibanaResponse +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [options](./kibana-plugin-server.ikibanaresponse.options.md) | HttpResponseOptions | | +| [payload](./kibana-plugin-server.ikibanaresponse.payload.md) | T | | +| [status](./kibana-plugin-server.ikibanaresponse.status.md) | number | | + diff --git a/docs/development/core/server/kibana-plugin-server.ikibanaresponse.options.md b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.options.md new file mode 100644 index 0000000000000..988d873c088fe --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.options.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IKibanaResponse](./kibana-plugin-server.ikibanaresponse.md) > [options](./kibana-plugin-server.ikibanaresponse.options.md) + +## IKibanaResponse.options property + +Signature: + +```typescript +readonly options: HttpResponseOptions; +``` diff --git a/docs/development/core/server/kibana-plugin-server.ikibanaresponse.payload.md b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.payload.md new file mode 100644 index 0000000000000..f1d10c5d22a42 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.payload.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IKibanaResponse](./kibana-plugin-server.ikibanaresponse.md) > [payload](./kibana-plugin-server.ikibanaresponse.payload.md) + +## IKibanaResponse.payload property + +Signature: + +```typescript +readonly payload?: T; +``` diff --git a/docs/development/core/server/kibana-plugin-server.ikibanaresponse.status.md b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.status.md new file mode 100644 index 0000000000000..b766ff66c357f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.ikibanaresponse.status.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IKibanaResponse](./kibana-plugin-server.ikibanaresponse.md) > [status](./kibana-plugin-server.ikibanaresponse.status.md) + +## IKibanaResponse.status property + +Signature: + +```typescript +readonly status: number; +``` diff --git a/docs/development/core/server/kibana-plugin-server.indexsettingsdeprecationinfo.md b/docs/development/core/server/kibana-plugin-server.indexsettingsdeprecationinfo.md index 8fd0c6bb9f997..66b15e532e2ad 100644 --- a/docs/development/core/server/kibana-plugin-server.indexsettingsdeprecationinfo.md +++ b/docs/development/core/server/kibana-plugin-server.indexsettingsdeprecationinfo.md @@ -4,6 +4,7 @@ ## IndexSettingsDeprecationInfo interface + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.irouter.md b/docs/development/core/server/kibana-plugin-server.irouter.md index 2fb2d30eb31d7..bbffe1e42f229 100644 --- a/docs/development/core/server/kibana-plugin-server.irouter.md +++ b/docs/development/core/server/kibana-plugin-server.irouter.md @@ -4,7 +4,7 @@ ## IRouter interface -Registers route handlers for specified resource path and method. +Registers route handlers for specified resource path and method. See [RouteConfig](./kibana-plugin-server.routeconfig.md) and [RequestHandler](./kibana-plugin-server.requesthandler.md) for more information about arguments to route registrations. Signature: diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md index 3e3e2bd57db96..8a259f6870628 100644 --- a/docs/development/core/server/kibana-plugin-server.md +++ b/docs/development/core/server/kibana-plugin-server.md @@ -27,6 +27,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | Enumeration | Description | | --- | --- | +| [AuthResultType](./kibana-plugin-server.authresulttype.md) | | | [AuthStatus](./kibana-plugin-server.authstatus.md) | Status indicating an outcome of the authentication. | ## Interfaces @@ -36,6 +37,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [APICaller](./kibana-plugin-server.apicaller.md) | | | [AssistanceAPIResponse](./kibana-plugin-server.assistanceapiresponse.md) | | | [AssistantAPIClientParams](./kibana-plugin-server.assistantapiclientparams.md) | | +| [Authenticated](./kibana-plugin-server.authenticated.md) | | | [AuthResultParams](./kibana-plugin-server.authresultparams.md) | Result of an incoming request authentication. | | [AuthToolkit](./kibana-plugin-server.authtoolkit.md) | A tool set defining an outcome of Auth interceptor for incoming request. | | [CallAPIOptions](./kibana-plugin-server.callapioptions.md) | The set of options that defines how API call should be made and result be processed. | @@ -53,12 +55,13 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ErrorHttpResponseOptions](./kibana-plugin-server.errorhttpresponseoptions.md) | HTTP response parameters | | [FakeRequest](./kibana-plugin-server.fakerequest.md) | Fake request object created manually by Kibana plugins. | | [HttpResponseOptions](./kibana-plugin-server.httpresponseoptions.md) | HTTP response parameters | -| [HttpServerSetup](./kibana-plugin-server.httpserversetup.md) | Kibana HTTP Service provides own abstraction for work with HTTP stack. Plugins don't have direct access to hapi server and its primitives anymore. Moreover, plugins shouldn't rely on the fact that HTTP Service uses one or another library under the hood. This gives the platform flexibility to upgrade or changing our internal HTTP stack without breaking plugins. If the HTTP Service lacks functionality you need, we are happy to discuss and support your needs. | +| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) | Kibana HTTP Service provides own abstraction for work with HTTP stack. Plugins don't have direct access to hapi server and its primitives anymore. Moreover, plugins shouldn't rely on the fact that HTTP Service uses one or another library under the hood. This gives the platform flexibility to upgrade or changing our internal HTTP stack without breaking plugins. If the HTTP Service lacks functionality you need, we are happy to discuss and support your needs. | | [HttpServiceStart](./kibana-plugin-server.httpservicestart.md) | | | [IContextContainer](./kibana-plugin-server.icontextcontainer.md) | An object that handles registration of context providers and configuring handlers with context. | +| [IKibanaResponse](./kibana-plugin-server.ikibanaresponse.md) | A response data object, expected to returned as a result of [RequestHandler](./kibana-plugin-server.requesthandler.md) execution | | [IKibanaSocket](./kibana-plugin-server.ikibanasocket.md) | A tiny abstraction for TCP socket. | | [IndexSettingsDeprecationInfo](./kibana-plugin-server.indexsettingsdeprecationinfo.md) | | -| [IRouter](./kibana-plugin-server.irouter.md) | Registers route handlers for specified resource path and method. | +| [IRouter](./kibana-plugin-server.irouter.md) | Registers route handlers for specified resource path and method. See [RouteConfig](./kibana-plugin-server.routeconfig.md) and [RequestHandler](./kibana-plugin-server.requesthandler.md) for more information about arguments to route registrations. | | [KibanaRequestRoute](./kibana-plugin-server.kibanarequestroute.md) | Request specific route information exposed to a handler. | | [LegacyRequest](./kibana-plugin-server.legacyrequest.md) | | | [LegacyServiceSetupDeps](./kibana-plugin-server.legacyservicesetupdeps.md) | | @@ -118,8 +121,9 @@ The plugin integrates with the core system via lifecycle events: `setup` | Type Alias | Description | | --- | --- | -| [AuthenticationHandler](./kibana-plugin-server.authenticationhandler.md) | | +| [AuthenticationHandler](./kibana-plugin-server.authenticationhandler.md) | See [AuthToolkit](./kibana-plugin-server.authtoolkit.md). | | [AuthHeaders](./kibana-plugin-server.authheaders.md) | Auth Headers map | +| [AuthResult](./kibana-plugin-server.authresult.md) | | | [ConfigPath](./kibana-plugin-server.configpath.md) | | | [ElasticsearchClientConfig](./kibana-plugin-server.elasticsearchclientconfig.md) | | | [GetAuthHeaders](./kibana-plugin-server.getauthheaders.md) | Get headers to authenticate a user against Elasticsearch. | @@ -129,7 +133,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HandlerParameters](./kibana-plugin-server.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-server.handlerfunction.md), excluding the [HandlerContextType](./kibana-plugin-server.handlercontexttype.md). | | [Headers](./kibana-plugin-server.headers.md) | Http request headers to read. | | [HttpResponsePayload](./kibana-plugin-server.httpresponsepayload.md) | Data send to the client as a response payload. | -| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) | | | [IBasePath](./kibana-plugin-server.ibasepath.md) | Access or manipulate the Kibana base path[BasePath](./kibana-plugin-server.basepath.md) | | [IClusterClient](./kibana-plugin-server.iclusterclient.md) | Represents an Elasticsearch cluster API client and allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via asScoped(...)).See [ClusterClient](./kibana-plugin-server.clusterclient.md). | | [IContextProvider](./kibana-plugin-server.icontextprovider.md) | A function that returns a context value for a specific key of given context type. | @@ -140,8 +143,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [LifecycleResponseFactory](./kibana-plugin-server.lifecycleresponsefactory.md) | Creates an object containing redirection or error response with error details, HTTP headers, and other data transmitted to the client. | | [MIGRATION\_ASSISTANCE\_INDEX\_ACTION](./kibana-plugin-server.migration_assistance_index_action.md) | | | [MIGRATION\_DEPRECATION\_LEVEL](./kibana-plugin-server.migration_deprecation_level.md) | | -| [OnPostAuthHandler](./kibana-plugin-server.onpostauthhandler.md) | | -| [OnPreAuthHandler](./kibana-plugin-server.onpreauthhandler.md) | | +| [OnPostAuthHandler](./kibana-plugin-server.onpostauthhandler.md) | See [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md). | +| [OnPreAuthHandler](./kibana-plugin-server.onpreauthhandler.md) | See [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md). | | [PluginInitializer](./kibana-plugin-server.plugininitializer.md) | The plugin export at the root of a plugin's server directory should conform to this interface. | | [PluginName](./kibana-plugin-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. | | [PluginOpaqueId](./kibana-plugin-server.pluginopaqueid.md) | | diff --git a/docs/development/core/server/kibana-plugin-server.migration_assistance_index_action.md b/docs/development/core/server/kibana-plugin-server.migration_assistance_index_action.md index 4753bd0db71f6..e5ecc6779b282 100644 --- a/docs/development/core/server/kibana-plugin-server.migration_assistance_index_action.md +++ b/docs/development/core/server/kibana-plugin-server.migration_assistance_index_action.md @@ -4,6 +4,7 @@ ## MIGRATION\_ASSISTANCE\_INDEX\_ACTION type + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.migration_deprecation_level.md b/docs/development/core/server/kibana-plugin-server.migration_deprecation_level.md index 2751faf6a1cd9..33e02a1b2bce0 100644 --- a/docs/development/core/server/kibana-plugin-server.migration_deprecation_level.md +++ b/docs/development/core/server/kibana-plugin-server.migration_deprecation_level.md @@ -4,6 +4,7 @@ ## MIGRATION\_DEPRECATION\_LEVEL type + Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-server.onpostauthhandler.md b/docs/development/core/server/kibana-plugin-server.onpostauthhandler.md index 884eb3e6346bd..a887dea26e3bc 100644 --- a/docs/development/core/server/kibana-plugin-server.onpostauthhandler.md +++ b/docs/development/core/server/kibana-plugin-server.onpostauthhandler.md @@ -4,6 +4,7 @@ ## OnPostAuthHandler type +See [OnPostAuthToolkit](./kibana-plugin-server.onpostauthtoolkit.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.onpreauthhandler.md b/docs/development/core/server/kibana-plugin-server.onpreauthhandler.md index 5eca904227bb9..003bd4b19eadf 100644 --- a/docs/development/core/server/kibana-plugin-server.onpreauthhandler.md +++ b/docs/development/core/server/kibana-plugin-server.onpreauthhandler.md @@ -4,6 +4,7 @@ ## OnPreAuthHandler type +See [OnPreAuthToolkit](./kibana-plugin-server.onpreauthtoolkit.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.requesthandler.md b/docs/development/core/server/kibana-plugin-server.requesthandler.md index 0b6a127119d8e..035d16c9fca3c 100644 --- a/docs/development/core/server/kibana-plugin-server.requesthandler.md +++ b/docs/development/core/server/kibana-plugin-server.requesthandler.md @@ -9,7 +9,7 @@ A function executed when route path matched requested resource path. Request han Signature: ```typescript -export declare type RequestHandler

= (context: RequestHandlerContext, request: KibanaRequest, TypeOf, TypeOf>, response: KibanaResponseFactory) => KibanaResponse | Promise>; +export declare type RequestHandler

= (context: RequestHandlerContext, request: KibanaRequest, TypeOf, TypeOf>, response: KibanaResponseFactory) => IKibanaResponse | Promise>; ``` ## Example diff --git a/docs/development/core/server/kibana-plugin-server.routeconfig.md b/docs/development/core/server/kibana-plugin-server.routeconfig.md index 84fa52719e3a9..769d0dda42644 100644 --- a/docs/development/core/server/kibana-plugin-server.routeconfig.md +++ b/docs/development/core/server/kibana-plugin-server.routeconfig.md @@ -17,6 +17,6 @@ export interface RouteConfig

RouteConfigOptions | Additional route options [RouteConfigOptions](./kibana-plugin-server.routeconfigoptions.md). | -| [path](./kibana-plugin-server.routeconfig.path.md) | string | The endpoint \_within\_ the router path to register the route. E.g. if the router is registered at /elasticsearch and the route path is /search, the full path for the route is /elasticsearch/search. Supports: - named path segments path/{name}. - optional path segments path/{position?}. - multi-segments path/{coordinates*2}. Segments are accessible within a handler function as params property of [KibanaRequest](./kibana-plugin-server.kibanarequest.md) object. To have read access to params you \*must\* specify validation schema with [RouteConfig.validate](./kibana-plugin-server.routeconfig.validate.md). | -| [validate](./kibana-plugin-server.routeconfig.validate.md) | RouteSchemas<P, Q, B> | false | A schema created with @kbn/config-schema that every request will be validated against. You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify validate: false. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the @kbn/config-schema library to output \*\*non-validated values\*\* with setting schema as schema.object({}, { allowUnknowns: true }); | +| [path](./kibana-plugin-server.routeconfig.path.md) | string | The endpoint \_within\_ the router path to register the route. | +| [validate](./kibana-plugin-server.routeconfig.validate.md) | RouteSchemas<P, Q, B> | false | A schema created with @kbn/config-schema that every request will be validated against. | diff --git a/docs/development/core/server/kibana-plugin-server.routeconfig.path.md b/docs/development/core/server/kibana-plugin-server.routeconfig.path.md index 3437f0e0fe064..0e6fa19f98ace 100644 --- a/docs/development/core/server/kibana-plugin-server.routeconfig.path.md +++ b/docs/development/core/server/kibana-plugin-server.routeconfig.path.md @@ -4,10 +4,15 @@ ## RouteConfig.path property -The endpoint \_within\_ the router path to register the route. E.g. if the router is registered at `/elasticsearch` and the route path is `/search`, the full path for the route is `/elasticsearch/search`. Supports: - named path segments `path/{name}`. - optional path segments `path/{position?}`. - multi-segments `path/{coordinates*2}`. Segments are accessible within a handler function as `params` property of [KibanaRequest](./kibana-plugin-server.kibanarequest.md) object. To have read access to `params` you \*must\* specify validation schema with [RouteConfig.validate](./kibana-plugin-server.routeconfig.validate.md). +The endpoint \_within\_ the router path to register the route. Signature: ```typescript path: string; ``` + +## Remarks + +E.g. if the router is registered at `/elasticsearch` and the route path is `/search`, the full path for the route is `/elasticsearch/search`. Supports: - named path segments `path/{name}`. - optional path segments `path/{position?}`. - multi-segments `path/{coordinates*2}`. Segments are accessible within a handler function as `params` property of [KibanaRequest](./kibana-plugin-server.kibanarequest.md) object. To have read access to `params` you \*must\* specify validation schema with [RouteConfig.validate](./kibana-plugin-server.routeconfig.validate.md). + diff --git a/docs/development/core/server/kibana-plugin-server.routeconfig.validate.md b/docs/development/core/server/kibana-plugin-server.routeconfig.validate.md index 8f8301e159e7e..e1ec743ae71cc 100644 --- a/docs/development/core/server/kibana-plugin-server.routeconfig.validate.md +++ b/docs/development/core/server/kibana-plugin-server.routeconfig.validate.md @@ -4,7 +4,7 @@ ## RouteConfig.validate property -A schema created with `@kbn/config-schema` that every request will be validated against. You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { allowUnknowns: true })`; +A schema created with `@kbn/config-schema` that every request will be validated against. Signature: @@ -12,6 +12,10 @@ A schema created with `@kbn/config-schema` that every request will be validated validate: RouteSchemas | false; ``` +## Remarks + +You \*must\* specify a validation schema to be able to read: - url path segments - request query - request body To opt out of validating the request, specify `validate: false`. In this case request params, query, and body will be \*\*empty\*\* objects and have no access to raw values. In some cases you may want to use another validation library. To do this, you need to instruct the `@kbn/config-schema` library to output \*\*non-validated values\*\* with setting schema as `schema.object({}, { allowUnknowns: true })`; + ## Example diff --git a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callascurrentuser.md b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callascurrentuser.md index ce0c51be08698..1f53270042185 100644 --- a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callascurrentuser.md +++ b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callascurrentuser.md @@ -4,7 +4,7 @@ ## ScopedClusterClient.callAsCurrentUser() method -Calls specified `endpoint` with provided `clientParams` on behalf of the user initiated request to the Kibana server (via HTTP request headers). +Calls specified `endpoint` with provided `clientParams` on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [APICaller](./kibana-plugin-server.apicaller.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callasinternaluser.md b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callasinternaluser.md index 59811de18d926..7249af7b429e4 100644 --- a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callasinternaluser.md +++ b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.callasinternaluser.md @@ -4,7 +4,7 @@ ## ScopedClusterClient.callAsInternalUser() method -Calls specified `endpoint` with provided `clientParams` on behalf of the Kibana internal user. +Calls specified `endpoint` with provided `clientParams` on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-server.apicaller.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.md b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.md index 7833f698d486d..dcbf869bc9360 100644 --- a/docs/development/core/server/kibana-plugin-server.scopedclusterclient.md +++ b/docs/development/core/server/kibana-plugin-server.scopedclusterclient.md @@ -24,6 +24,6 @@ export declare class ScopedClusterClient implements IScopedClusterClient | Method | Modifiers | Description | | --- | --- | --- | -| [callAsCurrentUser(endpoint, clientParams, options)](./kibana-plugin-server.scopedclusterclient.callascurrentuser.md) | | Calls specified endpoint with provided clientParams on behalf of the user initiated request to the Kibana server (via HTTP request headers). | -| [callAsInternalUser(endpoint, clientParams, options)](./kibana-plugin-server.scopedclusterclient.callasinternaluser.md) | | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. | +| [callAsCurrentUser(endpoint, clientParams, options)](./kibana-plugin-server.scopedclusterclient.callascurrentuser.md) | | Calls specified endpoint with provided clientParams on behalf of the user initiated request to the Kibana server (via HTTP request headers). See [APICaller](./kibana-plugin-server.apicaller.md). | +| [callAsInternalUser(endpoint, clientParams, options)](./kibana-plugin-server.scopedclusterclient.callasinternaluser.md) | | Calls specified endpoint with provided clientParams on behalf of the Kibana internal user. See [APICaller](./kibana-plugin-server.apicaller.md). | diff --git a/docs/infrastructure/infra-ui.asciidoc b/docs/infrastructure/infra-ui.asciidoc index e92f6b3f64205..5c8c50a978d63 100644 --- a/docs/infrastructure/infra-ui.asciidoc +++ b/docs/infrastructure/infra-ui.asciidoc @@ -62,29 +62,30 @@ Select *Auto-refresh* to keep up-to-date metrics information coming in, or *Stop [[infra-configure-source]] === Configure the data to use for your metrics +If your metrics have custom index patterns, or use non-default field settings, you can override the default configuration settings. + The default source configuration for metrics is specified in the {kibana-ref}/infrastructure-ui-settings-kb.html[Metrics app settings] in the {kibana-ref}/settings.html[Kibana configuration file]. The default configuration uses the `metricbeat-*` index pattern to query the data. The default configuration also defines field settings for things like timestamps and container names. -If your metrics have custom index patterns, or use non-default field settings, you can override the default settings. -Click *Configuration* to change the settings. -This opens the *Configure source* fly-out dialog. +To change the configuration settings, click the *Settings* tab. NOTE: These settings are shared with logs. Changes you make here may also affect the settings used by the *Logs* app. -In the *Configure source* dialog, you can change the following values: +In the *Settings* tab, you can change the values in these sections: * *Name*: the name of the source configuration -* *Indices*: the index pattern or patterns in the Elasticsearch indices to read metrics data and log data - from +* *Indices*: the index pattern or patterns in the Elasticsearch indices to read metrics data and log data from * *Fields*: the names of specific fields in the indices that are used to query and interpret the data correctly -TIP: If <> are enabled in your Kibana instance, any configuration changes you make here are specific to the current space. -You can make different subsets of data available by creating multiple spaces with different data source configurations. +When you have completed your changes, click *Apply*. -TIP: If you don't see the *Configuration* option, you may not have sufficient privileges to change the source configuration. +If the fields are greyed out and cannot be edited, you may not have sufficient privileges to change the source configuration. For more information see <>. +TIP: If <> are enabled in your Kibana instance, any configuration changes you make here are specific to the current space. +You can make different subsets of data available by creating multiple spaces with different data source configurations. + [float] [[infra-metrics-explorer]] === Visualize multiple metrics in Metrics Explorer diff --git a/docs/logs/configuring.asciidoc b/docs/logs/configuring.asciidoc index f2aa1e5e17b8f..6b54721f92e89 100644 --- a/docs/logs/configuring.asciidoc +++ b/docs/logs/configuring.asciidoc @@ -1,50 +1,46 @@ [role="xpack"] [[xpack-logs-configuring]] -:ecs-link: {ecs-ref}[Elastic Common Schema (ECS)] +:ecs-base-link: {ecs-ref}/ecs-base.html[base] == Configuring the Logs data The default source configuration for logs is specified in the {kibana-ref}/logs-ui-settings-kb.html[Logs app settings] in the {kibana-ref}/settings.html[Kibana configuration file]. The default configuration uses the `filebeat-*` index pattern to query the data. -The default configuration also defines field settings for things like timestamps and container names, and the default columns to show in the logs pane. +The default configuration also defines field settings for things like timestamps and container names, and the default columns to show in the logs stream. -If your logs have custom index patterns, or use non-default field settings, or contain parsed fields which you want to expose as individual columns, you can override the default settings. -Click *Configuration* to change the settings. -This opens the *Configure source* fly-out dialog. +If your logs have custom index patterns, use non-default field settings, or contain parsed fields which you want to expose as individual columns, you can override the default configuration settings. -NOTE: These settings are shared with metrics. Changes you make here may also affect the settings used by the *Metrics* app. - -TIP: If <> are enabled in your Kibana instance, any configuration changes you make here are specific to the current space. -You can make different subsets of data available by creating multiple spaces with different data source configurations. +To change the configuration settings, click the *Settings* tab. -TIP: If you don't see the *Configuration* option, you may not have sufficient privileges to change the source configuration. -For more information see <>. - -[float] -=== Indices and fields tab +NOTE: These settings are shared with metrics. Changes you make here may also affect the settings used by the *Metrics* app. -In the *Indices and fields* tab, you can change the following values: +In the *Settings* tab, you can change the values in these sections: * *Name*: the name of the source configuration * *Indices*: the index pattern or patterns in the Elasticsearch indices to read metrics data and log data from * *Fields*: the names of specific fields in the indices that are used to query and interpret the data correctly +* *Log columns*: the columns that are shown in the logs stream -[float] -==== Log columns configuration - -In the *Log columns* tab you can change the columns that are displayed in the Logs app. -By default the following columns are shown: +By default the logs stream shows following columns: * *Timestamp*: The timestamp of the log entry from the `timestamp` field. * *Message*: The message extracted from the document. The content of this field depends on the type of log message. -If no special log message type is detected, the {ecs-link} field `message` is used. -// ++ add a better link. The actual page location is ecs-base +If no special log message type is detected, the Elastic Common Schema (ECS) {ecs-base-link} field, `message`, is used. -To add a new column, click *Add column*. +To add a new column to the logs stream, in the *Settings* tab, click *Add column*. In the list of available fields, select the field you want to add. You can start typing a field name in the search box to filter the field list by that name. To remove an existing column, click the *Remove this column* icon -image:logs/images/logs-configure-source-dialog-remove-column-button.png[Remove column]. \ No newline at end of file +image:logs/images/logs-configure-source-dialog-remove-column-button.png[Remove column]. + +When you have completed your changes, click *Apply*. + +If the fields are greyed out and cannot be edited, you may not have sufficient privileges to change the source configuration. +For more information see <>. + +TIP: If <> are enabled in your Kibana instance, any configuration changes you make here are specific to the current space. +You can make different subsets of data available by creating multiple spaces with different data source configurations. + diff --git a/docs/logs/using.asciidoc b/docs/logs/using.asciidoc index bebc225feb0e6..65693f4399e53 100644 --- a/docs/logs/using.asciidoc +++ b/docs/logs/using.asciidoc @@ -43,6 +43,11 @@ To quickly jump to a nearby point in time, click the minimap timeline to the rig Click *Customize* to customize the view. Here, you can set the scale to use for the minimap timeline, choose whether to wrap long lines, and choose your preferred text size. +[float] +=== Configuring the data to use for your logs + +If your logs have custom index patterns, use non-default field settings, or contain parsed fields which you want to expose as individual columns, you can <>. + [float] [[logs-stream]] === Stream or pause logs @@ -70,10 +75,10 @@ To highlight a word or phrase in the logs stream, click *Highlights* and enter y To inspect a log event, hover over it, then click the *View details* icon image:logs/images/logs-view-event.png[View event icon] beside the event. This opens the *Log event document details* fly-out that shows the fields associated with the log event. -To quickly filter the logs stream by one of the field values, click the *View event with filter* icon image:logs/images/logs-view-event-with-filter.png[View event icon] beside the field. +To quickly filter the logs stream by one of the field values, in the log event details, click the *View event with filter* icon image:logs/images/logs-view-event-with-filter.png[View event icon] beside the field. This automatically adds a search filter to the logs stream to filter the entries by this field and value. -In the log event details, click *Actions* to see the other actions related to the event. +To see other actions related to the event, in the log event details, click *Actions*. Depending on the event and the features you have installed and configured, you may also be able to: * Select *View status in Uptime* to <> in the *Uptime* app. diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 2e9118fef46fa..caff7f5b1fdc6 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -94,7 +94,7 @@ refresh the page to apply the setting. the time filter. This should be an array of objects, with each object containing `from`, `to` (see {ref}/common-options.html#date-math[accepted formats]), and `display` (the title to be displayed). -`timepicker:refreshIntervalDefaults`:: The default refresh interval for the time filter. +`timepicker:refreshIntervalDefaults`:: The default refresh interval for the time filter. Example: `{ "display": "15 seconds", "pause": true, "value": 15000 }`. `timepicker:timeDefaults`:: The default selection in the time filter. `truncate:maxHeight`:: The maximum height that a cell occupies in a table. Set to 0 to disable truncation. @@ -268,6 +268,3 @@ If disabled, only visualizations that are considered production-ready are availa Helps improve the Elastic Stack by providing usage statistics for basic features. This data will not be shared outside of Elastic. - - - diff --git a/package.json b/package.json index 29410042a865d..b1ba573ffaf5a 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "@elastic/charts": "^13.5.1", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "^1.0.2", - "@elastic/eui": "14.4.0", + "@elastic/eui": "14.5.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", "@elastic/numeral": "2.3.3", diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index 02195c794d280..71279ad6fed03 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -17,13 +17,13 @@ * under the License. */ -import React, { MouseEventHandler } from 'react'; +import React from 'react'; import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import * as Url from 'url'; import { i18n } from '@kbn/i18n'; -import { IconType } from '@elastic/eui'; +import { IconType, Breadcrumb as EuiBreadcrumb } from '@elastic/eui'; import { InjectedMetadataStart } from '../injected_metadata'; import { NotificationsStart } from '../notifications'; @@ -59,12 +59,7 @@ export interface ChromeBrand { } /** @public */ -export interface ChromeBreadcrumb { - text: string; - href?: string; - 'data-test-subj'?: string; - onClick?: MouseEventHandler; -} +export type ChromeBreadcrumb = EuiBreadcrumb; /** @public */ export type ChromeHelpExtension = (element: HTMLDivElement) => () => void; diff --git a/src/core/public/chrome/ui/header/__snapshots__/header_breadcrumbs.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header_breadcrumbs.test.tsx.snap index 2df1c616b04b3..d089019915686 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header_breadcrumbs.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header_breadcrumbs.test.tsx.snap @@ -5,7 +5,6 @@ exports[`HeaderBreadcrumbs renders updates to the breadcrumbs$ observable 1`] = aria-current="page" className="euiBreadcrumb euiBreadcrumb--last" data-test-subj="breadcrumb first last" - title="First" > First @@ -18,7 +17,6 @@ Array [ color="subdued" data-test-subj="breadcrumb first" title="First" - type="button" >

Hide the toolbar when the mouse is not within the Canvas?
"`; +exports[` can navigate Toolbar Settings, closes when activated 2`] = `"
Settings
Hide the toolbar when the mouse is not within the Canvas?
"`; -exports[` can navigate Toolbar Settings, closes when activated 3`] = `"
Settings
Hide the toolbar when the mouse is not within the Canvas?
"`; +exports[` can navigate Toolbar Settings, closes when activated 3`] = `"
Settings
Hide the toolbar when the mouse is not within the Canvas?
"`; diff --git a/x-pack/legacy/plugins/code/public/components/main/__snapshots__/breadcrumb.test.tsx.snap b/x-pack/legacy/plugins/code/public/components/main/__snapshots__/breadcrumb.test.tsx.snap index 0530d5ec0cbd6..05e7cc4639dec 100644 --- a/x-pack/legacy/plugins/code/public/components/main/__snapshots__/breadcrumb.test.tsx.snap +++ b/x-pack/legacy/plugins/code/public/components/main/__snapshots__/breadcrumb.test.tsx.snap @@ -11,7 +11,6 @@ exports[`render correctly 1`] = ` href="#github.com/elastic/TypeScript-Node-Starter/tree/master/src" onClick={[Function]} rel="noreferrer" - title="src" > src @@ -56,7 +55,6 @@ exports[`render correctly 1`] = ` href="#github.com/elastic/TypeScript-Node-Starter/tree/master/src/public/css/lib/bootstrap/mixins" onClick={[Function]} rel="noreferrer" - title="mixins" > mixins @@ -67,7 +65,6 @@ exports[`render correctly 1`] = ` aria-current="page" className="euiBreadcrumb euiBreadcrumb--last" data-test-subj="codeFileBreadcrumb-_alerts.scss" - title="_alerts.scss" > _alerts.scss diff --git a/x-pack/legacy/plugins/code/public/components/main/breadcrumb.tsx b/x-pack/legacy/plugins/code/public/components/main/breadcrumb.tsx index 1f6aa48e569ea..52c5bfa59d536 100644 --- a/x-pack/legacy/plugins/code/public/components/main/breadcrumb.tsx +++ b/x-pack/legacy/plugins/code/public/components/main/breadcrumb.tsx @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore -import { EuiBreadcrumbs } from '@elastic/eui'; +import { EuiBreadcrumbs, Breadcrumb as EuiBreadcrumb } from '@elastic/eui'; import React from 'react'; import { MainRouteParams } from '../../common/types'; import { encodeRevisionString } from '../../../common/uri_util'; @@ -20,13 +19,7 @@ export class Breadcrumb extends React.PureComponent { const { resource, org, repo, revision, path } = this.props.routeParams; const repoUri = `${resource}/${org}/${repo}`; - const breadcrumbs: Array<{ - text: string; - href: string; - className?: string; - ['data-test-subj']: string; - onClick?: Function; - }> = []; + const breadcrumbs: EuiBreadcrumb[] = []; const pathSegments = path ? path.split('/') : []; pathSegments.forEach((p, index, array) => { diff --git a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap b/x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap index b400e82bb3f80..a7cc8843140c8 100644 --- a/x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap +++ b/x-pack/legacy/plugins/index_lifecycle_management/__jest__/__snapshots__/extend_index_management.test.js.snap @@ -351,9 +351,7 @@ exports[`ilm summary extension should return extension when index has lifecycle className="euiDescriptionList__description" > - + } closePopover={[Function]} display="inlineBlock" @@ -522,9 +518,7 @@ exports[`ilm summary extension should return extension when index has lifecycle className="euiPopover__anchor" > - + `; @@ -94,7 +94,7 @@ exports[`NoData should show text next to the spinner while checking a setting 1`
-
@@ -176,6 +176,6 @@ exports[`NoData should show text next to the spinner while checking a setting 1`
-
+ `; diff --git a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap b/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap index 7579cad3b8beb..7b468d08e29a6 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap +++ b/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap @@ -5,7 +5,7 @@ exports[`PageLoading should show a simple page loading component 1`] = ` class="euiPage" style="height:calc(100vh - 50px)" > -
- + `; diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap b/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap index cdc183cec39b9..517a99583a54d 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap +++ b/x-pack/legacy/plugins/remote_clusters/public/app/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap @@ -40,7 +40,6 @@ Array [
{ return {}; } - return searchEmbeddable.searchScope.searchSource.getSearchRequestBody(); + return searchEmbeddable.getSavedSearch().searchSource.getSearchRequestBody(); } public isCompatible = async (context: ActionContext) => { diff --git a/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/__snapshots__/basic_login_form.test.tsx.snap b/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/__snapshots__/basic_login_form.test.tsx.snap index 35cac1c21d3ba..3b3024024a9cf 100644 --- a/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/__snapshots__/basic_login_form.test.tsx.snap +++ b/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/__snapshots__/basic_login_form.test.tsx.snap @@ -10,6 +10,7 @@ exports[`BasicLoginForm renders as expected 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} label={ - - +

} fullWidth={false} @@ -45,6 +43,7 @@ exports[`it renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={true} + hasChildLabel={true} hasEmptyLabelSpace={true} labelType="label" > @@ -80,19 +79,17 @@ exports[`it renders without crashing 1`] = ` id="xpack.security.management.editRole.elasticSearchPrivileges.howToBeSubmittedOnBehalfOfOtherUsersDescription" values={Object {}} /> - - +

} fullWidth={false} @@ -112,6 +109,7 @@ exports[`it renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={true} labelType="label" > @@ -156,10 +154,8 @@ exports[`it renders without crashing 1`] = ` /> diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap index c5572aa626291..37db2e118861e 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap @@ -29,6 +29,7 @@ exports[` renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={true} labelType="label" > diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap index a2768361a270c..c20a391cdb20c 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap @@ -31,6 +31,7 @@ exports[` renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={true} + hasChildLabel={true} hasEmptyLabelSpace={false} label="Spaces" labelType="label" @@ -163,6 +164,7 @@ exports[` renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={true} + hasChildLabel={true} hasEmptyLabelSpace={false} label="Privilege" labelType="label" diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx index 427fb621d5ddd..282ce4eea160c 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx @@ -418,165 +418,159 @@ class EditUserPageUI extends Component { /> ) : null} -
{ - event.preventDefault(); - }} - > - - - - - {isNewUser ? this.passwordFields() : null} - {reserved ? null : ( - - - - - - - - - )} - - + + + + {isNewUser ? this.passwordFields() : null} + {reserved ? null : ( + + { - return { 'data-test-subj': `roleOption-${role.name}`, label: role.name }; + > + + + - - - {isNewUser || showChangePasswordForm ? null : ( - - - - + > + - )} - {this.changePasswordForm()} - - + + )} + + { + return { 'data-test-subj': `roleOption-${role.name}`, label: role.name }; + })} + selectedOptions={selectedRoles} + /> + - {reserved && ( - changeUrl(USERS_PATH)}> + {isNewUser || showChangePasswordForm ? null : ( + + - - )} - {reserved ? null : ( - - - this.saveUser()} - > - {isNewUser ? ( - - ) : ( - - )} - - + + + )} + {this.changePasswordForm()} + + + + {reserved && ( + changeUrl(USERS_PATH)}> + + + )} + {reserved ? null : ( + + + this.saveUser()} + > + {isNewUser ? ( + + ) : ( + + )} + + + + changeUrl(USERS_PATH)} + > + + + + + {isNewUser || reserved ? null : ( changeUrl(USERS_PATH)} + onClick={() => { + this.setState({ showDeleteConfirmation: true }); + }} + data-test-subj="userFormDeleteButton" + color="danger" > - - {isNewUser || reserved ? null : ( - - { - this.setState({ showDeleteConfirmation: true }); - }} - data-test-subj="userFormDeleteButton" - color="danger" - > - - - - )} - - )} - -
+ )} + + )} +
diff --git a/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts b/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts index 234667b1a4d3c..6df9d6801e2dc 100644 --- a/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts +++ b/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SpacesPlugin } from '../../../../spaces'; +import { LegacySpacesPlugin } from '../../../../spaces'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; @@ -23,7 +23,7 @@ test(`checkPrivileges.atSpace when spaces is enabled`, async () => { getBasePath: jest.fn(), getScopedSpacesClient: jest.fn(), getActiveSpace: jest.fn(), - } as OptionalPlugin; + } as OptionalPlugin; const request = Symbol(); const privilegeOrPrivileges = ['foo', 'bar']; const checkPrivilegesDynamically = checkPrivilegesDynamicallyWithRequestFactory( @@ -45,7 +45,7 @@ test(`checkPrivileges.globally when spaces is disabled`, async () => { const mockCheckPrivilegesWithRequest = jest.fn().mockReturnValue(mockCheckPrivileges); const mockSpaces = { isEnabled: false, - } as OptionalPlugin; + } as OptionalPlugin; const request = Symbol(); const privilegeOrPrivileges = ['foo', 'bar']; const checkPrivilegesDynamically = checkPrivilegesDynamicallyWithRequestFactory( diff --git a/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.ts b/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.ts index 537bc07f8e80c..243ad100c5715 100644 --- a/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.ts +++ b/x-pack/legacy/plugins/security/server/lib/authorization/check_privileges_dynamically.ts @@ -13,7 +13,7 @@ import { CheckPrivilegesAtResourceResponse, CheckPrivilegesWithRequest } from '. * you may not use this file except in compliance with the Elastic License. */ -import { SpacesPlugin } from '../../../../spaces'; +import { LegacySpacesPlugin } from '../../../../spaces'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; export type CheckPrivilegesDynamically = ( @@ -26,7 +26,7 @@ export type CheckPrivilegesDynamicallyWithRequest = ( export function checkPrivilegesDynamicallyWithRequestFactory( checkPrivilegesWithRequest: CheckPrivilegesWithRequest, - spaces: OptionalPlugin + spaces: OptionalPlugin ): CheckPrivilegesDynamicallyWithRequest { return function checkPrivilegesDynamicallyWithRequest(request: Legacy.Request) { const checkPrivileges = checkPrivilegesWithRequest(request); diff --git a/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.test.ts b/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.test.ts index 82bd784a917cd..7fa02330fac97 100644 --- a/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.test.ts +++ b/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SpacesPlugin } from '../../../../spaces'; +import { LegacySpacesPlugin } from '../../../../spaces'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; @@ -19,7 +19,7 @@ test(`checkPrivileges.atSpace when spaces is enabled`, async () => { const mockSpaces = ({ isEnabled: true, namespaceToSpaceId: jest.fn().mockReturnValue(spaceId), - } as unknown) as OptionalPlugin; + } as unknown) as OptionalPlugin; const request = Symbol(); const privilegeOrPrivileges = ['foo', 'bar']; @@ -50,7 +50,7 @@ test(`checkPrivileges.globally when spaces is disabled`, async () => { namespaceToSpaceId: jest.fn().mockImplementation(() => { throw new Error('should not be called'); }), - } as unknown) as OptionalPlugin; + } as unknown) as OptionalPlugin; const request = Symbol(); diff --git a/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.ts b/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.ts index e20a843537541..fb1d258b5a05f 100644 --- a/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.ts +++ b/x-pack/legacy/plugins/security/server/lib/authorization/check_saved_objects_privileges.ts @@ -5,7 +5,7 @@ */ import { Legacy } from 'kibana'; -import { SpacesPlugin } from '../../../../spaces'; +import { LegacySpacesPlugin } from '../../../../spaces'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { CheckPrivilegesAtResourceResponse, CheckPrivilegesWithRequest } from './check_privileges'; @@ -19,7 +19,7 @@ export type CheckSavedObjectsPrivileges = ( export const checkSavedObjectsPrivilegesWithRequestFactory = ( checkPrivilegesWithRequest: CheckPrivilegesWithRequest, - spaces: OptionalPlugin + spaces: OptionalPlugin ): CheckSavedObjectsPrivilegesWithRequest => { return function checkSavedObjectsPrivilegesWithRequest(request: Legacy.Request) { return async function checkSavedObjectsPrivileges( diff --git a/x-pack/legacy/plugins/security/server/lib/authorization/service.ts b/x-pack/legacy/plugins/security/server/lib/authorization/service.ts index e939deb64bc09..3d248adb9f8b8 100644 --- a/x-pack/legacy/plugins/security/server/lib/authorization/service.ts +++ b/x-pack/legacy/plugins/security/server/lib/authorization/service.ts @@ -7,7 +7,7 @@ import { Server } from 'hapi'; import { getClient } from '../../../../../server/lib/get_client_shield'; -import { SpacesPlugin } from '../../../../spaces'; +import { LegacySpacesPlugin } from '../../../../spaces'; import { XPackFeature, XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { APPLICATION_PREFIX } from '../../../common/constants'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; @@ -38,7 +38,7 @@ export function createAuthorizationService( server: Server, securityXPackFeature: XPackFeature, xpackMainPlugin: XPackMainPlugin, - spaces: OptionalPlugin + spaces: OptionalPlugin ): AuthorizationService { const shieldClient = getClient(server); const config = server.config(); diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap index f482a864bed6d..1aa3b087ac0d0 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap @@ -18,41 +18,33 @@ exports[`IndexPatternsMissingPrompt renders correctly against snapshot 1`] = ` An ECS compliant Kibana index pattern must be configured to view event data on the map. When using beats, you can run the following setup commands to create the required Kibana index patterns, otherwise you can configure them manually within Kibana settings.

- auditbeat-* - + , - filebeat-* - + , - packetbeat-* - + , - winlogbeat-* - +

} diff --git a/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/anomaly_score.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/anomaly_score.test.tsx.snap index 0698653696059..8760dce2b76df 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/anomaly_score.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/anomaly_score.test.tsx.snap @@ -125,14 +125,12 @@ exports[`anomaly_scores renders correctly against snapshot 1`] = ` - View in Machine Learning - + , "title": @@ -158,15 +156,13 @@ exports[`anomaly_scores renders correctly against snapshot 1`] = ` - Narrow to this date range - + , "title": "Detected", diff --git a/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/create_descriptions_list.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/create_descriptions_list.test.tsx.snap index 30afaa7bc71f7..0a136eb31fd6d 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/create_descriptions_list.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/ml/score/__snapshots__/create_descriptions_list.test.tsx.snap @@ -44,10 +44,8 @@ exports[`create_description_list renders correctly against snapshot 1`] = ` grow={false} > View in Machine Learning @@ -78,11 +76,9 @@ exports[`create_description_list renders correctly against snapshot 1`] = ` grow={false} > Narrow to this date range diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/popover_description.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/popover_description.test.tsx.snap index 5eeaee17ee72a..09e95c5ff59ea 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/popover_description.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/popover_description.test.tsx.snap @@ -9,18 +9,16 @@ exports[`JobsTableFilters renders correctly against snapshot 1`] = ` id="xpack.siem.components.mlPopup.anomalyDetectionDescription" values={ Object { - "machineLearning": - , + , } } /> diff --git a/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/upgrade_contents.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/upgrade_contents.test.tsx.snap index cf924f3a06edc..113612200d367 100644 --- a/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/upgrade_contents.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/ml_popover/__snapshots__/upgrade_contents.test.tsx.snap @@ -15,18 +15,16 @@ exports[`JobsTableFilters renders correctly against snapshot 1`] = ` id="xpack.siem.components.mlPopup.upgradeDescription" values={ Object { - "cloudLink": - , + , } } /> diff --git a/x-pack/legacy/plugins/spaces/common/index.ts b/x-pack/legacy/plugins/spaces/common/index.ts index a0842201e0f08..8961c9c5ccf79 100644 --- a/x-pack/legacy/plugins/spaces/common/index.ts +++ b/x-pack/legacy/plugins/spaces/common/index.ts @@ -6,5 +6,3 @@ export { isReservedSpace } from './is_reserved_space'; export { MAX_SPACE_INITIALS } from './constants'; - -export { getSpaceIdFromPath, addSpaceIdToPath } from './lib/spaces_url_parser'; diff --git a/x-pack/legacy/plugins/spaces/index.ts b/x-pack/legacy/plugins/spaces/index.ts index a287aa2fcbb3f..a92fdcb9304cd 100644 --- a/x-pack/legacy/plugins/spaces/index.ts +++ b/x-pack/legacy/plugins/spaces/index.ts @@ -4,29 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as Rx from 'rxjs'; import { resolve } from 'path'; import KbnServer, { Server } from 'src/legacy/server/kbn_server'; -import { CoreSetup, PluginInitializerContext } from 'src/core/server'; +import { Legacy } from 'kibana'; +import { KibanaRequest } from '../../../../src/core/server'; +import { SpacesServiceSetup } from '../../../plugins/spaces/server/spaces_service/spaces_service'; +import { SpacesPluginSetup } from '../../../plugins/spaces/server'; import { createOptionalPlugin } from '../../server/lib/optional_plugin'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; import mappings from './mappings.json'; import { wrapError } from './server/lib/errors'; -import { getActiveSpace } from './server/lib/get_active_space'; import { migrateToKibana660 } from './server/lib/migrations'; -import { plugin } from './server/new_platform'; import { SecurityPlugin } from '../security'; -import { SpacesServiceSetup } from './server/new_platform/spaces_service/spaces_service'; +// @ts-ignore +import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize'; import { initSpaceSelectorView, initEnterSpaceView } from './server/routes/views'; -export interface SpacesPlugin { - getSpaceId: SpacesServiceSetup['getSpaceId']; - getActiveSpace: SpacesServiceSetup['getActiveSpace']; +export interface LegacySpacesPlugin { + getSpaceId: (request: Legacy.Request) => ReturnType; + getActiveSpace: (request: Legacy.Request) => ReturnType; spaceIdToNamespace: SpacesServiceSetup['spaceIdToNamespace']; namespaceToSpaceId: SpacesServiceSetup['namespaceToSpaceId']; getBasePath: SpacesServiceSetup['getBasePath']; - getScopedSpacesClient: SpacesServiceSetup['scopedClient']; } export const spaces = (kibana: Record) => @@ -36,13 +36,6 @@ export const spaces = (kibana: Record) => publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], - config(Joi: any) { - return Joi.object({ - enabled: Joi.boolean().default(true), - maxSpaces: Joi.number().default(1000), - }).default(); - }, - uiCapabilities() { return { spaces: { @@ -92,18 +85,20 @@ export const spaces = (kibana: Record) => }, async replaceInjectedVars( vars: Record, - request: Record, + request: Legacy.Request, server: Record ) { - const spacesClient = await server.plugins.spaces.getScopedSpacesClient(request); + const spacesPlugin = server.newPlatform.setup.plugins.spaces as SpacesPluginSetup; + if (!spacesPlugin) { + throw new Error('New Platform XPack Spaces plugin is not available.'); + } + const kibanaRequest = KibanaRequest.from(request); + const spaceId = spacesPlugin.spacesService.getSpaceId(kibanaRequest); + const spacesClient = await spacesPlugin.spacesService.scopedClient(kibanaRequest); try { vars.activeSpace = { valid: true, - space: await getActiveSpace( - spacesClient, - request.getBasePath(), - server.config().get('server.basePath') - ), + space: await spacesClient.get(spaceId), }; } catch (e) { vars.activeSpace = { @@ -118,52 +113,18 @@ export const spaces = (kibana: Record) => async init(server: Server) { const kbnServer = (server as unknown) as KbnServer; - const initializerContext = { - config: { - create: () => { - return Rx.of({ - maxSpaces: server.config().get('xpack.spaces.maxSpaces'), - }); - }, - }, - logger: { - get(...contextParts: string[]) { - return kbnServer.newPlatform.coreContext.logger.get( - 'plugins', - 'spaces', - ...contextParts - ); - }, - }, - } as PluginInitializerContext; - const core = (kbnServer.newPlatform.setup.core as unknown) as CoreSetup; - - const plugins = { - xpackMain: server.plugins.xpack_main, - // TODO: Spaces has a circular dependency with Security right now. - // Security is not yet available when init runs, so this is wrapped in an optional function for the time being. - security: createOptionalPlugin( - server.config(), - 'xpack.security', - server.plugins, - 'security' - ), - spaces: this, - }; - - const { spacesService, registerLegacyAPI } = await plugin(initializerContext).setup( - core, - plugins - ); + const spacesPlugin = kbnServer.newPlatform.setup.plugins.spaces as SpacesPluginSetup; + if (!spacesPlugin) { + throw new Error('New Platform XPack Spaces plugin is not available.'); + } const config = server.config(); + const { registerLegacyAPI, createDefaultSpace } = spacesPlugin.__legacyCompat; + registerLegacyAPI({ - router: server.route.bind(server), legacyConfig: { - serverBasePath: config.get('server.basePath'), - serverDefaultRoute: config.get('server.defaultRoute'), kibanaIndex: config.get('kibana.index'), }, savedObjects: server.savedObjects, @@ -178,16 +139,30 @@ export const spaces = (kibana: Record) => create: (pluginId: string) => new AuditLogger(server, pluginId, server.config(), server.plugins.xpack_main.info), }, + security: createOptionalPlugin( + server.config(), + 'xpack.security', + server.plugins, + 'security' + ), + xpackMain: server.plugins.xpack_main, }); initEnterSpaceView(server); initSpaceSelectorView(server); - server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); - server.expose('getActiveSpace', spacesService.getActiveSpace); - server.expose('spaceIdToNamespace', spacesService.spaceIdToNamespace); - server.expose('namespaceToSpaceId', spacesService.namespaceToSpaceId); - server.expose('getBasePath', spacesService.getBasePath); - server.expose('getScopedSpacesClient', spacesService.scopedClient); + watchStatusAndLicenseToInitialize(server.plugins.xpack_main, this, async () => { + await createDefaultSpace(); + }); + + server.expose('getSpaceId', (request: Legacy.Request) => + spacesPlugin.spacesService.getSpaceId(request) + ); + server.expose('getActiveSpace', (request: Legacy.Request) => + spacesPlugin.spacesService.getActiveSpace(request) + ); + server.expose('spaceIdToNamespace', spacesPlugin.spacesService.spaceIdToNamespace); + server.expose('namespaceToSpaceId', spacesPlugin.spacesService.namespaceToSpaceId); + server.expose('getBasePath', spacesPlugin.spacesService.getBasePath); }, }); diff --git a/x-pack/legacy/plugins/spaces/public/lib/spaces_manager.ts b/x-pack/legacy/plugins/spaces/public/lib/spaces_manager.ts index e40e247e405fb..c1672e65326aa 100644 --- a/x-pack/legacy/plugins/spaces/public/lib/spaces_manager.ts +++ b/x-pack/legacy/plugins/spaces/public/lib/spaces_manager.ts @@ -10,7 +10,7 @@ import { Space } from '../../common/model/space'; import { GetSpacePurpose } from '../../common/model/types'; import { CopySavedObjectsToSpaceResponse } from './copy_saved_objects_to_space/types'; import { ENTER_SPACE_PATH } from '../../common/constants'; -import { addSpaceIdToPath } from '../../common'; +import { addSpaceIdToPath } from '../../../../../plugins/spaces/common'; export class SpacesManager extends EventEmitter { constructor(private readonly serverBasePath: string) { diff --git a/x-pack/legacy/plugins/spaces/public/views/management/components/__snapshots__/confirm_delete_modal.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/components/__snapshots__/confirm_delete_modal.test.tsx.snap index 3aa6cd3497783..82f94f2346ae7 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/components/__snapshots__/confirm_delete_modal.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/components/__snapshots__/confirm_delete_modal.test.tsx.snap @@ -49,6 +49,7 @@ exports[`ConfirmDeleteModal renders as expected 1`] = ` display="row" error="Space names do not match." fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} isInvalid={false} label="Confirm space name to delete" diff --git a/x-pack/legacy/plugins/spaces/public/views/management/components/secure_space_message/__snapshots__/secure_space_message.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/components/secure_space_message/__snapshots__/secure_space_message.test.tsx.snap index 9316ef46b8b61..bce57527cd55a 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/components/secure_space_message/__snapshots__/secure_space_message.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/components/secure_space_message/__snapshots__/secure_space_message.test.tsx.snap @@ -14,18 +14,16 @@ exports[`SecureSpaceMessage renders if security is enabled 1`] = ` id="xpack.spaces.management.secureSpaceMessage.howToAssignRoleToSpaceDescription" values={ Object { - "rolesLink": - , + , } } /> diff --git a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap index 97e4bae437cfc..24e6bd7516819 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap @@ -8,6 +8,7 @@ exports[`renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} label="Initials (2 max)" labelType="label" @@ -30,6 +31,7 @@ exports[`renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} isInvalid={false} label="Color" @@ -48,6 +50,7 @@ exports[`renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} label="Custom image" labelType="label" diff --git a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap index bcff2efcebeaf..15fd1ae81a347 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap @@ -6,6 +6,7 @@ exports[`renders without crashing 1`] = ` describedByIds={Array []} display="row" fullWidth={true} + hasChildLabel={true} hasEmptyLabelSpace={false} helpText={

- - +

} labelType="label" diff --git a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap index 6118c68aa9f99..5e91c1bd0e36c 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap @@ -169,17 +169,15 @@ exports[`EnabledFeatures renders as expected 1`] = ` id="xpack.spaces.management.enabledSpaceFeatures.goToRolesLink" values={ Object { - "rolesLink": - , + , } } /> diff --git a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap index 6c13259cdde88..43149d7b3911f 100644 --- a/x-pack/legacy/plugins/spaces/public/views/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap @@ -29,10 +29,8 @@ exports[`it renders without blowing up 1`] = ` > hide diff --git a/x-pack/legacy/plugins/spaces/public/views/space_selector/__snapshots__/space_selector.test.tsx.snap b/x-pack/legacy/plugins/spaces/public/views/space_selector/__snapshots__/space_selector.test.tsx.snap index 84ed864c36231..722d8908d480b 100644 --- a/x-pack/legacy/plugins/spaces/public/views/space_selector/__snapshots__/space_selector.test.tsx.snap +++ b/x-pack/legacy/plugins/spaces/public/views/space_selector/__snapshots__/space_selector.test.tsx.snap @@ -7,6 +7,7 @@ exports[`it renders without crashing 1`] = ` restrictWidth={false} > { - const spaceId = getSpaceIdFromPath(requestBasePath, serverBasePath); - - try { - return spacesClient.get(spaceId); - } catch (e) { - throw wrapError(e); - } -} diff --git a/x-pack/legacy/plugins/spaces/server/lib/route_pre_check_license.ts b/x-pack/legacy/plugins/spaces/server/lib/route_pre_check_license.ts deleted file mode 100644 index b29f55d6669aa..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/lib/route_pre_check_license.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; -import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; - -interface LicenseCheckDeps { - xpackMain: XPackMainPlugin; -} - -export function routePreCheckLicense({ xpackMain }: LicenseCheckDeps) { - const pluginId = 'spaces'; - return function forbidApiAccess(request: any) { - const licenseCheckResults = xpackMain.info.feature(pluginId).getLicenseCheckResults(); - if (!licenseCheckResults.showSpaces) { - return Boom.forbidden(licenseCheckResults.linksMessage); - } else { - return ''; - } - }; -} diff --git a/x-pack/legacy/plugins/spaces/server/lib/space_schema.test.ts b/x-pack/legacy/plugins/spaces/server/lib/space_schema.test.ts deleted file mode 100644 index f3356c7f090f5..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/lib/space_schema.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { spaceSchema } from './space_schema'; - -const defaultProperties = { - id: 'foo', - name: 'foo', -}; - -describe('#id', () => { - test('is optional', () => { - const result = spaceSchema.validate({ - ...defaultProperties, - id: undefined, - }); - expect(result.error).toBeNull(); - }); - - test('allows lowercase a-z, 0-9, "_" and "-"', () => { - const result = spaceSchema.validate({ - ...defaultProperties, - id: 'abcdefghijklmnopqrstuvwxyz0123456789_-', - }); - expect(result.error).toBeNull(); - }); - - test(`doesn't allow uppercase`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - id: 'Foo', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "id" fails because ["id" with value "Foo" fails to match the lower case, a-z, 0-9, "_", and "-" are allowed pattern]]` - ); - }); - - test(`doesn't allow an empty string`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - id: '', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "id" fails because ["id" is not allowed to be empty]]` - ); - }); - - ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', ',', '.', '/', '?'].forEach( - invalidCharacter => { - test(`doesn't allow ${invalidCharacter}`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - id: `foo-${invalidCharacter}`, - }); - expect(result.error).toMatchObject({ - message: `child "id" fails because ["id" with value "foo-${invalidCharacter}" fails to match the lower case, a-z, 0-9, "_", and "-" are allowed pattern]`, - }); - }); - } - ); -}); - -describe('#color', () => { - test('is optional', () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: undefined, - }); - expect(result.error).toBeNull(); - }); - - test(`doesn't allow an empty string`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "color" fails because ["color" is not allowed to be empty]]` - ); - }); - - test(`allows lower case hex color code`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '#aabbcc', - }); - expect(result.error).toBeNull(); - }); - - test(`allows upper case hex color code`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '#AABBCC', - }); - expect(result.error).toBeNull(); - }); - - test(`allows numeric hex color code`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '#123456', - }); - expect(result.error).toBeNull(); - }); - - test(`must start with a hash`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '123456', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "color" fails because ["color" with value "123456" fails to match the 6 digit hex color, starting with a # pattern]]` - ); - }); - - test(`cannot exceed 6 digits following the hash`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '1234567', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "color" fails because ["color" with value "1234567" fails to match the 6 digit hex color, starting with a # pattern]]` - ); - }); - - test(`cannot be fewer than 6 digits following the hash`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - color: '12345', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "color" fails because ["color" with value "12345" fails to match the 6 digit hex color, starting with a # pattern]]` - ); - }); -}); - -describe('#imageUrl', () => { - test('is optional', () => { - const result = spaceSchema.validate({ - ...defaultProperties, - imageUrl: undefined, - }); - expect(result.error).toBeNull(); - }); - - test(`must start with data:image`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - imageUrl: 'notValid', - }); - expect(result.error).toMatchInlineSnapshot( - `[ValidationError: child "imageUrl" fails because ["imageUrl" with value "notValid" fails to match the Image URL should start with 'data:image' pattern]]` - ); - }); - - test(`checking that a valid image is accepted as imageUrl`, () => { - const result = spaceSchema.validate({ - ...defaultProperties, - imageUrl: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTnU1rJkAAAB3klEQVRYR+2WzUrDQBCARzwqehE8ir1WPfgqRRA1bePBXgpe/MGCB9/Aiw+j+ASCB6kotklaEwW1F0WwNSaps9lV69awGzBpDzt8pJP9mXxsmk3ABH2oUEIilJAIJSRCCYlQQiKUkIh4QgY5agZodVjBowFrBktWQzDBU2ykiYaDuQpCYgnl3QunGzM6Z6YF+b5SkcgK1UH/aLbYReQiYL9d9/o+XFop5IU0Vl4uapAzoXC3eEBPw9vH1/wT6Vs2otPSkoH/IZzlzO/TU2vgQm8nl69Hp0H7nZ4OXogLJSSKBIUC3w88n+Ueyfv56fVZnqCQNVnCHbLrkV0Gd2d+GNkglsk438dhaTxloZDutV4wb06Vf40JcWZ2sMttPpE8NaHGeBnzIAhwPXqHseVB11EyLD0hxLUeaYud2a3B0g3k7GyFtrhX7F2RqhC+yV3jgTb2Rqdqf7/kUxYiWBOlTtXxfPJEtc8b5thGb+8AhL4ohnCNqQjZ2T2+K5rnw2M6KwEhKNDSGM3pTdxjhDgLbHkw/v/zw4AiPuSsfMzAiTidKxiF/ArpFqyzK8SMOlkwvloUMYRCtNvZLWeuIomd2Za/WZS4QomjhEQoIRFKSIQSEqGERAyfEH4YDBFQ/ARU6BiBxCAIQQAAAABJRU5ErkJggg==', - }); - expect(result.error).toBeNull(); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/lib/space_schema.ts b/x-pack/legacy/plugins/spaces/server/lib/space_schema.ts deleted file mode 100644 index 2b8175b09794e..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/lib/space_schema.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; -import { MAX_SPACE_INITIALS } from '../../common/constants'; - -export const SPACE_ID_REGEX = /^[a-z0-9_\-]+$/; - -export const spaceSchema = Joi.object({ - id: Joi.string().regex(SPACE_ID_REGEX, `lower case, a-z, 0-9, "_", and "-" are allowed`), - name: Joi.string().required(), - description: Joi.string().allow(''), - initials: Joi.string().max(MAX_SPACE_INITIALS), - color: Joi.string().regex(/^#[a-zA-Z0-9]{6}$/, `6 digit hex color, starting with a #`), - disabledFeatures: Joi.array() - .items(Joi.string()) - .default([]), - _reserved: Joi.boolean(), - imageUrl: Joi.string() - .allow('') - .regex(/^data:image.*$/, `Image URL should start with 'data:image'`), -}).default(); diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/config.ts b/x-pack/legacy/plugins/spaces/server/new_platform/config.ts deleted file mode 100644 index fbe8edb14f19b..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/new_platform/config.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { schema, TypeOf } from '@kbn/config-schema'; - -export const config = { - schema: schema.object({ - maxSpaces: schema.number({ defaultValue: 1000 }), - }), -}; - -export type SpacesConfigType = TypeOf; diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts deleted file mode 100644 index 405a3dd34e7fc..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import * as Rx from 'rxjs'; -import { Server } from 'hapi'; -import { Legacy } from 'kibana'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { elasticsearchServiceMock, coreMock } from 'src/core/server/mocks'; -import { SavedObjectsSchema, SavedObjectsLegacyService } from 'src/core/server'; -import { Readable } from 'stream'; -import { createPromiseFromStreams, createConcatStream } from 'src/legacy/utils/streams'; -import { createOptionalPlugin } from '../../../../../../server/lib/optional_plugin'; -import { SpacesClient } from '../../../lib/spaces_client'; -import { createSpaces } from './create_spaces'; -import { ExternalRouteDeps } from '../external'; -import { SpacesService } from '../../../new_platform/spaces_service'; -import { SpacesAuditLogger } from '../../../lib/audit_logger'; -import { LegacyAPI } from '../../../new_platform/plugin'; - -interface KibanaServer extends Legacy.Server { - savedObjects: any; -} - -export interface TestConfig { - [configKey: string]: any; -} - -export interface TestOptions { - setupFn?: (server: any) => void; - testConfig?: TestConfig; - payload?: any; - preCheckLicenseImpl?: (req: any, h: any) => any; - expectSpacesClientCall?: boolean; - expectPreCheckLicenseCall?: boolean; -} - -export type TeardownFn = () => void; - -export interface RequestRunnerResult { - server: any; - mockSavedObjectsRepository: any; - mockSavedObjectsService: { - getScopedSavedObjectsClient: jest.Mock< - SavedObjectsLegacyService['getScopedSavedObjectsClient'] - >; - importExport: { - getSortedObjectsForExport: jest.Mock< - SavedObjectsLegacyService['importExport']['getSortedObjectsForExport'] - >; - importSavedObjects: jest.Mock< - SavedObjectsLegacyService['importExport']['importSavedObjects'] - >; - resolveImportErrors: jest.Mock< - SavedObjectsLegacyService['importExport']['resolveImportErrors'] - >; - }; - }; - headers: Record; - response: any; -} - -export type RequestRunner = ( - method: string, - path: string, - options?: TestOptions -) => Promise; - -export const defaultPreCheckLicenseImpl = (request: any) => ''; - -const baseConfig: TestConfig = { - 'server.basePath': '', -}; - -async function readStreamToCompletion(stream: Readable) { - return (createPromiseFromStreams([stream, createConcatStream([])]) as unknown) as any[]; -} - -export function createTestHandler(initApiFn: (deps: ExternalRouteDeps) => void) { - const teardowns: TeardownFn[] = []; - - const spaces = createSpaces(); - - const request: RequestRunner = async ( - method: string, - path: string, - options: TestOptions = {} - ) => { - const { - setupFn = () => { - return; - }, - testConfig = {}, - payload, - preCheckLicenseImpl = defaultPreCheckLicenseImpl, - expectPreCheckLicenseCall = true, - expectSpacesClientCall = true, - } = options; - - let pre = jest.fn(); - if (preCheckLicenseImpl) { - pre = pre.mockImplementation(preCheckLicenseImpl); - } - - const server = new Server() as KibanaServer; - - const config = { - ...baseConfig, - ...testConfig, - }; - - await setupFn(server); - - const mockConfig = { - get: (key: string) => config[key], - }; - - server.decorate('server', 'config', jest.fn(() => mockConfig)); - - const mockSavedObjectsClientContract = { - get: jest.fn((type, id) => { - const result = spaces.filter(s => s.id === id); - if (!result.length) { - throw new Error(`not found: [${type}:${id}]`); - } - return result[0]; - }), - find: jest.fn(() => { - return { - total: spaces.length, - saved_objects: spaces, - }; - }), - create: jest.fn((type, attributes, { id }) => { - if (spaces.find(s => s.id === id)) { - throw new Error('conflict'); - } - return {}; - }), - update: jest.fn((type, id) => { - if (!spaces.find(s => s.id === id)) { - throw new Error('not found: during update'); - } - return {}; - }), - delete: jest.fn((type: string, id: string) => { - return {}; - }), - deleteByNamespace: jest.fn(), - }; - - server.savedObjects = { - types: ['visualization', 'dashboard', 'index-pattern', 'globalType'], - schema: new SavedObjectsSchema({ - space: { - isNamespaceAgnostic: true, - hidden: true, - }, - globalType: { - isNamespaceAgnostic: true, - }, - }), - getScopedSavedObjectsClient: jest.fn().mockResolvedValue(mockSavedObjectsClientContract), - importExport: { - getSortedObjectsForExport: jest.fn().mockResolvedValue( - new Readable({ - objectMode: true, - read() { - if (Array.isArray(payload.objects)) { - payload.objects.forEach((o: any) => this.push(o)); - } - this.push(null); - }, - }) - ), - importSavedObjects: jest.fn().mockImplementation(async (opts: Record) => { - const objectsToImport: any[] = await readStreamToCompletion(opts.readStream); - return { - success: true, - successCount: objectsToImport.length, - }; - }), - resolveImportErrors: jest.fn().mockImplementation(async (opts: Record) => { - const objectsToImport: any[] = await readStreamToCompletion(opts.readStream); - return { - success: true, - successCount: objectsToImport.length, - }; - }), - }, - SavedObjectsClient: { - errors: { - isNotFoundError: jest.fn((e: any) => e.message.startsWith('not found:')), - isConflictError: jest.fn((e: any) => e.message.startsWith('conflict')), - }, - }, - }; - - server.plugins.elasticsearch = { - createCluster: jest.fn(), - waitUntilReady: jest.fn(), - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), - }), - }; - - const log = { - log: jest.fn(), - trace: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - fatal: jest.fn(), - }; - - const coreSetupMock = coreMock.createSetup(); - - const legacyAPI = { - legacyConfig: { - serverBasePath: mockConfig.get('server.basePath'), - serverDefaultRoute: mockConfig.get('server.defaultRoute'), - }, - savedObjects: server.savedObjects, - } as LegacyAPI; - - const service = new SpacesService(log, () => legacyAPI); - const spacesService = await service.setup({ - http: coreSetupMock.http, - elasticsearch: elasticsearchServiceMock.createSetupContract(), - security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), - getSpacesAuditLogger: () => ({} as SpacesAuditLogger), - config$: Rx.of({ maxSpaces: 1000 }), - }); - - spacesService.scopedClient = jest.fn((req: any) => { - return Promise.resolve( - new SpacesClient( - null as any, - () => null, - null, - mockSavedObjectsClientContract, - { maxSpaces: 1000 }, - mockSavedObjectsClientContract, - req - ) - ); - }); - - initApiFn({ - routePreCheckLicenseFn: pre, - savedObjects: server.savedObjects, - spacesService, - log, - legacyRouter: server.route.bind(server), - }); - - teardowns.push(() => server.stop()); - - const headers = { - authorization: 'foo', - }; - - const testRun = async () => { - const response = await server.inject({ - method, - url: path, - headers, - payload, - }); - - if (preCheckLicenseImpl && expectPreCheckLicenseCall) { - expect(pre).toHaveBeenCalled(); - } else { - expect(pre).not.toHaveBeenCalled(); - } - - if (expectSpacesClientCall) { - expect(spacesService.scopedClient).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - authorization: headers.authorization, - }), - }) - ); - } else { - expect(spacesService.scopedClient).not.toHaveBeenCalled(); - } - - return response; - }; - - return { - server, - headers, - mockSavedObjectsRepository: mockSavedObjectsClientContract, - mockSavedObjectsService: server.savedObjects, - response: await testRun(), - }; - }; - - return { - request, - teardowns, - }; -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.test.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.test.ts deleted file mode 100644 index 292fc21a2dd79..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.test.ts +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -jest.mock('../../../lib/route_pre_check_license', () => { - return { - routePreCheckLicense: () => (request: any, h: any) => h.continue, - }; -}); - -jest.mock('../../../../../../server/lib/get_client_shield', () => { - return { - getClient: () => { - return { - callWithInternalUser: jest.fn(() => { - return; - }), - }; - }, - }; -}); - -import Boom from 'boom'; -import { createTestHandler, RequestRunner, TeardownFn } from '../__fixtures__'; -import { initCopyToSpacesApi } from './copy_to_space'; - -describe('POST /api/spaces/_copy_saved_objects', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - - beforeEach(() => { - const setup = createTestHandler(initCopyToSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const payload = { - spaces: ['a-space'], - objects: [], - }; - - const { response } = await request('POST', '/api/spaces/_copy_saved_objects', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(responsePayload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test(`uses a Saved Objects Client instance without the spaces wrapper`, async () => { - const payload = { - spaces: ['a-space'], - objects: [], - }; - - const { mockSavedObjectsService } = await request('POST', '/api/spaces/_copy_saved_objects', { - expectSpacesClientCall: false, - payload, - }); - - expect(mockSavedObjectsService.getScopedSavedObjectsClient).toHaveBeenCalledWith( - expect.any(Object), - { - excludedWrappers: ['spaces'], - } - ); - }); - - test(`requires space IDs to be unique`, async () => { - const payload = { - spaces: ['a-space', 'a-space'], - objects: [], - }; - - const { response } = await request('POST', '/api/spaces/_copy_saved_objects', { - expectSpacesClientCall: false, - expectPreCheckLicenseCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(responsePayload)).toMatchInlineSnapshot(` - Object { - "error": "Bad Request", - "message": "Invalid request payload input", - "statusCode": 400, - } - `); - }); - - test(`requires well-formed space IDS`, async () => { - const payload = { - spaces: ['a-space', 'a-space-invalid-!@#$%^&*()'], - objects: [], - }; - - const { response } = await request('POST', '/api/spaces/_copy_saved_objects', { - expectSpacesClientCall: false, - expectPreCheckLicenseCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(responsePayload)).toMatchInlineSnapshot(` - Object { - "error": "Bad Request", - "message": "Invalid request payload input", - "statusCode": 400, - } - `); - }); - - test(`requires objects to be unique`, async () => { - const payload = { - spaces: ['a-space'], - objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], - }; - - const { response } = await request('POST', '/api/spaces/_copy_saved_objects', { - expectSpacesClientCall: false, - expectPreCheckLicenseCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(responsePayload)).toMatchInlineSnapshot(` - Object { - "error": "Bad Request", - "message": "Invalid request payload input", - "statusCode": 400, - } - `); - }); - - test('does not allow namespace agnostic types to be copied (via "supportedTypes" property)', async () => { - const payload = { - spaces: ['a-space'], - objects: [{ type: 'globalType', id: 'bar' }, { type: 'visualization', id: 'bar' }], - }; - - const { response, mockSavedObjectsService } = await request( - 'POST', - '/api/spaces/_copy_saved_objects', - { - expectSpacesClientCall: false, - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsService.importExport.importSavedObjects).toHaveBeenCalledTimes(1); - const [ - importCallOptions, - ] = mockSavedObjectsService.importExport.importSavedObjects.mock.calls[0]; - - expect(importCallOptions).toMatchObject({ - namespace: 'a-space', - supportedTypes: ['visualization', 'dashboard', 'index-pattern'], - }); - }); - - test('copies to multiple spaces', async () => { - const payload = { - spaces: ['a-space', 'b-space'], - objects: [{ type: 'visualization', id: 'bar' }], - }; - - const { response, mockSavedObjectsService } = await request( - 'POST', - '/api/spaces/_copy_saved_objects', - { - expectSpacesClientCall: false, - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsService.importExport.importSavedObjects).toHaveBeenCalledTimes(2); - const [ - firstImportCallOptions, - ] = mockSavedObjectsService.importExport.importSavedObjects.mock.calls[0]; - - expect(firstImportCallOptions).toMatchObject({ - namespace: 'a-space', - }); - - const [ - secondImportCallOptions, - ] = mockSavedObjectsService.importExport.importSavedObjects.mock.calls[1]; - - expect(secondImportCallOptions).toMatchObject({ - namespace: 'b-space', - }); - }); -}); - -describe('POST /api/spaces/_resolve_copy_saved_objects_errors', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - - beforeEach(() => { - const setup = createTestHandler(initCopyToSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const payload = { - retries: {}, - objects: [], - }; - - const { response } = await request('POST', '/api/spaces/_resolve_copy_saved_objects_errors', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(responsePayload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test(`uses a Saved Objects Client instance without the spaces wrapper`, async () => { - const payload = { - retries: { - ['a-space']: [ - { - type: 'visualization', - id: 'bar', - overwrite: true, - }, - ], - }, - objects: [{ type: 'visualization', id: 'bar' }], - }; - - const { mockSavedObjectsService } = await request( - 'POST', - '/api/spaces/_resolve_copy_saved_objects_errors', - { - expectSpacesClientCall: false, - payload, - } - ); - - expect(mockSavedObjectsService.getScopedSavedObjectsClient).toHaveBeenCalledWith( - expect.any(Object), - { - excludedWrappers: ['spaces'], - } - ); - }); - - test(`requires objects to be unique`, async () => { - const payload = { - retries: {}, - objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], - }; - - const { response } = await request('POST', '/api/spaces/_resolve_copy_saved_objects_errors', { - expectSpacesClientCall: false, - expectPreCheckLicenseCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(responsePayload)).toMatchInlineSnapshot(` - Object { - "error": "Bad Request", - "message": "Invalid request payload input", - "statusCode": 400, - } - `); - }); - - test(`requires well-formed space ids`, async () => { - const payload = { - retries: { - ['invalid-space-id!@#$%^&*()']: [ - { - type: 'foo', - id: 'bar', - overwrite: true, - }, - ], - }, - objects: [{ type: 'foo', id: 'bar' }], - }; - - const { response } = await request('POST', '/api/spaces/_resolve_copy_saved_objects_errors', { - expectSpacesClientCall: false, - expectPreCheckLicenseCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(responsePayload)).toMatchInlineSnapshot(` - Object { - "error": "Bad Request", - "message": "Invalid request payload input", - "statusCode": 400, - } - `); - }); - - test('does not allow namespace agnostic types to be copied (via "supportedTypes" property)', async () => { - const payload = { - retries: { - ['a-space']: [ - { - type: 'visualization', - id: 'bar', - overwrite: true, - }, - { - type: 'globalType', - id: 'bar', - overwrite: true, - }, - ], - }, - objects: [ - { - type: 'globalType', - id: 'bar', - }, - { type: 'visualization', id: 'bar' }, - ], - }; - - const { response, mockSavedObjectsService } = await request( - 'POST', - '/api/spaces/_resolve_copy_saved_objects_errors', - { - expectSpacesClientCall: false, - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsService.importExport.resolveImportErrors).toHaveBeenCalledTimes(1); - const [ - resolveImportErrorsCallOptions, - ] = mockSavedObjectsService.importExport.resolveImportErrors.mock.calls[0]; - - expect(resolveImportErrorsCallOptions).toMatchObject({ - namespace: 'a-space', - supportedTypes: ['visualization', 'dashboard', 'index-pattern'], - }); - }); - - test('resolves conflicts for multiple spaces', async () => { - const payload = { - objects: [{ type: 'visualization', id: 'bar' }], - retries: { - ['a-space']: [ - { - type: 'visualization', - id: 'bar', - overwrite: true, - }, - ], - ['b-space']: [ - { - type: 'globalType', - id: 'bar', - overwrite: true, - }, - ], - }, - }; - - const { response, mockSavedObjectsService } = await request( - 'POST', - '/api/spaces/_resolve_copy_saved_objects_errors', - { - expectSpacesClientCall: false, - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsService.importExport.resolveImportErrors).toHaveBeenCalledTimes(2); - const [ - resolveImportErrorsFirstCallOptions, - ] = mockSavedObjectsService.importExport.resolveImportErrors.mock.calls[0]; - - expect(resolveImportErrorsFirstCallOptions).toMatchObject({ - namespace: 'a-space', - supportedTypes: ['visualization', 'dashboard', 'index-pattern'], - }); - - const [ - resolveImportErrorsSecondCallOptions, - ] = mockSavedObjectsService.importExport.resolveImportErrors.mock.calls[1]; - - expect(resolveImportErrorsSecondCallOptions).toMatchObject({ - namespace: 'b-space', - supportedTypes: ['visualization', 'dashboard', 'index-pattern'], - }); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.ts deleted file mode 100644 index be5a921f91340..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/copy_to_space.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; -import { Legacy } from 'kibana'; -import { - copySavedObjectsToSpacesFactory, - resolveCopySavedObjectsToSpacesConflictsFactory, -} from '../../../lib/copy_to_spaces'; -import { ExternalRouteDeps } from '.'; -import { COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS } from '../../../lib/copy_to_spaces/copy_to_spaces'; -import { SPACE_ID_REGEX } from '../../../lib/space_schema'; - -interface CopyPayload { - spaces: string[]; - objects: Array<{ type: string; id: string }>; - includeReferences: boolean; - overwrite: boolean; -} - -interface ResolveConflictsPayload { - objects: Array<{ type: string; id: string }>; - includeReferences: boolean; - retries: { - [spaceId: string]: Array<{ - type: string; - id: string; - overwrite: boolean; - }>; - }; -} - -export function initCopyToSpacesApi(deps: ExternalRouteDeps) { - const { legacyRouter, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - - legacyRouter({ - method: 'POST', - path: '/api/spaces/_copy_saved_objects', - async handler(request: Legacy.Request, h: Legacy.ResponseToolkit) { - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient( - request, - COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS - ); - - const copySavedObjectsToSpaces = copySavedObjectsToSpacesFactory( - savedObjectsClient, - savedObjects - ); - - const { - spaces: destinationSpaceIds, - objects, - includeReferences, - overwrite, - } = request.payload as CopyPayload; - - const sourceSpaceId = spacesService.getSpaceId(request); - - const copyResponse = await copySavedObjectsToSpaces(sourceSpaceId, destinationSpaceIds, { - objects, - includeReferences, - overwrite, - }); - - return h.response(copyResponse); - }, - options: { - tags: ['access:copySavedObjectsToSpaces'], - validate: { - payload: { - spaces: Joi.array() - .items( - Joi.string().regex(SPACE_ID_REGEX, `lower case, a-z, 0-9, "_", and "-" are allowed`) - ) - .unique(), - objects: Joi.array() - .items(Joi.object({ type: Joi.string(), id: Joi.string() })) - .unique(), - includeReferences: Joi.bool().default(false), - overwrite: Joi.bool().default(false), - }, - }, - pre: [routePreCheckLicenseFn], - }, - }); - - legacyRouter({ - method: 'POST', - path: '/api/spaces/_resolve_copy_saved_objects_errors', - async handler(request: Legacy.Request, h: Legacy.ResponseToolkit) { - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient( - request, - COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS - ); - - const resolveCopySavedObjectsToSpacesConflicts = resolveCopySavedObjectsToSpacesConflictsFactory( - savedObjectsClient, - savedObjects - ); - - const { objects, includeReferences, retries } = request.payload as ResolveConflictsPayload; - - const sourceSpaceId = spacesService.getSpaceId(request); - - const resolveConflictsResponse = await resolveCopySavedObjectsToSpacesConflicts( - sourceSpaceId, - { - objects, - includeReferences, - retries, - } - ); - - return h.response(resolveConflictsResponse); - }, - options: { - tags: ['access:copySavedObjectsToSpaces'], - validate: { - payload: Joi.object({ - objects: Joi.array() - .items(Joi.object({ type: Joi.string(), id: Joi.string() })) - .required() - .unique(), - includeReferences: Joi.bool().default(false), - retries: Joi.object() - .pattern( - SPACE_ID_REGEX, - Joi.array().items( - Joi.object({ - type: Joi.string().required(), - id: Joi.string().required(), - overwrite: Joi.boolean().default(false), - }) - ) - ) - .required(), - }).default(), - }, - pre: [routePreCheckLicenseFn], - }, - }); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.test.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.test.ts deleted file mode 100644 index a1a23604f159a..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -jest.mock('../../../lib/route_pre_check_license', () => { - return { - routePreCheckLicense: () => (request: any, h: any) => h.continue, - }; -}); - -jest.mock('../../../../../../server/lib/get_client_shield', () => { - return { - getClient: () => { - return { - callWithInternalUser: jest.fn(() => { - return; - }), - }; - }, - }; -}); -import Boom from 'boom'; -import { createTestHandler, RequestRunner, TeardownFn } from '../__fixtures__'; -import { initDeleteSpacesApi } from './delete'; - -describe('Spaces Public API', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - - beforeEach(() => { - const setup = createTestHandler(initDeleteSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test(`'DELETE spaces/{id}' deletes the space`, async () => { - const { response } = await request('DELETE', '/api/spaces/space/a-space'); - - const { statusCode } = response; - - expect(statusCode).toEqual(204); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const { response } = await request('DELETE', '/api/spaces/space/a-space', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - }); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(payload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test('DELETE spaces/{id} throws when deleting a non-existent space', async () => { - const { response } = await request('DELETE', '/api/spaces/space/not-a-space'); - - const { statusCode } = response; - - expect(statusCode).toEqual(404); - }); - - test(`'DELETE spaces/{id}' cannot delete reserved spaces`, async () => { - const { response } = await request('DELETE', '/api/spaces/space/default'); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(400); - expect(JSON.parse(payload)).toEqual({ - statusCode: 400, - error: 'Bad Request', - message: 'This Space cannot be deleted because it is reserved.', - }); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.ts deleted file mode 100644 index 720e932743e9a..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/delete.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; -import { wrapError } from '../../../lib/errors'; -import { SpacesClient } from '../../../lib/spaces_client'; -import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; - -export function initDeleteSpacesApi(deps: ExternalRouteDeps) { - const { legacyRouter, savedObjects, spacesService, routePreCheckLicenseFn } = deps; - - legacyRouter({ - method: 'DELETE', - path: '/api/spaces/space/{id}', - async handler(request: ExternalRouteRequestFacade, h: any) { - const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = await spacesService.scopedClient(request); - - const id = request.params.id; - - let result; - - try { - result = await spacesClient.delete(id); - } catch (error) { - if (SavedObjectsClient.errors.isNotFoundError(error)) { - return Boom.notFound(); - } - return wrapError(error); - } - - return h.response(result).code(204); - }, - options: { - pre: [routePreCheckLicenseFn], - }, - }); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/get.test.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/get.test.ts deleted file mode 100644 index 5357c38e0e9ae..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/get.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -jest.mock('../../../lib/route_pre_check_license', () => { - return { - routePreCheckLicense: () => (request: any, h: any) => h.continue, - }; -}); - -jest.mock('../../../../../../server/lib/get_client_shield', () => { - return { - getClient: () => { - return { - callWithInternalUser: jest.fn(() => { - return; - }), - }; - }, - }; -}); -import Boom from 'boom'; -import { Space } from '../../../../common/model/space'; -import { createSpaces, createTestHandler, RequestRunner, TeardownFn } from '../__fixtures__'; -import { initGetSpacesApi } from './get'; - -describe('GET spaces', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - const spaces = createSpaces(); - - beforeEach(() => { - const setup = createTestHandler(initGetSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test(`'GET spaces' returns all available spaces`, async () => { - const { response } = await request('GET', '/api/spaces/space'); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(200); - const resultSpaces: Space[] = JSON.parse(payload); - expect(resultSpaces.map(s => s.id)).toEqual(spaces.map(s => s.id)); - }); - - test(`'GET spaces' returns all available spaces with the 'any' purpose`, async () => { - const { response } = await request('GET', '/api/spaces/space?purpose=any'); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(200); - const resultSpaces: Space[] = JSON.parse(payload); - expect(resultSpaces.map(s => s.id)).toEqual(spaces.map(s => s.id)); - }); - - test(`'GET spaces' returns all available spaces with the 'copySavedObjectsIntoSpace' purpose`, async () => { - const { response } = await request( - 'GET', - '/api/spaces/space?purpose=copySavedObjectsIntoSpace' - ); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(200); - const resultSpaces: Space[] = JSON.parse(payload); - expect(resultSpaces.map(s => s.id)).toEqual(spaces.map(s => s.id)); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const { response } = await request('GET', '/api/spaces/space', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - }); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(payload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test(`'GET spaces/{id}' returns the space with that id`, async () => { - const { response } = await request('GET', '/api/spaces/space/default'); - - const { statusCode, payload } = response; - - expect(statusCode).toEqual(200); - const resultSpace = JSON.parse(payload); - expect(resultSpace.id).toEqual('default'); - }); - - test(`'GET spaces/{id}' returns 404 when retrieving a non-existent space`, async () => { - const { response } = await request('GET', '/api/spaces/space/not-a-space'); - - const { statusCode } = response; - - expect(statusCode).toEqual(404); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/get.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/get.ts deleted file mode 100644 index 310cef5c1069e..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/get.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; -import Joi from 'joi'; -import { RequestQuery } from 'hapi'; -import { GetSpacePurpose } from '../../../../common/model/types'; -import { Space } from '../../../../common/model/space'; -import { wrapError } from '../../../lib/errors'; -import { SpacesClient } from '../../../lib/spaces_client'; -import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; - -export function initGetSpacesApi(deps: ExternalRouteDeps) { - const { legacyRouter, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - - legacyRouter({ - method: 'GET', - path: '/api/spaces/space', - async handler(request: ExternalRouteRequestFacade) { - log.debug(`Inside GET /api/spaces/space`); - - const purpose: GetSpacePurpose = (request.query as RequestQuery).purpose as GetSpacePurpose; - - const spacesClient: SpacesClient = await spacesService.scopedClient(request); - - let spaces: Space[]; - - try { - log.debug(`Attempting to retrieve all spaces for ${purpose} purpose`); - spaces = await spacesClient.getAll(purpose); - log.debug(`Retrieved ${spaces.length} spaces for ${purpose} purpose`); - } catch (error) { - log.debug(`Error retrieving spaces for ${purpose} purpose: ${error}`); - return wrapError(error); - } - - return spaces; - }, - options: { - pre: [routePreCheckLicenseFn], - validate: { - query: Joi.object().keys({ - purpose: Joi.string() - .valid('any', 'copySavedObjectsIntoSpace') - .default('any'), - }), - }, - }, - }); - - legacyRouter({ - method: 'GET', - path: '/api/spaces/space/{id}', - async handler(request: ExternalRouteRequestFacade) { - const spaceId = request.params.id; - - const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = await spacesService.scopedClient(request); - - try { - return await spacesClient.get(spaceId); - } catch (error) { - if (SavedObjectsClient.errors.isNotFoundError(error)) { - return Boom.notFound(); - } - return wrapError(error); - } - }, - options: { - pre: [routePreCheckLicenseFn], - }, - }); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/index.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/index.ts deleted file mode 100644 index 7828a6b59d566..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Legacy } from 'kibana'; -import { Logger, SavedObjectsLegacyService } from 'src/core/server'; -import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; -import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; -import { initDeleteSpacesApi } from './delete'; -import { initGetSpacesApi } from './get'; -import { initPostSpacesApi } from './post'; -import { initPutSpacesApi } from './put'; -import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; -import { initCopyToSpacesApi } from './copy_to_space'; - -type Omit = Pick>; - -interface RouteDeps { - xpackMain: XPackMainPlugin; - legacyRouter: Legacy.Server['route']; - savedObjects: SavedObjectsLegacyService; - spacesService: SpacesServiceSetup; - log: Logger; -} - -export interface ExternalRouteDeps extends Omit { - routePreCheckLicenseFn: any; -} - -export type ExternalRouteRequestFacade = Legacy.Request; - -export function initExternalSpacesApi({ xpackMain, ...rest }: RouteDeps) { - const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); - - const deps: ExternalRouteDeps = { - ...rest, - routePreCheckLicenseFn, - }; - - initDeleteSpacesApi(deps); - initGetSpacesApi(deps); - initPostSpacesApi(deps); - initPutSpacesApi(deps); - initCopyToSpacesApi(deps); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/post.test.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/post.test.ts deleted file mode 100644 index c53aaf29636a4..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/post.test.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -jest.mock('../../../lib/route_pre_check_license', () => { - return { - routePreCheckLicense: () => (request: any, h: any) => h.continue, - }; -}); - -jest.mock('../../../../../../server/lib/get_client_shield', () => { - return { - getClient: () => { - return { - callWithInternalUser: jest.fn(() => { - return; - }), - }; - }, - }; -}); - -import Boom from 'boom'; -import { createTestHandler, RequestRunner, TeardownFn } from '../__fixtures__'; -import { initPostSpacesApi } from './post'; - -describe('Spaces Public API', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - - beforeEach(() => { - const setup = createTestHandler(initPostSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test('POST /space should create a new space with the provided ID', async () => { - const payload = { - id: 'my-space-id', - name: 'my new space', - description: 'with a description', - disabledFeatures: ['foo'], - }; - - const { mockSavedObjectsRepository, response } = await request('POST', '/api/spaces/space', { - payload, - }); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsRepository.create).toHaveBeenCalledTimes(1); - expect(mockSavedObjectsRepository.create).toHaveBeenCalledWith( - 'space', - { name: 'my new space', description: 'with a description', disabledFeatures: ['foo'] }, - { id: 'my-space-id' } - ); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const payload = { - id: 'my-space-id', - name: 'my new space', - description: 'with a description', - }; - - const { response } = await request('POST', '/api/spaces/space', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(responsePayload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test('POST /space should not allow a space to be updated', async () => { - const payload = { - id: 'a-space', - name: 'my updated space', - description: 'with a description', - }; - - const { response } = await request('POST', '/api/spaces/space', { payload }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(409); - expect(JSON.parse(responsePayload)).toEqual({ - error: 'Conflict', - message: 'A space with the identifier a-space already exists.', - statusCode: 409, - }); - }); - - test('POST /space should not require disabledFeatures to be specified', async () => { - const payload = { - id: 'my-space-id', - name: 'my new space', - description: 'with a description', - }; - - const { mockSavedObjectsRepository, response } = await request('POST', '/api/spaces/space', { - payload, - }); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsRepository.create).toHaveBeenCalledTimes(1); - expect(mockSavedObjectsRepository.create).toHaveBeenCalledWith( - 'space', - { name: 'my new space', description: 'with a description', disabledFeatures: [] }, - { id: 'my-space-id' } - ); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/post.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/post.ts deleted file mode 100644 index 6a17b5c5eace6..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/post.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; -import { Space } from '../../../../common/model/space'; -import { wrapError } from '../../../lib/errors'; -import { spaceSchema } from '../../../lib/space_schema'; -import { SpacesClient } from '../../../lib/spaces_client'; -import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; - -export function initPostSpacesApi(deps: ExternalRouteDeps) { - const { legacyRouter, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - - legacyRouter({ - method: 'POST', - path: '/api/spaces/space', - async handler(request: ExternalRouteRequestFacade) { - log.debug(`Inside POST /api/spaces/space`); - const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = await spacesService.scopedClient(request); - - const space = request.payload as Space; - - try { - log.debug(`Attempting to create space`); - return await spacesClient.create(space); - } catch (error) { - if (SavedObjectsClient.errors.isConflictError(error)) { - return Boom.conflict(`A space with the identifier ${space.id} already exists.`); - } - log.debug(`Error creating space: ${error}`); - return wrapError(error); - } - }, - options: { - validate: { - payload: spaceSchema, - }, - pre: [routePreCheckLicenseFn], - }, - }); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/put.test.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/put.test.ts deleted file mode 100644 index d2ac1f89e1df9..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/put.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -jest.mock('../../../lib/route_pre_check_license', () => { - return { - routePreCheckLicense: () => (request: any, h: any) => h.continue, - }; -}); - -jest.mock('../../../../../../server/lib/get_client_shield', () => { - return { - getClient: () => { - return { - callWithInternalUser: jest.fn(() => { - return; - }), - }; - }, - }; -}); -import Boom from 'boom'; -import { createTestHandler, RequestRunner, TeardownFn } from '../__fixtures__'; -import { initPutSpacesApi } from './put'; - -describe('Spaces Public API', () => { - let request: RequestRunner; - let teardowns: TeardownFn[]; - - beforeEach(() => { - const setup = createTestHandler(initPutSpacesApi); - - request = setup.request; - teardowns = setup.teardowns; - }); - - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); - - test('PUT /space should update an existing space with the provided ID', async () => { - const payload = { - id: 'a-space', - name: 'my updated space', - description: 'with a description', - disabledFeatures: [], - }; - - const { mockSavedObjectsRepository, response } = await request( - 'PUT', - '/api/spaces/space/a-space', - { - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledTimes(1); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledWith('space', 'a-space', { - name: 'my updated space', - description: 'with a description', - disabledFeatures: [], - }); - }); - - test('PUT /space should allow an empty description', async () => { - const payload = { - id: 'a-space', - name: 'my updated space', - description: '', - disabledFeatures: ['foo'], - }; - - const { mockSavedObjectsRepository, response } = await request( - 'PUT', - '/api/spaces/space/a-space', - { - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledTimes(1); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledWith('space', 'a-space', { - name: 'my updated space', - description: '', - disabledFeatures: ['foo'], - }); - }); - - test('PUT /space should not require disabledFeatures', async () => { - const payload = { - id: 'a-space', - name: 'my updated space', - description: '', - }; - - const { mockSavedObjectsRepository, response } = await request( - 'PUT', - '/api/spaces/space/a-space', - { - payload, - } - ); - - const { statusCode } = response; - - expect(statusCode).toEqual(200); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledTimes(1); - expect(mockSavedObjectsRepository.update).toHaveBeenCalledWith('space', 'a-space', { - name: 'my updated space', - description: '', - disabledFeatures: [], - }); - }); - - test(`returns result of routePreCheckLicense`, async () => { - const payload = { - id: 'a-space', - name: 'my updated space', - description: 'with a description', - }; - - const { response } = await request('PUT', '/api/spaces/space/a-space', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - expectSpacesClientCall: false, - payload, - }); - - const { statusCode, payload: responsePayload } = response; - - expect(statusCode).toEqual(403); - expect(JSON.parse(responsePayload)).toMatchObject({ - message: 'test forbidden message', - }); - }); - - test('PUT /space should not allow a new space to be created', async () => { - const payload = { - id: 'a-new-space', - name: 'my new space', - description: 'with a description', - }; - - const { response } = await request('PUT', '/api/spaces/space/a-new-space', { payload }); - - const { statusCode } = response; - - expect(statusCode).toEqual(404); - }); -}); diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/external/put.ts b/x-pack/legacy/plugins/spaces/server/routes/api/external/put.ts deleted file mode 100644 index 8e0f7673358d0..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/api/external/put.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Boom from 'boom'; -import { Space } from '../../../../common/model/space'; -import { wrapError } from '../../../lib/errors'; -import { spaceSchema } from '../../../lib/space_schema'; -import { SpacesClient } from '../../../lib/spaces_client'; -import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; - -export function initPutSpacesApi(deps: ExternalRouteDeps) { - const { legacyRouter, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - - legacyRouter({ - method: 'PUT', - path: '/api/spaces/space/{id}', - async handler(request: ExternalRouteRequestFacade) { - const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = await spacesService.scopedClient(request); - - const space: Space = request.payload as Space; - const id = request.params.id; - - let result: Space; - try { - result = await spacesClient.update(id, { ...space }); - } catch (error) { - if (SavedObjectsClient.errors.isNotFoundError(error)) { - return Boom.notFound(); - } - return wrapError(error); - } - - return result; - }, - options: { - validate: { - payload: spaceSchema, - }, - pre: [routePreCheckLicenseFn], - }, - }); -} diff --git a/x-pack/legacy/plugins/spaces/server/routes/lib/get_space_by_id.ts b/x-pack/legacy/plugins/spaces/server/routes/lib/get_space_by_id.ts deleted file mode 100644 index eaa789b32c39b..0000000000000 --- a/x-pack/legacy/plugins/spaces/server/routes/lib/get_space_by_id.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { Space } from '../../../common/model/space'; -import { SpacesClient } from '../../lib/spaces_client'; -import { convertSavedObjectToSpace } from './convert_saved_object_to_space'; - -export async function getSpaceById( - client: SpacesClient, - spaceId: string, - errors: any -): Promise { - try { - const existingSpace = await client.get(spaceId); - return convertSavedObjectToSpace(existingSpace); - } catch (error) { - if (errors.isNotFoundError(error)) { - return null; - } - throw error; - } -} diff --git a/x-pack/legacy/plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap b/x-pack/legacy/plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap index 5bc88f425118b..68a1b92666ea9 100644 --- a/x-pack/legacy/plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap +++ b/x-pack/legacy/plugins/telemetry/public/components/__snapshots__/telemetry_form.test.js.snap @@ -38,31 +38,27 @@ exports[`TelemetryForm renders as expected 1`] = ` Help us improve the Elastic Stack by providing usage statistics for basic features. We will not share this data outside of Elastic.

- - +

- - +

, "type": "boolean", diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap index 79fc12a17c929..86d33dfccb0b9 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap @@ -13,6 +13,7 @@ exports[`Transform: Aggregation Minimal initialization 1`] = ` display="row" error={false} fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} helpText="" isInvalid={false} @@ -32,6 +33,7 @@ exports[`Transform: Aggregation Minimal initialization 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={true} labelType="label" > diff --git a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap index 927317524803f..01114e3b9cfa3 100644 --- a/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap +++ b/x-pack/legacy/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap @@ -13,6 +13,7 @@ exports[`Transform: Group By Minimal initialization 1`] = ` display="row" error={false} fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} helpText="" isInvalid={false} @@ -33,6 +34,7 @@ exports[`Transform: Group By Minimal initialization 1`] = ` display="row" error={false} fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={false} isInvalid={false} label="Interval" @@ -83,6 +85,7 @@ exports[`Transform: Group By Minimal initialization 1`] = ` describedByIds={Array []} display="row" fullWidth={false} + hasChildLabel={true} hasEmptyLabelSpace={true} labelType="label" > diff --git a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap index 6f92d475ae6c5..4c500b02a0936 100644 --- a/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap +++ b/x-pack/legacy/plugins/upgrade_assistant/public/components/tabs/checkup/__snapshots__/checkup_tab.test.tsx.snap @@ -39,18 +39,16 @@ exports[`CheckupTab render with deprecations 1`] = ` id="xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.calloutDetail" values={ Object { - "snapshotRestoreDocsButton": - , + , } } /> @@ -325,18 +323,16 @@ exports[`CheckupTab render with error 1`] = ` id="xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.calloutDetail" values={ Object { - "snapshotRestoreDocsButton": - , + , } } /> @@ -394,18 +390,16 @@ exports[`CheckupTab render without deprecations 1`] = ` id="xpack.upgradeAssistant.checkupTab.backUpCallout.calloutBody.calloutDetail" values={ Object { - "snapshotRestoreDocsButton": - , + , } } /> @@ -440,17 +434,15 @@ exports[`CheckupTab render without deprecations 1`] = ` id="xpack.upgradeAssistant.checkupTab.noIssues.nextStepsDetail" values={ Object { - "overviewTabButton": - , + , } } /> diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/integration_link.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/integration_link.test.tsx.snap index 2927e867dec1f..502af2eb91051 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/integration_link.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/__tests__/__snapshots__/integration_link.test.tsx.snap @@ -30,9 +30,7 @@ exports[`IntegrationLink component renders a disabled link when href is undefine exports[`IntegrationLink component renders without errors 1`] = ` - , + , } } /> diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap index 4783806340f07..393ab7f1b45e2 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap @@ -152,18 +152,16 @@ exports[`EmptyState component does not render empty state with appropriate base id="xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage" values={ Object { - "configureHeartbeatLink": - , + , } } /> @@ -246,26 +244,22 @@ exports[`EmptyState component does not render empty state with appropriate base id="xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage" values={ Object { - "configureHeartbeatLink": - , + , } } >
- , + , } } /> @@ -716,26 +708,22 @@ exports[`EmptyState component notifies when index does not exist 1`] = ` id="xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage" values={ Object { - "configureHeartbeatLink": - , + , } } > Add location   diff --git a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/__tests__/__snapshots__/kibana_global_help.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/__tests__/__snapshots__/kibana_global_help.test.tsx.snap index 9ae847cfc7fb9..b3f749b12d9d1 100644 --- a/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/__tests__/__snapshots__/kibana_global_help.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/lib/adapters/framework/__tests__/__snapshots__/kibana_global_help.test.tsx.snap @@ -27,12 +27,10 @@ exports[`renderUptimeKibanaGlobalHelp renders links with expected urls 1`] = ` /> - - + `; diff --git a/x-pack/package.json b/x-pack/package.json index b0fabd89d20c7..de996ae30bb9a 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -195,7 +195,7 @@ "@elastic/datemath": "5.0.2", "@elastic/ems-client": "1.0.2", "@elastic/filesaver": "1.1.2", - "@elastic/eui": "14.4.0", + "@elastic/eui": "14.5.0", "@elastic/javascript-typescript-langserver": "^0.3.3", "@elastic/lsp-extension": "^0.1.2", "@elastic/maki": "6.1.0", diff --git a/x-pack/plugins/spaces/common/constants.ts b/x-pack/plugins/spaces/common/constants.ts new file mode 100644 index 0000000000000..11882ca2f1b3a --- /dev/null +++ b/x-pack/plugins/spaces/common/constants.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const DEFAULT_SPACE_ID = `default`; + +/** + * The minimum number of spaces required to show a search control. + */ +export const SPACE_SEARCH_COUNT_THRESHOLD = 8; + +/** + * The maximum number of characters allowed in the Space Avatar's initials + */ +export const MAX_SPACE_INITIALS = 2; + +/** + * The type name used within the Monitoring index to publish spaces stats. + * @type {string} + */ +export const KIBANA_SPACES_STATS_TYPE = 'spaces'; + +/** + * The path to enter a space. + */ +export const ENTER_SPACE_PATH = '/spaces/enter'; diff --git a/x-pack/plugins/spaces/common/index.ts b/x-pack/plugins/spaces/common/index.ts new file mode 100644 index 0000000000000..65baa1bd99102 --- /dev/null +++ b/x-pack/plugins/spaces/common/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { isReservedSpace } from './is_reserved_space'; +export { MAX_SPACE_INITIALS } from './constants'; +export { addSpaceIdToPath, getSpaceIdFromPath } from './lib/spaces_url_parser'; diff --git a/x-pack/plugins/spaces/common/is_reserved_space.test.ts b/x-pack/plugins/spaces/common/is_reserved_space.test.ts new file mode 100644 index 0000000000000..dd1372183ed8a --- /dev/null +++ b/x-pack/plugins/spaces/common/is_reserved_space.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isReservedSpace } from './is_reserved_space'; +import { Space } from './model/space'; + +test('it returns true for reserved spaces', () => { + const space: Space = { + id: '', + name: '', + disabledFeatures: [], + _reserved: true, + }; + + expect(isReservedSpace(space)).toEqual(true); +}); + +test('it returns false for non-reserved spaces', () => { + const space: Space = { + id: '', + name: '', + disabledFeatures: [], + }; + + expect(isReservedSpace(space)).toEqual(false); +}); + +test('it handles empty input', () => { + // @ts-ignore + expect(isReservedSpace()).toEqual(false); +}); diff --git a/x-pack/plugins/spaces/common/is_reserved_space.ts b/x-pack/plugins/spaces/common/is_reserved_space.ts new file mode 100644 index 0000000000000..788ef80c194ce --- /dev/null +++ b/x-pack/plugins/spaces/common/is_reserved_space.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get } from 'lodash'; +import { Space } from './model/space'; + +/** + * Returns whether the given Space is reserved or not. + * + * @param space the space + * @returns boolean + */ +export function isReservedSpace(space?: Partial | null): boolean { + return get(space, '_reserved', false); +} diff --git a/x-pack/legacy/plugins/spaces/common/lib/__snapshots__/spaces_url_parser.test.ts.snap b/x-pack/plugins/spaces/common/lib/__snapshots__/spaces_url_parser.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/spaces/common/lib/__snapshots__/spaces_url_parser.test.ts.snap rename to x-pack/plugins/spaces/common/lib/__snapshots__/spaces_url_parser.test.ts.snap diff --git a/x-pack/legacy/plugins/spaces/common/lib/spaces_url_parser.test.ts b/x-pack/plugins/spaces/common/lib/spaces_url_parser.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/common/lib/spaces_url_parser.test.ts rename to x-pack/plugins/spaces/common/lib/spaces_url_parser.test.ts diff --git a/x-pack/legacy/plugins/spaces/common/lib/spaces_url_parser.ts b/x-pack/plugins/spaces/common/lib/spaces_url_parser.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/common/lib/spaces_url_parser.ts rename to x-pack/plugins/spaces/common/lib/spaces_url_parser.ts diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/index.ts b/x-pack/plugins/spaces/common/model/space.ts similarity index 54% rename from x-pack/legacy/plugins/spaces/server/new_platform/index.ts rename to x-pack/plugins/spaces/common/model/space.ts index edf27e2dd819b..c44ce41ec51c0 100644 --- a/x-pack/legacy/plugins/spaces/server/new_platform/index.ts +++ b/x-pack/plugins/spaces/common/model/space.ts @@ -4,9 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from 'src/core/server'; -import { Plugin } from './plugin'; - -export function plugin(initializerContext: PluginInitializerContext) { - return new Plugin(initializerContext); +export interface Space { + id: string; + name: string; + description?: string; + color?: string; + initials?: string; + disabledFeatures: string[]; + _reserved?: boolean; + imageUrl?: string; } diff --git a/x-pack/plugins/spaces/common/model/types.ts b/x-pack/plugins/spaces/common/model/types.ts new file mode 100644 index 0000000000000..58c36da33dbd7 --- /dev/null +++ b/x-pack/plugins/spaces/common/model/types.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export type GetSpacePurpose = 'any' | 'copySavedObjectsIntoSpace'; diff --git a/x-pack/plugins/spaces/kibana.json b/x-pack/plugins/spaces/kibana.json new file mode 100644 index 0000000000000..15d900bf99e14 --- /dev/null +++ b/x-pack/plugins/spaces/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "spaces", + "version": "8.0.0", + "kibanaVersion": "kibana", + "configPath": ["xpack", "spaces"], + "requiredPlugins": ["features", "licensing"], + "server": true, + "ui": false +} diff --git a/x-pack/plugins/spaces/server/config.ts b/x-pack/plugins/spaces/server/config.ts new file mode 100644 index 0000000000000..a28624fb82c15 --- /dev/null +++ b/x-pack/plugins/spaces/server/config.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext } from 'src/core/server'; +import { Observable } from 'rxjs'; + +export const ConfigSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), + maxSpaces: schema.number({ defaultValue: 1000 }), +}); + +export function createConfig$(context: PluginInitializerContext) { + return context.config.create>(); +} + +export type ConfigType = ReturnType extends Observable + ? P + : ReturnType; diff --git a/x-pack/plugins/spaces/server/index.ts b/x-pack/plugins/spaces/server/index.ts new file mode 100644 index 0000000000000..21d6c840fb017 --- /dev/null +++ b/x-pack/plugins/spaces/server/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext } from '../../../../src/core/server'; +import { ConfigSchema } from './config'; +import { Plugin } from './plugin'; + +// These exports are part of public Spaces plugin contract, any change in signature of exported +// functions or removal of exports should be considered as a breaking change. Ideally we should +// reduce number of such exports to zero and provide everything we want to expose via Setup/Start +// run-time contracts. + +// end public contract exports + +export { SpacesPluginSetup } from './plugin'; + +export const config = { schema: ConfigSchema }; +export const plugin = (initializerContext: PluginInitializerContext) => + new Plugin(initializerContext); diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_modal/index.ts b/x-pack/plugins/spaces/server/lib/__fixtures__/index.ts similarity index 78% rename from x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_modal/index.ts rename to x-pack/plugins/spaces/server/lib/__fixtures__/index.ts index 3713dd161143a..3ac2b4594049f 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/components/create_analytics_modal/index.ts +++ b/x-pack/plugins/spaces/server/lib/__fixtures__/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { CreateAnalyticsModal } from './create_analytics_modal'; +export { spacesConfig } from './spaces_config'; diff --git a/x-pack/plugins/spaces/server/lib/__fixtures__/spaces_config.ts b/x-pack/plugins/spaces/server/lib/__fixtures__/spaces_config.ts new file mode 100644 index 0000000000000..1697b9d59af8a --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/__fixtures__/spaces_config.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ConfigSchema } from '../../config'; + +export const spacesConfig = ConfigSchema.validate({}); diff --git a/x-pack/legacy/plugins/spaces/server/lib/__snapshots__/create_default_space.test.ts.snap b/x-pack/plugins/spaces/server/lib/__snapshots__/create_default_space.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/__snapshots__/create_default_space.test.ts.snap rename to x-pack/plugins/spaces/server/lib/__snapshots__/create_default_space.test.ts.snap diff --git a/x-pack/legacy/plugins/spaces/server/lib/audit_logger.test.ts b/x-pack/plugins/spaces/server/lib/audit_logger.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/audit_logger.test.ts rename to x-pack/plugins/spaces/server/lib/audit_logger.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/audit_logger.ts b/x-pack/plugins/spaces/server/lib/audit_logger.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/audit_logger.ts rename to x-pack/plugins/spaces/server/lib/audit_logger.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/index.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/index.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/index.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/index.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/create_empty_failure_response.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/create_empty_failure_response.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/create_empty_failure_response.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/create_empty_failure_response.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/get_eligible_types.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/get_eligible_types.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/get_eligible_types.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/get_eligible_types.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/read_stream_to_completion.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/read_stream_to_completion.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/read_stream_to_completion.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/read_stream_to_completion.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/readable_stream_from_array.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/readable_stream_from_array.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/lib/readable_stream_from_array.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/lib/readable_stream_from_array.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/resolve_copy_conflicts.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/types.ts b/x-pack/plugins/spaces/server/lib/copy_to_spaces/types.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/types.ts rename to x-pack/plugins/spaces/server/lib/copy_to_spaces/types.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts similarity index 86% rename from x-pack/legacy/plugins/spaces/server/lib/create_default_space.test.ts rename to x-pack/plugins/spaces/server/lib/create_default_space.test.ts index cd0ecdea97fb2..8486508c45364 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -3,23 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../../server/lib/get_client_shield', () => ({ - getClient: jest.fn(), -})); -import * as Rx from 'rxjs'; + import Boom from 'boom'; -import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; -import { SavedObjectsLegacyService } from 'src/core/server'; -import { ElasticsearchServiceSetup } from 'src/core/server'; - -let mockCallWithRequest; -beforeEach(() => { - mockCallWithRequest = jest.fn(); - (getClient as jest.Mock).mockReturnValue({ - callWithRequest: mockCallWithRequest, - }); -}); +import { SavedObjectsLegacyService, IClusterClient } from 'src/core/server'; + interface MockServerSettings { defaultExists?: boolean; simulateGetErrorCondition?: boolean; @@ -84,11 +72,9 @@ const createMockDeps = (settings: MockServerSettings = {}) => { return { config: mockServer.config(), savedObjects: (mockServer.savedObjects as unknown) as SavedObjectsLegacyService, - elasticsearch: ({ - dataClient$: Rx.of({ - callAsInternalUser: jest.fn(), - }), - } as unknown) as ElasticsearchServiceSetup, + esClient: ({ + callAsInternalUser: jest.fn(), + } as unknown) as jest.Mocked, }; }; diff --git a/x-pack/legacy/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts similarity index 80% rename from x-pack/legacy/plugins/spaces/server/lib/create_default_space.ts rename to x-pack/plugins/spaces/server/lib/create_default_space.ts index 9e574c19c987f..2301fa26dab28 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -5,22 +5,18 @@ */ import { i18n } from '@kbn/i18n'; - -import { first } from 'rxjs/operators'; -import { SavedObjectsLegacyService, CoreSetup } from 'src/core/server'; +import { SavedObjectsLegacyService, IClusterClient } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { - elasticsearch: CoreSetup['elasticsearch']; + esClient: Pick; savedObjects: SavedObjectsLegacyService; } -export async function createDefaultSpace({ elasticsearch, savedObjects }: Deps) { +export async function createDefaultSpace({ esClient, savedObjects }: Deps) { const { getSavedObjectsRepository, SavedObjectsClient } = savedObjects; - const client = await elasticsearch.dataClient$.pipe(first()).toPromise(); - - const savedObjectsRepository = getSavedObjectsRepository(client.callAsInternalUser, ['space']); + const savedObjectsRepository = getSavedObjectsRepository(esClient.callAsInternalUser, ['space']); const defaultSpaceExists = await doesDefaultSpaceExist( SavedObjectsClient, diff --git a/x-pack/plugins/spaces/server/lib/errors.ts b/x-pack/plugins/spaces/server/lib/errors.ts new file mode 100644 index 0000000000000..d800020038a38 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/errors.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { boomify, isBoom } from 'boom'; +import { ResponseError, CustomHttpResponseOptions } from 'src/core/server'; + +export function wrapError(error: any): CustomHttpResponseOptions { + const boom = isBoom(error) ? error : boomify(error); + return { + body: boom, + headers: boom.output.headers, + statusCode: boom.output.statusCode, + }; +} diff --git a/x-pack/legacy/plugins/spaces/server/lib/get_space_selector_url.test.ts b/x-pack/plugins/spaces/server/lib/get_space_selector_url.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/get_space_selector_url.test.ts rename to x-pack/plugins/spaces/server/lib/get_space_selector_url.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/get_space_selector_url.ts b/x-pack/plugins/spaces/server/lib/get_space_selector_url.ts similarity index 81% rename from x-pack/legacy/plugins/spaces/server/lib/get_space_selector_url.ts rename to x-pack/plugins/spaces/server/lib/get_space_selector_url.ts index 6d088fda757de..8cc641bc2e7cf 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/get_space_selector_url.ts +++ b/x-pack/plugins/spaces/server/lib/get_space_selector_url.ts @@ -4,6 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export function getSpaceSelectorUrl(serverBasePath: string = '') { +export function getSpaceSelectorUrl(serverBasePath: string) { return `${serverBasePath}/spaces/space_selector`; } diff --git a/x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts similarity index 62% rename from x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts rename to x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts index 6609ca42a7f67..912cccbc01782 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts @@ -5,12 +5,24 @@ */ import { getSpacesUsageCollector, UsageStats } from './get_spaces_usage_collector'; +import * as Rx from 'rxjs'; +import { PluginsSetup } from '../plugin'; +import { Feature } from '../../../features/server'; +import { ILicense, LicensingPluginSetup } from '../../../licensing/server'; + +interface SetupOpts { + license?: Partial; + features?: Feature[]; +} -function getServerMock(customization?: any) { +function setup({ + license = { isAvailable: true }, + features = [{ id: 'feature1' } as Feature, { id: 'feature2' } as Feature], +}: SetupOpts = {}) { class MockUsageCollector { private fetch: any; - constructor(server: any, { fetch }: any) { + constructor({ fetch }: any) { this.fetch = fetch; } // to make typescript happy @@ -19,39 +31,23 @@ function getServerMock(customization?: any) { } } - const getLicenseCheckResults = jest.fn().mockReturnValue({}); - const defaultServerMock = { - plugins: { - xpack_main: { - info: { - isAvailable: jest.fn().mockReturnValue(true), - feature: () => ({ - getLicenseCheckResults, - }), - license: { - isOneOf: jest.fn().mockReturnValue(false), - getType: jest.fn().mockReturnValue('platinum'), - }, - toJSON: () => ({ b: 1 }), - }, - getFeatures: jest.fn().mockReturnValue([{ id: 'feature1' }, { id: 'feature2' }]), - }, - }, - expose: () => { - return; - }, - log: () => { - return; - }, + const licensing = { + license$: Rx.of(license), + } as LicensingPluginSetup; + + const featuresSetup = ({ + getFeatures: jest.fn().mockReturnValue(features), + } as unknown) as PluginsSetup['features']; + + return { + licensing, + features: featuresSetup, usage: { collectorSet: { - makeUsageCollector: (options: any) => { - return new MockUsageCollector(defaultServerMock, options); - }, + makeUsageCollector: (options: any) => new MockUsageCollector(options), }, }, }; - return Object.assign(defaultServerMock, customization); } const defaultCallClusterMock = jest.fn().mockResolvedValue({ @@ -73,17 +69,14 @@ const defaultCallClusterMock = jest.fn().mockResolvedValue({ }); describe('with a basic license', () => { - let serverWithBasicLicenseMock: any; let usageStats: UsageStats; beforeAll(async () => { - serverWithBasicLicenseMock = getServerMock(); - serverWithBasicLicenseMock.plugins.xpack_main.info.license.getType = jest - .fn() - .mockReturnValue('basic'); + const { features, licensing, usage } = setup({ license: { isAvailable: true, type: 'basic' } }); const { fetch: getSpacesUsage } = getSpacesUsageCollector({ kibanaIndex: '.kibana', - usage: serverWithBasicLicenseMock.usage, - xpackMain: serverWithBasicLicenseMock.plugins.xpack_main, + usage, + features, + licensing, }); usageStats = await getSpacesUsage(defaultCallClusterMock); }); @@ -113,13 +106,12 @@ describe('with a basic license', () => { describe('with no license', () => { let usageStats: UsageStats; beforeAll(async () => { - const serverWithNoLicenseMock = getServerMock(); - serverWithNoLicenseMock.plugins.xpack_main.info.isAvailable = jest.fn().mockReturnValue(false); - + const { features, licensing, usage } = setup({ license: { isAvailable: false } }); const { fetch: getSpacesUsage } = getSpacesUsageCollector({ kibanaIndex: '.kibana', - usage: serverWithNoLicenseMock.usage, - xpackMain: serverWithNoLicenseMock.plugins.xpack_main, + usage, + features, + licensing, }); usageStats = await getSpacesUsage(defaultCallClusterMock); }); @@ -142,17 +134,16 @@ describe('with no license', () => { }); describe('with platinum license', () => { - let serverWithPlatinumLicenseMock: any; let usageStats: UsageStats; beforeAll(async () => { - serverWithPlatinumLicenseMock = getServerMock(); - serverWithPlatinumLicenseMock.plugins.xpack_main.info.license.getType = jest - .fn() - .mockReturnValue('platinum'); + const { features, licensing, usage } = setup({ + license: { isAvailable: true, type: 'platinum' }, + }); const { fetch: getSpacesUsage } = getSpacesUsageCollector({ kibanaIndex: '.kibana', - usage: serverWithPlatinumLicenseMock.usage, - xpackMain: serverWithPlatinumLicenseMock.plugins.xpack_main, + usage, + features, + licensing, }); usageStats = await getSpacesUsage(defaultCallClusterMock); }); diff --git a/x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts similarity index 83% rename from x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.ts rename to x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts index 623f613faaa0c..bfbc5e6ab775d 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/get_spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts @@ -6,10 +6,11 @@ import { get } from 'lodash'; import { CallAPIOptions } from 'src/core/server'; -import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; +import { take } from 'rxjs/operators'; // @ts-ignore -import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; +import { KIBANA_STATS_TYPE_MONITORING } from '../../../../legacy/plugins/monitoring/common/constants'; import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; +import { PluginsSetup } from '../plugin'; type CallCluster = ( endpoint: string, @@ -30,22 +31,23 @@ interface SpacesAggregationResponse { /** * - * @param callCluster - * @param server + * @param {CallCluster} callCluster + * @param {string} kibanaIndex + * @param {PluginsSetup['features']} features * @param {boolean} spacesAvailable * @return {UsageStats} */ async function getSpacesUsage( callCluster: CallCluster, kibanaIndex: string, - xpackMainPlugin: XPackMainPlugin, + features: PluginsSetup['features'], spacesAvailable: boolean ) { if (!spacesAvailable) { return {} as UsageStats; } - const knownFeatureIds = xpackMainPlugin.getFeatures().map(feature => feature.id); + const knownFeatureIds = features.getFeatures().map(feature => feature.id); const resp = await callCluster('search', { index: kibanaIndex, @@ -115,7 +117,8 @@ export interface UsageStats { interface CollectorDeps { kibanaIndex: string; usage: { collectorSet: any }; - xpackMain: XPackMainPlugin; + features: PluginsSetup['features']; + licensing: PluginsSetup['licensing']; } /* @@ -128,13 +131,13 @@ export function getSpacesUsageCollector(deps: CollectorDeps) { type: KIBANA_SPACES_STATS_TYPE, isReady: () => true, fetch: async (callCluster: CallCluster) => { - const xpackInfo = deps.xpackMain.info; - const available = xpackInfo && xpackInfo.isAvailable(); // some form of spaces is available for all valid licenses + const license = await deps.licensing.license$.pipe(take(1)).toPromise(); + const available = license.isAvailable; // some form of spaces is available for all valid licenses const usageStats = await getSpacesUsage( callCluster, deps.kibanaIndex, - deps.xpackMain, + deps.features, available ); diff --git a/x-pack/plugins/spaces/server/lib/migrations/index.ts b/x-pack/plugins/spaces/server/lib/migrations/index.ts new file mode 100644 index 0000000000000..b303a8489ffb0 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/migrations/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { migrateToKibana660 } from './migrate_6x'; diff --git a/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.test.ts b/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.test.ts new file mode 100644 index 0000000000000..964eb8137685f --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { migrateToKibana660 } from './migrate_6x'; + +describe('migrateTo660', () => { + it('adds a "disabledFeatures" attribute initialized as an empty array', () => { + expect( + migrateToKibana660({ + id: 'space:foo', + attributes: {}, + }) + ).toEqual({ + id: 'space:foo', + attributes: { + disabledFeatures: [], + }, + }); + }); + + it('does not initialize "disabledFeatures" if the property already exists', () => { + // This scenario shouldn't happen organically. Protecting against defects in the migration. + expect( + migrateToKibana660({ + id: 'space:foo', + attributes: { + disabledFeatures: ['foo', 'bar', 'baz'], + }, + }) + ).toEqual({ + id: 'space:foo', + attributes: { + disabledFeatures: ['foo', 'bar', 'baz'], + }, + }); + }); +}); diff --git a/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.ts b/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.ts new file mode 100644 index 0000000000000..0c080a8dabb0a --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/migrations/migrate_6x.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export function migrateToKibana660(doc: Record) { + if (!doc.attributes.hasOwnProperty('disabledFeatures')) { + doc.attributes.disabledFeatures = []; + } + return doc; +} diff --git a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/request_interceptors/index.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/index.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts similarity index 90% rename from x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 511af53c13ab4..1f20fee46ba4c 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -10,30 +10,30 @@ import { Legacy } from 'kibana'; import { kibanaTestUser } from '@kbn/test'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { - HttpServiceSetup, CoreSetup, SavedObjectsLegacyService, SavedObjectsErrorHelpers, -} from '../../../../../../../src/core/server'; + IBasePath, + IRouter, +} from '../../../../../../src/core/server'; import { elasticsearchServiceMock, loggingServiceMock, -} from '../../../../../../../src/core/server/mocks'; -import * as kbnTestServer from '../../../../../../../src/test_utils/kbn_server'; -import { LegacyAPI } from '../../new_platform/plugin'; -import { SpacesService } from '../../new_platform/spaces_service'; -import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; +} from '../../../../../../src/core/server/mocks'; +import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; +import { LegacyAPI, PluginsSetup } from '../../plugin'; +import { SpacesService } from '../../spaces_service'; import { SpacesAuditLogger } from '../audit_logger'; -import { SecurityPlugin } from '../../../../security'; import { convertSavedObjectToSpace } from '../../routes/lib'; -import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; -import { Feature } from '../../../../../../plugins/features/server'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; +import { Feature } from '../../../../features/server'; +import { OptionalPlugin } from '../../../../../legacy/server/lib/optional_plugin'; +import { SecurityPlugin } from '../../../../../legacy/plugins/security'; +import { spacesConfig } from '../__fixtures__'; describe('onPostAuthInterceptor', () => { let root: ReturnType; - const defaultRoute = '/app/kibana'; const headers = { authorization: `Basic ${Buffer.from( `${kibanaTestUser.username}:${kibanaTestUser.password}` @@ -46,7 +46,7 @@ describe('onPostAuthInterceptor', () => { afterEach(async () => await root.shutdown()); - function initKbnServer(http: HttpServiceSetup, routes: 'legacy' | 'new-platform') { + function initKbnServer(router: IRouter, basePath: IBasePath, routes: 'legacy' | 'new-platform') { const kbnServer = kbnTestServer.getKbnServer(root); if (routes === 'legacy') { @@ -55,52 +55,50 @@ describe('onPostAuthInterceptor', () => { method: 'GET', path: '/foo', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { method: 'GET', path: '/app/kibana', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { method: 'GET', path: '/app/app-1', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { method: 'GET', path: '/app/app-2', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { method: 'GET', path: '/api/test/foo', handler: (req: Legacy.Request) => { - return { path: req.path, basePath: http.basePath.get(req) }; + return { path: req.path, basePath: basePath.get(req) }; }, }, { method: 'GET', path: '/some/path/s/foo/bar', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, ]); } if (routes === 'new-platform') { - const router = http.createRouter('/'); - router.get({ path: '/api/np_test/foo', validate: false }, (context, req, h) => { - return h.ok({ body: { path: req.url.pathname, basePath: http.basePath.get(req) } }); + return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); }); } } @@ -117,7 +115,7 @@ describe('onPostAuthInterceptor', () => { .asLoggerFactory() .get('xpack', 'spaces'); - const xpackMainPlugin = { + const featuresPlugin = { getFeatures: () => [ { @@ -141,7 +139,7 @@ describe('onPostAuthInterceptor', () => { app: ['kibana'], }, ] as Feature[], - } as XPackMainPlugin; + } as PluginsSetup['features']; const savedObjectsService = { SavedObjectsClient: { @@ -164,10 +162,6 @@ describe('onPostAuthInterceptor', () => { }; const legacyAPI = { - legacyConfig: { - serverDefaultRoute: defaultRoute, - serverBasePath: '', - }, savedObjects: (savedObjectsService as unknown) as SavedObjectsLegacyService, } as LegacyAPI; @@ -176,9 +170,9 @@ describe('onPostAuthInterceptor', () => { const spacesService = await service.setup({ http: (http as unknown) as CoreSetup['http'], elasticsearch: elasticsearchServiceMock.createSetupContract(), - security: {} as OptionalPlugin, + getSecurity: () => ({} as OptionalPlugin), getSpacesAuditLogger: () => ({} as SpacesAuditLogger), - config$: Rx.of({ maxSpaces: 1000 }), + config$: Rx.of(spacesConfig), }); spacesService.scopedClient = jest.fn().mockResolvedValue({ @@ -212,15 +206,17 @@ describe('onPostAuthInterceptor', () => { getLegacyAPI: () => legacyAPI, http: (http as unknown) as CoreSetup['http'], log: loggingMock, - xpackMain: xpackMainPlugin, + features: featuresPlugin, spacesService, }); - initKbnServer(http, 'new-platform'); + const router = http.createRouter('/'); + + initKbnServer(router, http.basePath, 'new-platform'); await root.start(); - initKbnServer(http, 'legacy'); + initKbnServer(router, http.basePath, 'legacy'); const response = await kbnTestServer.request.get(root, path); diff --git a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts similarity index 85% rename from x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index e02677d94a8da..4674f3641084a 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -6,9 +6,8 @@ import { Logger, CoreSetup } from 'src/core/server'; import { Space } from '../../../common/model/space'; import { wrapError } from '../errors'; -import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; -import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { LegacyAPI } from '../../new_platform/plugin'; +import { SpacesServiceSetup } from '../../spaces_service/spaces_service'; +import { LegacyAPI, PluginsSetup } from '../../plugin'; import { getSpaceSelectorUrl } from '../get_space_selector_url'; import { DEFAULT_SPACE_ID, ENTER_SPACE_PATH } from '../../../common/constants'; import { addSpaceIdToPath } from '../../../common'; @@ -16,21 +15,21 @@ import { addSpaceIdToPath } from '../../../common'; export interface OnPostAuthInterceptorDeps { getLegacyAPI(): LegacyAPI; http: CoreSetup['http']; - xpackMain: XPackMainPlugin; + features: PluginsSetup['features']; spacesService: SpacesServiceSetup; log: Logger; } export function initSpacesOnPostAuthRequestInterceptor({ - xpackMain, + features, getLegacyAPI, spacesService, log, http, }: OnPostAuthInterceptorDeps) { - const { serverBasePath } = getLegacyAPI().legacyConfig; - http.registerOnPostAuth(async (request, response, toolkit) => { + const serverBasePath = http.basePath.serverBasePath; + const path = request.url.pathname!; const spaceId = spacesService.getSpaceId(request); @@ -66,12 +65,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ }); } } catch (error) { - const wrappedError = wrapError(error); - return response.customError({ - body: wrappedError, - headers: wrappedError.output.headers, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrapError(error)); } } else if (isRequestingSpaceRoot) { const destination = addSpaceIdToPath(serverBasePath, spaceId, ENTER_SPACE_PATH); @@ -89,7 +83,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ } catch (error) { const wrappedError = wrapError(error); - const statusCode = wrappedError.output.statusCode; + const statusCode = wrappedError.statusCode; // If user is not authorized, or the space cannot be found, allow them to select another space // by redirecting to the space selector. @@ -106,11 +100,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ }); } else { log.error(`Unable to navigate to space "${spaceId}". ${error}`); - return response.customError({ - body: wrappedError, - headers: wrappedError.output.headers, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrappedError); } } @@ -120,7 +110,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ if (appId !== 'kibana' && space && space.disabledFeatures.length > 0) { log.debug(`Verifying application is available: "${appId}"`); - const allFeatures = xpackMain.getFeatures(); + const allFeatures = features.getFeatures(); const isRegisteredApp = allFeatures.some(feature => feature.app.includes(appId)); if (isRegisteredApp) { diff --git a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts similarity index 87% rename from x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index e8bfab9fb1df0..d6ff4a20052e4 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -8,14 +8,15 @@ import { Legacy } from 'kibana'; import { schema } from '@kbn/config-schema'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { - HttpServiceSetup, KibanaRequest, KibanaResponseFactory, CoreSetup, -} from '../../../../../../../src/core/server'; + IBasePath, + IRouter, +} from '../../../../../../src/core/server'; -import * as kbnTestServer from '../../../../../../../src/test_utils/kbn_server'; -import { LegacyAPI } from '../../new_platform/plugin'; +import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; +import { LegacyAPI } from '../../plugin'; describe('onRequestInterceptor', () => { let root: ReturnType; @@ -26,7 +27,7 @@ describe('onRequestInterceptor', () => { afterEach(async () => await root.shutdown()); - function initKbnServer(http: HttpServiceSetup, routes: 'legacy' | 'new-platform') { + function initKbnServer(router: IRouter, basePath: IBasePath, routes: 'legacy' | 'new-platform') { const kbnServer = kbnTestServer.getKbnServer(root); if (routes === 'legacy') { @@ -35,14 +36,14 @@ describe('onRequestInterceptor', () => { method: 'GET', path: '/foo', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { method: 'GET', path: '/some/path/s/foo/bar', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.basePath.get(req) }); + return h.response({ path: req.path, basePath: basePath.get(req) }); }, }, { @@ -51,7 +52,7 @@ describe('onRequestInterceptor', () => { handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { return h.response({ path: req.path, - basePath: http.basePath.get(req), + basePath: basePath.get(req), query: req.query, }); }, @@ -60,19 +61,17 @@ describe('onRequestInterceptor', () => { } if (routes === 'new-platform') { - const router = http.createRouter('/'); - router.get( { path: '/np_foo', validate: false }, (context: unknown, req: KibanaRequest, h: KibanaResponseFactory) => { - return h.ok({ body: { path: req.url.pathname, basePath: http.basePath.get(req) } }); + return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); } ); router.get( { path: '/some/path/s/np_foo/bar', validate: false }, (context: unknown, req: KibanaRequest, h: KibanaResponseFactory) => { - return h.ok({ body: { path: req.url.pathname, basePath: http.basePath.get(req) } }); + return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); } ); @@ -91,7 +90,7 @@ describe('onRequestInterceptor', () => { return h.ok({ body: { path: req.url.pathname, - basePath: http.basePath.get(req), + basePath: basePath.get(req), query: req.query, }, }); @@ -110,18 +109,18 @@ describe('onRequestInterceptor', () => { initSpacesOnRequestInterceptor({ getLegacyAPI: () => ({ - legacyConfig: { - serverBasePath: opts.basePath, - }, + legacyConfig: {}, } as LegacyAPI), http: (http as unknown) as CoreSetup['http'], }); - initKbnServer(http, 'new-platform'); + const router = http.createRouter('/'); + + initKbnServer(router, http.basePath, 'new-platform'); await root.start(); - initKbnServer(http, 'legacy'); + initKbnServer(router, http.basePath, 'legacy'); return { http, diff --git a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts similarity index 93% rename from x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index 114cc9bf86d46..22d704c1b7e13 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -12,7 +12,7 @@ import { import { format } from 'url'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { modifyUrl } from '../utils/url'; -import { LegacyAPI } from '../../new_platform/plugin'; +import { LegacyAPI } from '../../plugin'; import { getSpaceIdFromPath } from '../../../common'; export interface OnRequestInterceptorDeps { @@ -25,7 +25,7 @@ export function initSpacesOnRequestInterceptor({ getLegacyAPI, http }: OnRequest response: LifecycleResponseFactory, toolkit: OnPreAuthToolkit ) { - const { serverBasePath } = getLegacyAPI().legacyConfig; + const serverBasePath = http.basePath.serverBasePath; const path = request.url.pathname; // If navigating within the context of a space, then we store the Space's URL Context on the request, diff --git a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.ts.snap b/x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.ts.snap rename to x-pack/plugins/spaces/server/lib/saved_objects_client/__snapshots__/spaces_saved_objects_client.test.ts.snap diff --git a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts similarity index 88% rename from x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts rename to x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts index 466c3237fd7db..aa61af07c268e 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts @@ -6,7 +6,7 @@ import { SavedObjectsClientWrapperFactory } from 'src/core/server'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; -import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; +import { SpacesServiceSetup } from '../../spaces_service/spaces_service'; export function spacesSavedObjectsClientWrapperFactory( spacesService: SpacesServiceSetup, diff --git a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts similarity index 99% rename from x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts rename to x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index 4a5796b2e4ea2..7e1c4ff211a6f 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -6,7 +6,7 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; -import { spacesServiceMock } from '../../new_platform/spaces_service/spaces_service.mock'; +import { spacesServiceMock } from '../../spaces_service/spaces_service.mock'; const types = ['foo', 'bar', 'space']; diff --git a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts similarity index 98% rename from x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts rename to x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts index d47a22e8d4545..2c5e4d0998b51 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts @@ -14,7 +14,7 @@ import { SavedObjectsFindOptions, SavedObjectsUpdateOptions, } from 'src/core/server'; -import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; +import { SpacesServiceSetup } from '../../spaces_service/spaces_service'; import { spaceIdToNamespace } from '../utils/namespace'; interface SpacesSavedObjectsClientOptions { diff --git a/x-pack/plugins/spaces/server/lib/space_schema.test.ts b/x-pack/plugins/spaces/server/lib/space_schema.test.ts new file mode 100644 index 0000000000000..92ccb5401893a --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/space_schema.test.ts @@ -0,0 +1,231 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { spaceSchema } from './space_schema'; + +const defaultProperties = { + id: 'foo', + name: 'foo', +}; + +describe('#id', () => { + test('is required', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + id: undefined, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[id]: expected value of type [string] but got [undefined]"` + ); + }); + + test('allows lowercase a-z, 0-9, "_" and "-"', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + id: 'abcdefghijklmnopqrstuvwxyz0123456789_-', + }) + ).not.toThrowError(); + }); + + test(`doesn't allow uppercase`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + id: 'Foo', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[id]: must be lower case, a-z, 0-9, '_', and '-' are allowed"` + ); + }); + + test(`doesn't allow an empty string`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + id: '', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[id]: must be lower case, a-z, 0-9, '_', and '-' are allowed"` + ); + }); + + ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', ',', '.', '/', '?'].forEach( + invalidCharacter => { + test(`doesn't allow ${invalidCharacter}`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + id: `foo-${invalidCharacter}`, + }) + ).toThrowError(); + }); + } + ); +}); + +describe('#disabledFeatures', () => { + test('is optional', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + disabledFeatures: undefined, + }) + ).not.toThrowError(); + }); + + test('defaults to an empty array', () => { + const result = spaceSchema.validate({ + ...defaultProperties, + disabledFeatures: undefined, + }); + expect(result.disabledFeatures).toEqual([]); + }); + + test('must be an array if provided', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + disabledFeatures: 'foo', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[disabledFeatures]: expected value of type [array] but got [string]"` + ); + }); + + test('allows an array of strings', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + disabledFeatures: ['foo', 'bar'], + }) + ).not.toThrowError(); + }); + + test('does not allow an array containing non-string elements', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + disabledFeatures: ['foo', true], + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[disabledFeatures.1]: expected value of type [string] but got [boolean]"` + ); + }); +}); + +describe('#color', () => { + test('is optional', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: undefined, + }) + ).not.toThrowError(); + }); + + test(`doesn't allow an empty string`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[color]: must be a 6 digit hex color, starting with a #"` + ); + }); + + test(`allows lower case hex color code`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '#aabbcc', + }) + ).not.toThrowError(); + }); + + test(`allows upper case hex color code`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '#AABBCC', + }) + ).not.toThrowError(); + }); + + test(`allows numeric hex color code`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '#123456', + }) + ).not.toThrowError(); + }); + + test(`must start with a hash`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '123456', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[color]: must be a 6 digit hex color, starting with a #"` + ); + }); + + test(`cannot exceed 6 digits following the hash`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '1234567', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[color]: must be a 6 digit hex color, starting with a #"` + ); + }); + + test(`cannot be fewer than 6 digits following the hash`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + color: '12345', + }) + ).toThrowErrorMatchingInlineSnapshot( + `"[color]: must be a 6 digit hex color, starting with a #"` + ); + }); +}); + +describe('#imageUrl', () => { + test('is optional', () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + imageUrl: undefined, + }) + ).not.toThrowError(); + }); + + test(`must start with data:image`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + imageUrl: 'notValid', + }) + ).toThrowErrorMatchingInlineSnapshot(`"[imageUrl]: must start with 'data:image'"`); + }); + + test(`checking that a valid image is accepted as imageUrl`, () => { + expect(() => + spaceSchema.validate({ + ...defaultProperties, + imageUrl: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTnU1rJkAAAB3klEQVRYR+2WzUrDQBCARzwqehE8ir1WPfgqRRA1bePBXgpe/MGCB9/Aiw+j+ASCB6kotklaEwW1F0WwNSaps9lV69awGzBpDzt8pJP9mXxsmk3ABH2oUEIilJAIJSRCCYlQQiKUkIh4QgY5agZodVjBowFrBktWQzDBU2ykiYaDuQpCYgnl3QunGzM6Z6YF+b5SkcgK1UH/aLbYReQiYL9d9/o+XFop5IU0Vl4uapAzoXC3eEBPw9vH1/wT6Vs2otPSkoH/IZzlzO/TU2vgQm8nl69Hp0H7nZ4OXogLJSSKBIUC3w88n+Ueyfv56fVZnqCQNVnCHbLrkV0Gd2d+GNkglsk438dhaTxloZDutV4wb06Vf40JcWZ2sMttPpE8NaHGeBnzIAhwPXqHseVB11EyLD0hxLUeaYud2a3B0g3k7GyFtrhX7F2RqhC+yV3jgTb2Rqdqf7/kUxYiWBOlTtXxfPJEtc8b5thGb+8AhL4ohnCNqQjZ2T2+K5rnw2M6KwEhKNDSGM3pTdxjhDgLbHkw/v/zw4AiPuSsfMzAiTidKxiF/ArpFqyzK8SMOlkwvloUMYRCtNvZLWeuIomd2Za/WZS4QomjhEQoIRFKSIQSEqGERAyfEH4YDBFQ/ARU6BiBxCAIQQAAAABJRU5ErkJggg==', + }) + ).not.toThrowError(); + }); +}); diff --git a/x-pack/plugins/spaces/server/lib/space_schema.ts b/x-pack/plugins/spaces/server/lib/space_schema.ts new file mode 100644 index 0000000000000..18d9478576e52 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/space_schema.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { MAX_SPACE_INITIALS } from '../../common'; + +export const SPACE_ID_REGEX = /^[a-z0-9_\-]+$/; + +export const spaceSchema = schema.object({ + id: schema.string({ + validate: value => { + if (!SPACE_ID_REGEX.test(value)) { + return `must be lower case, a-z, 0-9, '_', and '-' are allowed`; + } + }, + }), + name: schema.string({ minLength: 1 }), + description: schema.maybe(schema.string()), + initials: schema.maybe(schema.string({ maxLength: MAX_SPACE_INITIALS })), + color: schema.maybe( + schema.string({ + validate: value => { + if (!/^#[a-zA-Z0-9]{6}$/.test(value)) { + return `must be a 6 digit hex color, starting with a #`; + } + }, + }) + ), + disabledFeatures: schema.arrayOf(schema.string(), { defaultValue: [] }), + _reserved: schema.maybe(schema.boolean()), + imageUrl: schema.maybe( + schema.string({ + validate: value => { + if (value !== '' && !/^data:image.*$/.test(value)) { + return `must start with 'data:image'`; + } + }, + }) + ), +}); diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap b/x-pack/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap rename to x-pack/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/index.ts b/x-pack/plugins/spaces/server/lib/spaces_client/index.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_client/index.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/index.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts similarity index 96% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts index d773cd86ef688..10f6292abf319 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts @@ -29,7 +29,7 @@ const createSpacesClientMock = () => create: jest.fn().mockImplementation((space: Space) => Promise.resolve(space)), update: jest.fn().mockImplementation((space: Space) => Promise.resolve(space)), delete: jest.fn(), - } as unknown) as SpacesClient); + } as unknown) as jest.Mocked); export const spacesClientMock = { create: createSpacesClientMock, diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts similarity index 98% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts index 78ad10bbd9164..e62a3a0efa601 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts @@ -5,9 +5,9 @@ */ import { SpacesClient } from './spaces_client'; -import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; -import { actionsFactory } from '../../../../security/server/lib/authorization/actions'; -import { SpacesConfigType, config } from '../../new_platform/config'; +import { AuthorizationService } from '../../../../../legacy/plugins/security/server/lib/authorization/service'; +import { actionsFactory } from '../../../../../legacy/plugins/security/server/lib/authorization/actions'; +import { ConfigType, ConfigSchema } from '../../config'; import { GetSpacePurpose } from '../../../common/model/types'; const createMockAuditLogger = () => { @@ -69,8 +69,8 @@ const createMockAuthorization = () => { }; }; -const createMockConfig = (mockConfig: SpacesConfigType = { maxSpaces: 1000 }) => { - return config.schema.validate(mockConfig); +const createMockConfig = (mockConfig: ConfigType = { maxSpaces: 1000, enabled: true }) => { + return ConfigSchema.validate(mockConfig); }; describe('#getAll', () => { @@ -123,6 +123,7 @@ describe('#getAll', () => { const maxSpaces = 1234; const mockConfig = createMockConfig({ maxSpaces: 1234, + enabled: true, }); const client = new SpacesClient( @@ -162,6 +163,7 @@ describe('#getAll', () => { const maxSpaces = 1234; const mockConfig = createMockConfig({ maxSpaces: 1234, + enabled: true, }); const request = Symbol() as any; @@ -287,6 +289,7 @@ describe('#getAll', () => { const maxSpaces = 1234; const mockConfig = createMockConfig({ maxSpaces: 1234, + enabled: true, }); const mockInternalRepository = { find: jest.fn().mockReturnValue({ @@ -355,6 +358,7 @@ describe('#getAll', () => { const maxSpaces = 1234; const mockConfig = createMockConfig({ maxSpaces: 1234, + enabled: true, }); const request = Symbol() as any; @@ -725,6 +729,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; @@ -766,6 +771,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; @@ -807,6 +813,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; @@ -850,6 +857,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; @@ -931,6 +939,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; @@ -983,6 +992,7 @@ describe('#create', () => { }; const mockConfig = createMockConfig({ maxSpaces, + enabled: true, }); const request = Symbol() as any; diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts similarity index 97% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts index 6d30084d0dc86..052534879e678 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/spaces_client/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts @@ -7,11 +7,11 @@ import Boom from 'boom'; import { omit } from 'lodash'; import { Legacy } from 'kibana'; import { KibanaRequest } from 'src/core/server'; -import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; +import { AuthorizationService } from '../../../../../legacy/plugins/security/server/lib/authorization/service'; import { isReservedSpace } from '../../../common/is_reserved_space'; import { Space } from '../../../common/model/space'; import { SpacesAuditLogger } from '../audit_logger'; -import { SpacesConfigType } from '../../new_platform/config'; +import { ConfigType } from '../../config'; import { GetSpacePurpose } from '../../../common/model/types'; type SpacesClientRequestFacade = Legacy.Request | KibanaRequest; @@ -33,7 +33,7 @@ export class SpacesClient { private readonly debugLogger: (message: string) => void, private readonly authorization: AuthorizationService | null, private readonly callWithRequestSavedObjectRepository: any, - private readonly config: SpacesConfigType, + private readonly config: ConfigType, private readonly internalSavedObjectRepository: any, private readonly request: SpacesClientRequestFacade ) {} diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts similarity index 81% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts rename to x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 725b4cdc6bbad..4fbc4df03d00e 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -7,13 +7,14 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; -import { SpacesService } from '../new_platform/spaces_service'; +import { SpacesService } from '../spaces_service'; import { SavedObjectsLegacyService } from 'src/core/server'; import { SpacesAuditLogger } from './audit_logger'; -import { elasticsearchServiceMock, coreMock } from '../../../../../../src/core/server/mocks'; -import { spacesServiceMock } from '../new_platform/spaces_service/spaces_service.mock'; -import { createOptionalPlugin } from '../../../../server/lib/optional_plugin'; -import { LegacyAPI } from '../new_platform/plugin'; +import { elasticsearchServiceMock, coreMock } from '../../../../../src/core/server/mocks'; +import { spacesServiceMock } from '../spaces_service/spaces_service.mock'; +import { createOptionalPlugin } from '../../../../legacy/server/lib/optional_plugin'; +import { LegacyAPI } from '../plugin'; +import { spacesConfig } from './__fixtures__'; const log = { log: jest.fn(), @@ -26,9 +27,7 @@ const log = { }; const legacyAPI: LegacyAPI = { - legacyConfig: { - serverBasePath: '/foo', - }, + legacyConfig: {}, savedObjects: {} as SavedObjectsLegacyService, } as LegacyAPI; @@ -56,9 +55,10 @@ describe('createSpacesTutorialContextFactory', () => { const spacesService = await service.setup({ http: coreMock.createSetup().http, elasticsearch: elasticsearchServiceMock.createSetupContract(), - security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), getSpacesAuditLogger: () => ({} as SpacesAuditLogger), - config$: Rx.of({ maxSpaces: 1000 }), + config$: Rx.of(spacesConfig), }); const contextFactory = createSpacesTutorialContextFactory(spacesService); diff --git a/x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts similarity index 86% rename from x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts rename to x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts index 770294840f1c6..f89681b709949 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SpacesServiceSetup } from '../new_platform/spaces_service/spaces_service'; +import { SpacesServiceSetup } from '../spaces_service/spaces_service'; export function createSpacesTutorialContextFactory(spacesService: SpacesServiceSetup) { return function spacesTutorialContextFactory(request: any) { diff --git a/x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts b/x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts similarity index 98% rename from x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts rename to x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts index 18de89e33cb9a..f6133f5c03c6b 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts +++ b/x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.test.ts @@ -5,7 +5,7 @@ */ import { UICapabilities } from 'ui/capabilities'; -import { Feature } from '../../../../../plugins/features/server'; +import { Feature } from '../../../../plugins/features/server'; import { Space } from '../../common/model/space'; import { toggleUICapabilities } from './toggle_ui_capabilities'; diff --git a/x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.ts b/x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.ts similarity index 97% rename from x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.ts rename to x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.ts index c80ebdf88ef46..63f52ac379300 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/toggle_ui_capabilities.ts +++ b/x-pack/plugins/spaces/server/lib/toggle_ui_capabilities.ts @@ -5,7 +5,7 @@ */ import _ from 'lodash'; import { UICapabilities } from 'ui/capabilities'; -import { Feature } from '../../../../../plugins/features/server'; +import { Feature } from '../../../../plugins/features/server'; import { Space } from '../../common/model/space'; export function toggleUICapabilities( diff --git a/x-pack/legacy/plugins/spaces/server/lib/utils/namespace.test.ts b/x-pack/plugins/spaces/server/lib/utils/namespace.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/utils/namespace.test.ts rename to x-pack/plugins/spaces/server/lib/utils/namespace.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/utils/namespace.ts b/x-pack/plugins/spaces/server/lib/utils/namespace.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/utils/namespace.ts rename to x-pack/plugins/spaces/server/lib/utils/namespace.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/utils/url.test.ts b/x-pack/plugins/spaces/server/lib/utils/url.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/utils/url.test.ts rename to x-pack/plugins/spaces/server/lib/utils/url.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/lib/utils/url.ts b/x-pack/plugins/spaces/server/lib/utils/url.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/lib/utils/url.ts rename to x-pack/plugins/spaces/server/lib/utils/url.ts diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts similarity index 57% rename from x-pack/legacy/plugins/spaces/server/new_platform/plugin.ts rename to x-pack/plugins/spaces/server/plugin.ts index ed11e6da317fa..4b071baaa7e2c 100644 --- a/x-pack/legacy/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -5,30 +5,33 @@ */ import { Observable } from 'rxjs'; -import { SavedObjectsLegacyService, CoreSetup } from 'src/core/server'; -import { Logger, PluginInitializerContext } from 'src/core/server'; +import { take } from 'rxjs/operators'; import { CapabilitiesModifier } from 'src/legacy/server/capabilities'; -import { Legacy } from 'kibana'; -import { OptionalPlugin } from '../../../../server/lib/optional_plugin'; -import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; -import { createDefaultSpace } from '../lib/create_default_space'; +import { + SavedObjectsLegacyService, + CoreSetup, + KibanaRequest, + Logger, + PluginInitializerContext, +} from '../../../../src/core/server'; +import { SecurityPlugin } from '../../../legacy/plugins/security'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { OptionalPlugin } from '../../../legacy/server/lib/optional_plugin'; +import { XPackMainPlugin } from '../../../legacy/plugins/xpack_main/xpack_main'; +import { createDefaultSpace } from './lib/create_default_space'; // @ts-ignore import { AuditLogger } from '../../../../server/lib/audit_logger'; -// @ts-ignore -import { watchStatusAndLicenseToInitialize } from '../../../../server/lib/watch_status_and_license_to_initialize'; -import { checkLicense } from '../lib/check_license'; -import { spacesSavedObjectsClientWrapperFactory } from '../lib/saved_objects_client/saved_objects_client_wrapper_factory'; -import { SpacesAuditLogger } from '../lib/audit_logger'; -import { createSpacesTutorialContextFactory } from '../lib/spaces_tutorial_context_factory'; -import { initExternalSpacesApi } from '../routes/api/external'; -import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; +import { spacesSavedObjectsClientWrapperFactory } from './lib/saved_objects_client/saved_objects_client_wrapper_factory'; +import { SpacesAuditLogger } from './lib/audit_logger'; +import { createSpacesTutorialContextFactory } from './lib/spaces_tutorial_context_factory'; +import { getSpacesUsageCollector } from './lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; -import { SecurityPlugin } from '../../../security'; import { SpacesServiceSetup } from './spaces_service/spaces_service'; -import { SpacesConfigType } from './config'; -import { getActiveSpace } from '../lib/get_active_space'; -import { toggleUICapabilities } from '../lib/toggle_ui_capabilities'; -import { initSpacesRequestInterceptors } from '../lib/request_interceptors'; +import { ConfigType } from './config'; +import { toggleUICapabilities } from './lib/toggle_ui_capabilities'; +import { initSpacesRequestInterceptors } from './lib/request_interceptors'; +import { initExternalSpacesApi } from './routes/api/external'; /** * Describes a set of APIs that is available in the legacy platform only and required by this plugin @@ -52,30 +55,33 @@ export interface LegacyAPI { }; legacyConfig: { kibanaIndex: string; - serverBasePath: string; - serverDefaultRoute: string; }; - router: Legacy.Server['route']; -} - -export interface PluginsSetup { + xpackMain: XPackMainPlugin; // TODO: Spaces has a circular dependency with Security right now. // Security is not yet available when init runs, so this is wrapped in an optional plugin for the time being. security: OptionalPlugin; - xpackMain: XPackMainPlugin; - // TODO: this is temporary for `watchLicenseAndStatusToInitialize` - spaces: any; +} + +export interface PluginsSetup { + features: FeaturesPluginSetup; + licensing: LicensingPluginSetup; } export interface SpacesPluginSetup { spacesService: SpacesServiceSetup; - registerLegacyAPI: (legacyAPI: LegacyAPI) => void; + __legacyCompat: { + registerLegacyAPI: (legacyAPI: LegacyAPI) => void; + // TODO: We currently need the legacy plugin to inform this plugin when it is safe to create the default space. + // The NP does not have the equivilent ES connection/health/comapt checks that the legacy world does. + // See: https://github.com/elastic/kibana/issues/43456 + createDefaultSpace: () => Promise; + }; } export class Plugin { private readonly pluginId = 'spaces'; - private readonly config$: Observable; + private readonly config$: Observable; private readonly log: Logger; @@ -98,99 +104,91 @@ export class Plugin { }; constructor(initializerContext: PluginInitializerContext) { - this.config$ = initializerContext.config.create(); + this.config$ = initializerContext.config.create(); this.log = initializerContext.logger.get(); } - public async setup(core: CoreSetup, plugins: PluginsSetup): Promise { - const xpackMainPlugin: XPackMainPlugin = plugins.xpackMain; - watchStatusAndLicenseToInitialize(xpackMainPlugin, plugins.spaces, async () => { - await createDefaultSpace({ - elasticsearch: core.elasticsearch, - savedObjects: this.getLegacyAPI().savedObjects, - }); - }); - - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin. - xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); + public async start() {} + public async setup(core: CoreSetup, plugins: PluginsSetup): Promise { const service = new SpacesService(this.log, this.getLegacyAPI); const spacesService = await service.setup({ http: core.http, elasticsearch: core.elasticsearch, - security: plugins.security, + getSecurity: () => this.getLegacyAPI().security, getSpacesAuditLogger: this.getSpacesAuditLogger, config$: this.config$, }); + const externalRouter = core.http.createRouter(); + initExternalSpacesApi({ + externalRouter, + log: this.log, + getSavedObjects: () => this.getLegacyAPI().savedObjects, + spacesService, + }); + + initSpacesRequestInterceptors({ + http: core.http, + log: this.log, + getLegacyAPI: this.getLegacyAPI, + spacesService, + features: plugins.features, + }); + return { spacesService, - registerLegacyAPI: (legacyAPI: LegacyAPI) => { - this.legacyAPI = legacyAPI; - this.setupLegacyComponents(core, spacesService, plugins.xpackMain); + __legacyCompat: { + registerLegacyAPI: (legacyAPI: LegacyAPI) => { + this.legacyAPI = legacyAPI; + this.setupLegacyComponents(spacesService, plugins.features, plugins.licensing); + }, + createDefaultSpace: async () => { + const esClient = await core.elasticsearch.adminClient$.pipe(take(1)).toPromise(); + return createDefaultSpace({ + esClient, + savedObjects: this.getLegacyAPI().savedObjects, + }); + }, }, }; } + public stop() {} + private setupLegacyComponents( - core: CoreSetup, spacesService: SpacesServiceSetup, - xpackMainPlugin: XPackMainPlugin + featuresSetup: FeaturesPluginSetup, + licensingSetup: LicensingPluginSetup ) { const legacyAPI = this.getLegacyAPI(); - const { addScopedSavedObjectsClientWrapperFactory, types } = legacyAPI.savedObjects; addScopedSavedObjectsClientWrapperFactory( Number.MIN_SAFE_INTEGER, 'spaces', spacesSavedObjectsClientWrapperFactory(spacesService, types) ); - legacyAPI.tutorial.addScopedTutorialContextFactory( createSpacesTutorialContextFactory(spacesService) ); - legacyAPI.capabilities.registerCapabilitiesModifier(async (request, uiCapabilities) => { - const spacesClient = await spacesService.scopedClient(request); try { - const activeSpace = await getActiveSpace( - spacesClient, - core.http.basePath.get(request), - legacyAPI.legacyConfig.serverBasePath - ); - - const features = xpackMainPlugin.getFeatures(); + const activeSpace = await spacesService.getActiveSpace(KibanaRequest.from(request)); + const features = featuresSetup.getFeatures(); return toggleUICapabilities(features, uiCapabilities, activeSpace); } catch (e) { return uiCapabilities; } }); - // Register a function with server to manage the collection of usage stats legacyAPI.usage.collectorSet.register( getSpacesUsageCollector({ kibanaIndex: legacyAPI.legacyConfig.kibanaIndex, usage: legacyAPI.usage, - xpackMain: xpackMainPlugin, + features: featuresSetup, + licensing: licensingSetup, }) ); - - initExternalSpacesApi({ - legacyRouter: legacyAPI.router, - log: this.log, - savedObjects: legacyAPI.savedObjects, - spacesService, - xpackMain: xpackMainPlugin, - }); - - initSpacesRequestInterceptors({ - http: core.http, - log: this.log, - getLegacyAPI: this.getLegacyAPI, - spacesService, - xpackMain: xpackMainPlugin, - }); } } diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_legacy_api.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_legacy_api.ts new file mode 100644 index 0000000000000..5f366871ba81e --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_legacy_api.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Readable } from 'stream'; +import { createPromiseFromStreams, createConcatStream } from 'src/legacy/utils/streams'; +import { SavedObjectsSchema, SavedObjectsLegacyService } from 'src/core/server'; +import { LegacyAPI } from '../../../plugin'; +import { Space } from '../../../../common/model/space'; +import { createSpaces } from '.'; + +async function readStreamToCompletion(stream: Readable) { + return (await (createPromiseFromStreams([stream, createConcatStream([])]) as unknown)) as any[]; +} + +interface LegacyAPIOpts { + spaces?: Space[]; +} + +export const createLegacyAPI = ({ + spaces = createSpaces().map(s => ({ id: s.id, ...s.attributes })), +}: LegacyAPIOpts = {}) => { + const mockSavedObjectsClientContract = { + get: jest.fn((type, id) => { + const result = spaces.filter(s => s.id === id); + if (!result.length) { + throw new Error(`not found: [${type}:${id}]`); + } + return result[0]; + }), + find: jest.fn(() => { + return { + total: spaces.length, + saved_objects: spaces, + }; + }), + create: jest.fn((type, attributes, { id }) => { + if (spaces.find(s => s.id === id)) { + throw new Error('conflict'); + } + return {}; + }), + update: jest.fn((type, id) => { + if (!spaces.find(s => s.id === id)) { + throw new Error('not found: during update'); + } + return {}; + }), + delete: jest.fn((type: string, id: string) => { + return {}; + }), + deleteByNamespace: jest.fn(), + }; + + const savedObjectsService = ({ + types: ['visualization', 'dashboard', 'index-pattern', 'globalType'], + schema: new SavedObjectsSchema({ + space: { + isNamespaceAgnostic: true, + hidden: true, + }, + globalType: { + isNamespaceAgnostic: true, + }, + }), + getScopedSavedObjectsClient: jest.fn().mockResolvedValue(mockSavedObjectsClientContract), + importExport: { + objectLimit: 10000, + getSortedObjectsForExport: jest.fn().mockResolvedValue( + new Readable({ + objectMode: true, + read() { + this.push(null); + }, + }) + ), + importSavedObjects: jest.fn().mockImplementation(async (opts: Record) => { + const objectsToImport: any[] = await readStreamToCompletion(opts.readStream); + return { + success: true, + successCount: objectsToImport.length, + }; + }), + resolveImportErrors: jest.fn().mockImplementation(async (opts: Record) => { + const objectsToImport: any[] = await readStreamToCompletion(opts.readStream); + return { + success: true, + successCount: objectsToImport.length, + }; + }), + }, + SavedObjectsClient: { + errors: { + isNotFoundError: jest.fn((e: any) => e.message.startsWith('not found:')), + isConflictError: jest.fn((e: any) => e.message.startsWith('conflict')), + }, + }, + } as unknown) as jest.Mocked; + + const legacyAPI: jest.Mocked = { + legacyConfig: { + kibanaIndex: '', + }, + auditLogger: {} as any, + capabilities: {} as any, + security: {} as any, + tutorial: {} as any, + usage: {} as any, + xpackMain: {} as any, + savedObjects: savedObjectsService, + }; + + return legacyAPI; +}; diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_mock_so_repository.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_mock_so_repository.ts new file mode 100644 index 0000000000000..1548a88e554e3 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_mock_so_repository.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from 'src/core/server'; + +export const createMockSavedObjectsRepository = (spaces: any[] = []) => { + const mockSavedObjectsClientContract = ({ + get: jest.fn((type, id) => { + const result = spaces.filter(s => s.id === id); + if (!result.length) { + throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); + } + return result[0]; + }), + find: jest.fn(() => { + return { + total: spaces.length, + saved_objects: spaces, + }; + }), + create: jest.fn((type, attributes, { id }) => { + if (spaces.find(s => s.id === id)) { + throw SavedObjectsErrorHelpers.decorateConflictError(new Error(), 'space conflict'); + } + return {}; + }), + update: jest.fn((type, id) => { + if (!spaces.find(s => s.id === id)) { + throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); + } + return {}; + }), + delete: jest.fn((type: string, id: string) => { + return {}; + }), + deleteByNamespace: jest.fn(), + } as unknown) as jest.Mocked; + + return mockSavedObjectsClientContract; +}; diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts similarity index 86% rename from x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts rename to x-pack/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts index 85284e3fc3a1c..0e23054819ea5 100644 --- a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_spaces.ts @@ -10,18 +10,21 @@ export function createSpaces() { id: 'a-space', attributes: { name: 'a space', + disabledFeatures: [], }, }, { id: 'b-space', attributes: { name: 'b space', + disabledFeatures: [], }, }, { id: 'default', attributes: { name: 'Default Space', + disabledFeatures: [], _reserved: true, }, }, diff --git a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/index.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/index.ts similarity index 56% rename from x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/index.ts rename to x-pack/plugins/spaces/server/routes/api/__fixtures__/index.ts index 37fe32c80032e..1f5a5fe2cc91e 100644 --- a/x-pack/legacy/plugins/spaces/server/routes/api/__fixtures__/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/index.ts @@ -5,11 +5,6 @@ */ export { createSpaces } from './create_spaces'; -export { - createTestHandler, - TestConfig, - TestOptions, - TeardownFn, - RequestRunner, - RequestRunnerResult, -} from './create_test_handler'; +export { createLegacyAPI } from './create_legacy_api'; +export { createMockSavedObjectsRepository } from './create_mock_so_repository'; +export { mockRouteContext, mockRouteContextWithInvalidLicense } from './route_contexts'; diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/route_contexts.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/route_contexts.ts new file mode 100644 index 0000000000000..5bb811ef6be4c --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/route_contexts.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandlerContext } from 'src/core/server'; +import { LICENSE_STATUS } from '../../../../../licensing/server/constants'; + +export const mockRouteContext = ({ + licensing: { + license: { + check: jest.fn().mockReturnValue({ + check: LICENSE_STATUS.Valid, + }), + }, + }, +} as unknown) as RequestHandlerContext; + +export const mockRouteContextWithInvalidLicense = ({ + licensing: { + license: { + check: jest.fn().mockReturnValue({ + check: LICENSE_STATUS.Invalid, + message: 'License is invalid for spaces', + }), + }, + }, +} as unknown) as RequestHandlerContext; diff --git a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts new file mode 100644 index 0000000000000..92744aa9f0fc5 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.test.ts @@ -0,0 +1,450 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContext, + mockRouteContextWithInvalidLicense, +} from '../__fixtures__'; +import { CoreSetup, IRouter, kibanaResponseFactory } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServiceMock, + httpServerMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { initCopyToSpacesApi } from './copy_to_space'; +import { ObjectType } from '@kbn/config-schema'; +import { RouteSchemas } from 'src/core/server/http/router/route'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('copy to space', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initCopyToSpacesApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + const [ + [ctsRouteDefinition, ctsRouteHandler], + [resolveRouteDefinition, resolveRouteHandler], + ] = router.post.mock.calls; + + return { + copyToSpace: { + routeValidation: ctsRouteDefinition.validate as RouteSchemas< + ObjectType, + ObjectType, + ObjectType + >, + routeHandler: ctsRouteHandler, + }, + resolveConflicts: { + routeValidation: resolveRouteDefinition.validate as RouteSchemas< + ObjectType, + ObjectType, + ObjectType + >, + routeHandler: resolveRouteHandler, + }, + savedObjectsRepositoryMock, + legacyAPI, + }; + }; + + describe('POST /api/spaces/_copy_saved_objects', () => { + it(`returns http/403 when the license is invalid`, async () => { + const { copyToSpace } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'post', + }); + + const response = await copyToSpace.routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); + + it(`uses a Saved Objects Client instance without the spaces wrapper`, async () => { + const payload = { + spaces: ['a-space'], + objects: [], + }; + + const { copyToSpace, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + await copyToSpace.routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(legacyAPI.savedObjects.getScopedSavedObjectsClient).toHaveBeenCalledWith( + expect.any(Object), + { + excludedWrappers: ['spaces'], + } + ); + }); + + it(`requires space IDs to be unique`, async () => { + const payload = { + spaces: ['a-space', 'a-space'], + objects: [], + }; + + const { copyToSpace } = await setup(); + + expect(() => + copyToSpace.routeValidation.body!.validate(payload) + ).toThrowErrorMatchingInlineSnapshot(`"[spaces]: duplicate space ids are not allowed"`); + }); + + it(`requires well-formed space IDS`, async () => { + const payload = { + spaces: ['a-space', 'a-space-invalid-!@#$%^&*()'], + objects: [], + }; + + const { copyToSpace } = await setup(); + + expect(() => + copyToSpace.routeValidation.body!.validate(payload) + ).toThrowErrorMatchingInlineSnapshot( + `"[spaces.1]: lower case, a-z, 0-9, \\"_\\", and \\"-\\" are allowed"` + ); + }); + + it(`requires objects to be unique`, async () => { + const payload = { + spaces: ['a-space'], + objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], + }; + + const { copyToSpace } = await setup(); + + expect(() => + copyToSpace.routeValidation.body!.validate(payload) + ).toThrowErrorMatchingInlineSnapshot(`"[objects]: duplicate objects are not allowed"`); + }); + + it('does not allow namespace agnostic types to be copied (via "supportedTypes" property)', async () => { + const payload = { + spaces: ['a-space'], + objects: [{ type: 'globalType', id: 'bar' }, { type: 'visualization', id: 'bar' }], + }; + + const { copyToSpace, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await copyToSpace.routeHandler( + mockRouteContext, + request, + kibanaResponseFactory + ); + + const { status } = response; + + expect(status).toEqual(200); + expect(legacyAPI.savedObjects.importExport.importSavedObjects).toHaveBeenCalledTimes(1); + const [importCallOptions] = (legacyAPI.savedObjects.importExport + .importSavedObjects as any).mock.calls[0]; + + expect(importCallOptions).toMatchObject({ + namespace: 'a-space', + supportedTypes: ['visualization', 'dashboard', 'index-pattern'], + }); + }); + + it('copies to multiple spaces', async () => { + const payload = { + spaces: ['a-space', 'b-space'], + objects: [{ type: 'visualization', id: 'bar' }], + }; + + const { copyToSpace, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await copyToSpace.routeHandler( + mockRouteContext, + request, + kibanaResponseFactory + ); + + const { status } = response; + + expect(status).toEqual(200); + expect(legacyAPI.savedObjects.importExport.importSavedObjects).toHaveBeenCalledTimes(2); + const [firstImportCallOptions] = (legacyAPI.savedObjects.importExport + .importSavedObjects as any).mock.calls[0]; + + expect(firstImportCallOptions).toMatchObject({ + namespace: 'a-space', + }); + + const [secondImportCallOptions] = (legacyAPI.savedObjects.importExport + .importSavedObjects as any).mock.calls[1]; + + expect(secondImportCallOptions).toMatchObject({ + namespace: 'b-space', + }); + }); + }); + + describe('POST /api/spaces/_resolve_copy_saved_objects_errors', () => { + it(`returns http/403 when the license is invalid`, async () => { + const { resolveConflicts } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'post', + }); + + const response = await resolveConflicts.routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); + + it(`uses a Saved Objects Client instance without the spaces wrapper`, async () => { + const payload = { + retries: { + ['a-space']: [ + { + type: 'visualization', + id: 'bar', + overwrite: true, + }, + ], + }, + objects: [{ type: 'visualization', id: 'bar' }], + }; + + const { resolveConflicts, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + await resolveConflicts.routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(legacyAPI.savedObjects.getScopedSavedObjectsClient).toHaveBeenCalledWith( + expect.any(Object), + { + excludedWrappers: ['spaces'], + } + ); + }); + + it(`requires objects to be unique`, async () => { + const payload = { + retries: {}, + objects: [{ type: 'foo', id: 'bar' }, { type: 'foo', id: 'bar' }], + }; + + const { resolveConflicts } = await setup(); + + expect(() => + resolveConflicts.routeValidation.body!.validate(payload) + ).toThrowErrorMatchingInlineSnapshot(`"[objects]: duplicate objects are not allowed"`); + }); + + it(`requires well-formed space ids`, async () => { + const payload = { + retries: { + ['invalid-space-id!@#$%^&*()']: [ + { + type: 'foo', + id: 'bar', + overwrite: true, + }, + ], + }, + objects: [{ type: 'foo', id: 'bar' }], + }; + + const { resolveConflicts } = await setup(); + + expect(() => + resolveConflicts.routeValidation.body!.validate(payload) + ).toThrowErrorMatchingInlineSnapshot( + `"[key(\\"invalid-space-id!@#$%^&*()\\")]: Invalid space id: invalid-space-id!@#$%^&*()"` + ); + }); + + it('does not allow namespace agnostic types to be copied (via "supportedTypes" property)', async () => { + const payload = { + retries: { + ['a-space']: [ + { + type: 'visualization', + id: 'bar', + overwrite: true, + }, + { + type: 'globalType', + id: 'bar', + overwrite: true, + }, + ], + }, + objects: [ + { + type: 'globalType', + id: 'bar', + }, + { type: 'visualization', id: 'bar' }, + ], + }; + + const { resolveConflicts, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await resolveConflicts.routeHandler( + mockRouteContext, + request, + kibanaResponseFactory + ); + + const { status } = response; + + expect(status).toEqual(200); + expect(legacyAPI.savedObjects.importExport.resolveImportErrors).toHaveBeenCalledTimes(1); + const [resolveImportErrorsCallOptions] = (legacyAPI.savedObjects.importExport + .resolveImportErrors as any).mock.calls[0]; + + expect(resolveImportErrorsCallOptions).toMatchObject({ + namespace: 'a-space', + supportedTypes: ['visualization', 'dashboard', 'index-pattern'], + }); + }); + + it('resolves conflicts for multiple spaces', async () => { + const payload = { + objects: [{ type: 'visualization', id: 'bar' }], + retries: { + ['a-space']: [ + { + type: 'visualization', + id: 'bar', + overwrite: true, + }, + ], + ['b-space']: [ + { + type: 'globalType', + id: 'bar', + overwrite: true, + }, + ], + }, + }; + + const { resolveConflicts, legacyAPI } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await resolveConflicts.routeHandler( + mockRouteContext, + request, + kibanaResponseFactory + ); + + const { status } = response; + + expect(status).toEqual(200); + expect(legacyAPI.savedObjects.importExport.resolveImportErrors).toHaveBeenCalledTimes(2); + const [resolveImportErrorsFirstCallOptions] = (legacyAPI.savedObjects.importExport + .resolveImportErrors as any).mock.calls[0]; + + expect(resolveImportErrorsFirstCallOptions).toMatchObject({ + namespace: 'a-space', + supportedTypes: ['visualization', 'dashboard', 'index-pattern'], + }); + + const [resolveImportErrorsSecondCallOptions] = (legacyAPI.savedObjects.importExport + .resolveImportErrors as any).mock.calls[1]; + + expect(resolveImportErrorsSecondCallOptions).toMatchObject({ + namespace: 'b-space', + supportedTypes: ['visualization', 'dashboard', 'index-pattern'], + }); + }); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.ts b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.ts new file mode 100644 index 0000000000000..040a0552c38be --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/copy_to_space.ts @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import _ from 'lodash'; +import { SavedObject } from 'src/core/server'; +import { + copySavedObjectsToSpacesFactory, + resolveCopySavedObjectsToSpacesConflictsFactory, +} from '../../../lib/copy_to_spaces'; +import { ExternalRouteDeps } from '.'; +import { COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS } from '../../../lib/copy_to_spaces/copy_to_spaces'; +import { SPACE_ID_REGEX } from '../../../lib/space_schema'; +import { createLicensedRouteHandler } from '../../lib'; + +type SavedObjectIdentifier = Pick; + +const areObjectsUnique = (objects: SavedObjectIdentifier[]) => + _.uniq(objects, (o: SavedObjectIdentifier) => `${o.type}:${o.id}`).length === objects.length; + +export function initCopyToSpacesApi(deps: ExternalRouteDeps) { + const { externalRouter, spacesService, getSavedObjects } = deps; + + externalRouter.post( + { + path: '/api/spaces/_copy_saved_objects', + options: { + tags: ['access:copySavedObjectsToSpaces'], + }, + validate: { + body: schema.object({ + spaces: schema.arrayOf( + schema.string({ + validate: value => { + if (!SPACE_ID_REGEX.test(value)) { + return `lower case, a-z, 0-9, "_", and "-" are allowed`; + } + }, + }), + { + validate: spaceIds => { + if (_.uniq(spaceIds).length !== spaceIds.length) { + return 'duplicate space ids are not allowed'; + } + }, + } + ), + objects: schema.arrayOf( + schema.object({ + type: schema.string(), + id: schema.string(), + }), + { + validate: objects => { + if (!areObjectsUnique(objects)) { + return 'duplicate objects are not allowed'; + } + }, + } + ), + includeReferences: schema.boolean({ defaultValue: false }), + overwrite: schema.boolean({ defaultValue: false }), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const savedObjectsClient = getSavedObjects().getScopedSavedObjectsClient( + request, + COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS + ); + const copySavedObjectsToSpaces = copySavedObjectsToSpacesFactory( + savedObjectsClient, + getSavedObjects() + ); + const { spaces: destinationSpaceIds, objects, includeReferences, overwrite } = request.body; + const sourceSpaceId = spacesService.getSpaceId(request); + const copyResponse = await copySavedObjectsToSpaces(sourceSpaceId, destinationSpaceIds, { + objects, + includeReferences, + overwrite, + }); + return response.ok({ body: copyResponse }); + }) + ); + + externalRouter.post( + { + path: '/api/spaces/_resolve_copy_saved_objects_errors', + options: { + tags: ['access:copySavedObjectsToSpaces'], + }, + validate: { + body: schema.object({ + retries: schema.recordOf( + schema.string({ + validate: spaceId => { + if (!SPACE_ID_REGEX.test(spaceId)) { + return `Invalid space id: ${spaceId}`; + } + }, + }), + schema.arrayOf( + schema.object({ + type: schema.string(), + id: schema.string(), + overwrite: schema.boolean({ defaultValue: false }), + }) + ) + ), + objects: schema.arrayOf( + schema.object({ + type: schema.string(), + id: schema.string(), + }), + { + validate: objects => { + if (!areObjectsUnique(objects)) { + return 'duplicate objects are not allowed'; + } + }, + } + ), + includeReferences: schema.boolean({ defaultValue: false }), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const savedObjectsClient = getSavedObjects().getScopedSavedObjectsClient( + request, + COPY_TO_SPACES_SAVED_OBJECTS_CLIENT_OPTS + ); + const resolveCopySavedObjectsToSpacesConflicts = resolveCopySavedObjectsToSpacesConflictsFactory( + savedObjectsClient, + getSavedObjects() + ); + const { objects, includeReferences, retries } = request.body; + const sourceSpaceId = spacesService.getSpaceId(request); + const resolveConflictsResponse = await resolveCopySavedObjectsToSpacesConflicts( + sourceSpaceId, + { + objects, + includeReferences, + retries, + } + ); + return response.ok({ body: resolveConflictsResponse }); + }) + ); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts new file mode 100644 index 0000000000000..e341bd3e4bcbb --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.test.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContext, + mockRouteContextWithInvalidLicense, +} from '../__fixtures__'; +import { CoreSetup, IRouter, kibanaResponseFactory } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServiceMock, + httpServerMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { initDeleteSpacesApi } from './delete'; +import { RouteSchemas } from 'src/core/server/http/router/route'; +import { ObjectType } from '@kbn/config-schema'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('Spaces Public API', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initDeleteSpacesApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + const [routeDefinition, routeHandler] = router.delete.mock.calls[0]; + + return { + routeValidation: routeDefinition.validate as RouteSchemas, + routeHandler, + }; + }; + + it('requires a space id as part of the path', async () => { + const { routeValidation } = await setup(); + expect(() => routeValidation.params!.validate({})).toThrowErrorMatchingInlineSnapshot( + `"[id]: expected value of type [string] but got [undefined]"` + ); + }); + + it(`deletes the space`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'a-space', + }, + method: 'delete', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(204); + }); + + it(`returns http/403 when the license is invalid`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'a-space', + }, + method: 'delete', + }); + + const response = await routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); + + it('throws when deleting a non-existent space', async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'not-a-space', + }, + method: 'delete', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(404); + }); + + it(`DELETE spaces/{id}' cannot delete reserved spaces`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'default', + }, + method: 'delete', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status, payload } = response; + + expect(status).toEqual(400); + expect(payload.message).toEqual('This Space cannot be deleted because it is reserved.'); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts new file mode 100644 index 0000000000000..536efdc1de649 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { wrapError } from '../../../lib/errors'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { ExternalRouteDeps } from '.'; +import { createLicensedRouteHandler } from '../../lib'; + +export function initDeleteSpacesApi(deps: ExternalRouteDeps) { + const { externalRouter, getSavedObjects, spacesService } = deps; + + externalRouter.delete( + { + path: '/api/spaces/space/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const { SavedObjectsClient } = getSavedObjects(); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); + + const id = request.params.id; + + try { + await spacesClient.delete(id); + } catch (error) { + if (SavedObjectsClient.errors.isNotFoundError(error)) { + return response.notFound(); + } + return response.customError(wrapError(error)); + } + + return response.noContent(); + }) + ); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts new file mode 100644 index 0000000000000..69c4f16d4ca80 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/get.test.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContextWithInvalidLicense, + mockRouteContext, +} from '../__fixtures__'; +import { initGetSpaceApi } from './get'; +import { CoreSetup, IRouter, kibanaResponseFactory } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServiceMock, + httpServerMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('GET space', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initGetSpaceApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + return { + routeHandler: router.get.mock.calls[0][1], + }; + }; + + it(`returns http/403 when the license is invalid`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'get', + }); + + const response = await routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); + + it(`returns the space with that id`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'default', + }, + method: 'get', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toEqual(200); + expect(response.payload).toEqual(spaces.find(s => s.id === 'default')); + }); + + it(`'GET spaces/{id}' returns 404 when retrieving a non-existent space`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'not-a-space', + }, + method: 'get', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toEqual(404); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts new file mode 100644 index 0000000000000..7643ec811db71 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { wrapError } from '../../../lib/errors'; +import { ExternalRouteDeps } from '.'; +import { createLicensedRouteHandler } from '../../lib'; + +export function initGetSpaceApi(deps: ExternalRouteDeps) { + const { externalRouter, spacesService, getSavedObjects } = deps; + + externalRouter.get( + { + path: '/api/spaces/space/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const spaceId = request.params.id; + + const { SavedObjectsClient } = getSavedObjects(); + const spacesClient = await spacesService.scopedClient(request); + + try { + const space = await spacesClient.get(spaceId); + return response.ok({ body: space }); + } catch (error) { + if (SavedObjectsClient.errors.isNotFoundError(error)) { + return response.notFound(); + } + return response.customError(wrapError(error)); + } + }) + ); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts new file mode 100644 index 0000000000000..fd31b7d084c0e --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.test.ts @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContext, + mockRouteContextWithInvalidLicense, +} from '../__fixtures__'; +import { CoreSetup, kibanaResponseFactory, IRouter } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServiceMock, + httpServerMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { initGetAllSpacesApi } from './get_all'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('GET /spaces/space', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initGetAllSpacesApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + return { + routeHandler: router.get.mock.calls[0][1], + }; + }; + + it(`returns all available spaces`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'get', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toEqual(200); + expect(response.payload).toEqual(spaces); + }); + + it(`returns all available spaces with the 'any' purpose`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + query: { + purpose: 'any', + }, + method: 'get', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toEqual(200); + expect(response.payload).toEqual(spaces); + }); + + it(`returns all available spaces with the 'copySavedObjectsIntoSpace' purpose`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + query: { + purpose: 'copySavedObjectsIntoSpace', + }, + method: 'get', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toEqual(200); + expect(response.payload).toEqual(spaces); + }); + + it(`returns http/403 when the license is invalid`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'get', + }); + + const response = await routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts new file mode 100644 index 0000000000000..cd1e03eb10b0a --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { Space } from '../../../../common/model/space'; +import { wrapError } from '../../../lib/errors'; +import { ExternalRouteDeps } from '.'; +import { createLicensedRouteHandler } from '../../lib'; + +export function initGetAllSpacesApi(deps: ExternalRouteDeps) { + const { externalRouter, log, spacesService } = deps; + + externalRouter.get( + { + path: '/api/spaces/space', + validate: { + query: schema.object({ + purpose: schema.oneOf( + [schema.literal('any'), schema.literal('copySavedObjectsIntoSpace')], + { + defaultValue: 'any', + } + ), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + log.debug(`Inside GET /api/spaces/space`); + + const purpose = request.query.purpose; + + const spacesClient = await spacesService.scopedClient(request); + + let spaces: Space[]; + + try { + log.debug(`Attempting to retrieve all spaces for ${purpose} purpose`); + spaces = await spacesClient.getAll(purpose); + log.debug(`Retrieved ${spaces.length} spaces for ${purpose} purpose`); + } catch (error) { + log.debug(`Error retrieving spaces for ${purpose} purpose: ${error}`); + return response.customError(wrapError(error)); + } + + return response.ok({ body: spaces }); + }) + ); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/index.ts b/x-pack/plugins/spaces/server/routes/api/external/index.ts new file mode 100644 index 0000000000000..60b0170ee04a7 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/index.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Logger, SavedObjectsLegacyService, IRouter } from 'src/core/server'; +import { initDeleteSpacesApi } from './delete'; +import { initGetSpaceApi } from './get'; +import { initGetAllSpacesApi } from './get_all'; +import { initPostSpacesApi } from './post'; +import { initPutSpacesApi } from './put'; +import { SpacesServiceSetup } from '../../../spaces_service/spaces_service'; +import { initCopyToSpacesApi } from './copy_to_space'; + +export interface ExternalRouteDeps { + externalRouter: IRouter; + getSavedObjects: () => SavedObjectsLegacyService; + spacesService: SpacesServiceSetup; + log: Logger; +} + +export function initExternalSpacesApi(deps: ExternalRouteDeps) { + initDeleteSpacesApi(deps); + initGetSpaceApi(deps); + initGetAllSpacesApi(deps); + initPostSpacesApi(deps); + initPutSpacesApi(deps); + initCopyToSpacesApi(deps); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.test.ts b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts new file mode 100644 index 0000000000000..f874f96833350 --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/post.test.ts @@ -0,0 +1,179 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContext, + mockRouteContextWithInvalidLicense, +} from '../__fixtures__'; +import { CoreSetup, kibanaResponseFactory, IRouter } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServerMock, + httpServiceMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { initPostSpacesApi } from './post'; +import { RouteSchemas } from 'src/core/server/http/router/route'; +import { ObjectType } from '@kbn/config-schema'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('Spaces Public API', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initPostSpacesApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + const [routeDefinition, routeHandler] = router.post.mock.calls[0]; + + return { + routeValidation: routeDefinition.validate as RouteSchemas, + routeHandler, + savedObjectsRepositoryMock, + }; + }; + + it('should create a new space with the provided ID', async () => { + const payload = { + id: 'my-space-id', + name: 'my new space', + description: 'with a description', + disabledFeatures: ['foo'], + }; + + const { routeHandler, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.create).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.create).toHaveBeenCalledWith( + 'space', + { name: 'my new space', description: 'with a description', disabledFeatures: ['foo'] }, + { id: 'my-space-id' } + ); + }); + + it(`returns http/403 when the license is invalid`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'post', + }); + + const response = await routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); + + it('should not allow a space to be updated', async () => { + const payload = { + id: 'a-space', + name: 'my updated space', + description: 'with a description', + }; + + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status, payload: responsePayload } = response; + + expect(status).toEqual(409); + expect(responsePayload.message).toEqual('space conflict'); + }); + + it('should not require disabledFeatures to be specified', async () => { + const payload = { + id: 'my-space-id', + name: 'my new space', + description: 'with a description', + }; + + const { routeValidation, routeHandler, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + body: routeValidation.body!.validate(payload), + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.create).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.create).toHaveBeenCalledWith( + 'space', + { name: 'my new space', description: 'with a description', disabledFeatures: [] }, + { id: 'my-space-id' } + ); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts new file mode 100644 index 0000000000000..3a24df8b7270e --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import Boom from 'boom'; +import { wrapError } from '../../../lib/errors'; +import { spaceSchema } from '../../../lib/space_schema'; +import { ExternalRouteDeps } from '.'; +import { createLicensedRouteHandler } from '../../lib'; + +export function initPostSpacesApi(deps: ExternalRouteDeps) { + const { externalRouter, log, spacesService, getSavedObjects } = deps; + + externalRouter.post( + { + path: '/api/spaces/space', + validate: { + body: spaceSchema, + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + log.debug(`Inside POST /api/spaces/space`); + const { SavedObjectsClient } = getSavedObjects(); + const spacesClient = await spacesService.scopedClient(request); + + const space = request.body; + + try { + log.debug(`Attempting to create space`); + const createdSpace = await spacesClient.create(space); + return response.ok({ body: createdSpace }); + } catch (error) { + if (SavedObjectsClient.errors.isConflictError(error)) { + const { body } = wrapError( + Boom.conflict(`A space with the identifier ${space.id} already exists.`) + ); + return response.conflict({ body }); + } + log.debug(`Error creating space: ${error}`); + return response.customError(wrapError(error)); + } + }) + ); +} diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.test.ts b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts new file mode 100644 index 0000000000000..b06bb41fe8b6b --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/put.test.ts @@ -0,0 +1,219 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as Rx from 'rxjs'; +import { + createSpaces, + createLegacyAPI, + createMockSavedObjectsRepository, + mockRouteContext, + mockRouteContextWithInvalidLicense, +} from '../__fixtures__'; +import { CoreSetup, IRouter, kibanaResponseFactory } from 'src/core/server'; +import { + loggingServiceMock, + elasticsearchServiceMock, + httpServiceMock, + httpServerMock, +} from 'src/core/server/mocks'; +import { SpacesService } from '../../../spaces_service'; +import { createOptionalPlugin } from '../../../../../../legacy/server/lib/optional_plugin'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { SpacesClient } from '../../../lib/spaces_client'; +import { initPutSpacesApi } from './put'; +import { RouteSchemas } from 'src/core/server/http/router/route'; +import { ObjectType } from '@kbn/config-schema'; +import { spacesConfig } from '../../../lib/__fixtures__'; + +describe('PUT /api/spaces/space', () => { + const spacesSavedObjects = createSpaces(); + const spaces = spacesSavedObjects.map(s => ({ id: s.id, ...s.attributes })); + + const setup = async () => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + + const legacyAPI = createLegacyAPI({ spaces }); + + const savedObjectsRepositoryMock = createMockSavedObjectsRepository(spacesSavedObjects); + + const log = loggingServiceMock.create().get('spaces'); + + const service = new SpacesService(log, () => legacyAPI); + const spacesService = await service.setup({ + http: (httpService as unknown) as CoreSetup['http'], + elasticsearch: elasticsearchServiceMock.createSetupContract(), + getSecurity: () => + createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + getSpacesAuditLogger: () => ({} as SpacesAuditLogger), + config$: Rx.of(spacesConfig), + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + savedObjectsRepositoryMock, + spacesConfig, + savedObjectsRepositoryMock, + req + ) + ); + }); + + initPutSpacesApi({ + externalRouter: router, + getSavedObjects: () => legacyAPI.savedObjects, + log, + spacesService, + }); + + const [routeDefinition, routeHandler] = router.put.mock.calls[0]; + + return { + routeValidation: routeDefinition.validate as RouteSchemas, + routeHandler, + savedObjectsRepositoryMock, + }; + }; + + it('should update an existing space with the provided ID', async () => { + const payload = { + id: 'a-space', + name: 'my updated space', + description: 'with a description', + disabledFeatures: [], + }; + + const { routeHandler, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: payload.id, + }, + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledWith('space', 'a-space', { + name: 'my updated space', + description: 'with a description', + disabledFeatures: [], + }); + }); + + it('should allow an empty description', async () => { + const payload = { + id: 'a-space', + name: 'my updated space', + description: '', + disabledFeatures: ['foo'], + }; + + const { routeHandler, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: payload.id, + }, + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledWith('space', 'a-space', { + name: 'my updated space', + description: '', + disabledFeatures: ['foo'], + }); + }); + + it('should not require disabledFeatures', async () => { + const payload = { + id: 'a-space', + name: 'my updated space', + description: '', + }; + + const { routeHandler, routeValidation, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: payload.id, + }, + body: routeValidation.body!.validate(payload), + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledWith('space', 'a-space', { + name: 'my updated space', + description: '', + disabledFeatures: [], + }); + }); + + it('should not allow a new space to be created', async () => { + const payload = { + id: 'a-new-space', + name: 'my new space', + description: 'with a description', + }; + + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: payload.id, + }, + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(404); + }); + + it(`returns http/403 when the license is invalid`, async () => { + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + method: 'post', + }); + + const response = await routeHandler( + mockRouteContextWithInvalidLicense, + request, + kibanaResponseFactory + ); + + expect(response.status).toEqual(403); + expect(response.payload).toEqual({ + message: 'License is invalid for spaces', + }); + }); +}); diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts new file mode 100644 index 0000000000000..4c19b0bd2edda --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { Space } from '../../../../common/model/space'; +import { wrapError } from '../../../lib/errors'; +import { spaceSchema } from '../../../lib/space_schema'; +import { ExternalRouteDeps } from '.'; +import { createLicensedRouteHandler } from '../../lib'; + +export function initPutSpacesApi(deps: ExternalRouteDeps) { + const { externalRouter, spacesService, getSavedObjects } = deps; + + externalRouter.put( + { + path: '/api/spaces/space/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + body: spaceSchema, + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const { SavedObjectsClient } = getSavedObjects(); + const spacesClient = await spacesService.scopedClient(request); + + const space = request.body; + const id = request.params.id; + + let result: Space; + try { + result = await spacesClient.update(id, { ...space }); + } catch (error) { + if (SavedObjectsClient.errors.isNotFoundError(error)) { + return response.notFound(); + } + return response.customError(wrapError(error)); + } + + return response.ok({ body: result }); + }) + ); +} diff --git a/x-pack/legacy/plugins/spaces/server/routes/lib/convert_saved_object_to_space.test.ts b/x-pack/plugins/spaces/server/routes/lib/convert_saved_object_to_space.test.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/routes/lib/convert_saved_object_to_space.test.ts rename to x-pack/plugins/spaces/server/routes/lib/convert_saved_object_to_space.test.ts diff --git a/x-pack/legacy/plugins/spaces/server/routes/lib/convert_saved_object_to_space.ts b/x-pack/plugins/spaces/server/routes/lib/convert_saved_object_to_space.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/routes/lib/convert_saved_object_to_space.ts rename to x-pack/plugins/spaces/server/routes/lib/convert_saved_object_to_space.ts diff --git a/x-pack/legacy/plugins/spaces/server/routes/lib/index.ts b/x-pack/plugins/spaces/server/routes/lib/index.ts similarity index 81% rename from x-pack/legacy/plugins/spaces/server/routes/lib/index.ts rename to x-pack/plugins/spaces/server/routes/lib/index.ts index af67388792565..068ff67d3d136 100644 --- a/x-pack/legacy/plugins/spaces/server/routes/lib/index.ts +++ b/x-pack/plugins/spaces/server/routes/lib/index.ts @@ -5,4 +5,4 @@ */ export { convertSavedObjectToSpace } from './convert_saved_object_to_space'; -export { getSpaceById } from './get_space_by_id'; +export { createLicensedRouteHandler } from './licensed_route_handler'; diff --git a/x-pack/plugins/spaces/server/routes/lib/licensed_route_handler.ts b/x-pack/plugins/spaces/server/routes/lib/licensed_route_handler.ts new file mode 100644 index 0000000000000..a3bc2fa71fefe --- /dev/null +++ b/x-pack/plugins/spaces/server/routes/lib/licensed_route_handler.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandler } from 'src/core/server'; +import { ObjectType } from '@kbn/config-schema'; +import { LICENSE_STATUS } from '../../../../licensing/server/constants'; + +export const createLicensedRouteHandler = < + P extends ObjectType, + Q extends ObjectType, + B extends ObjectType +>( + handler: RequestHandler +) => { + const licensedRouteHandler: RequestHandler = (context, request, responseToolkit) => { + const { license } = context.licensing; + const licenseCheck = license.check('spaces', 'basic'); + if ( + licenseCheck.check === LICENSE_STATUS.Unavailable || + licenseCheck.check === LICENSE_STATUS.Invalid + ) { + return responseToolkit.forbidden({ body: { message: licenseCheck.message! } }); + } + + return handler(context, request, responseToolkit); + }; + + return licensedRouteHandler; +}; diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/index.ts b/x-pack/plugins/spaces/server/spaces_service/index.ts similarity index 100% rename from x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/index.ts rename to x-pack/plugins/spaces/server/spaces_service/index.ts diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.mock.ts similarity index 76% rename from x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts rename to x-pack/plugins/spaces/server/spaces_service/spaces_service.mock.ts index bcbd377d60ee1..6f21330368f8d 100644 --- a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.mock.ts @@ -5,12 +5,12 @@ */ import { SpacesServiceSetup } from './spaces_service'; -import { spacesClientMock } from '../../lib/spaces_client/spaces_client.mock'; -import { DEFAULT_SPACE_ID } from '../../../common/constants'; -import { namespaceToSpaceId, spaceIdToNamespace } from '../../lib/utils/namespace'; +import { spacesClientMock } from '../lib/spaces_client/spaces_client.mock'; +import { DEFAULT_SPACE_ID } from '../../common/constants'; +import { namespaceToSpaceId, spaceIdToNamespace } from '../lib/utils/namespace'; const createSetupContractMock = (spaceId = DEFAULT_SPACE_ID) => { - const setupContract: SpacesServiceSetup = { + const setupContract: jest.Mocked = { getSpaceId: jest.fn().mockReturnValue(spaceId), isInDefaultSpace: jest.fn().mockReturnValue(spaceId === DEFAULT_SPACE_ID), getBasePath: jest.fn().mockReturnValue(''), diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts similarity index 92% rename from x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts rename to x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts index 817474dc0fb3a..d0910e00586ed 100644 --- a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts @@ -6,16 +6,18 @@ import * as Rx from 'rxjs'; import { SpacesService } from './spaces_service'; import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks'; -import { SpacesAuditLogger } from '../../lib/audit_logger'; +import { SpacesAuditLogger } from '../lib/audit_logger'; import { KibanaRequest, SavedObjectsLegacyService, SavedObjectsErrorHelpers, + HttpServiceSetup, } from 'src/core/server'; -import { DEFAULT_SPACE_ID } from '../../../common/constants'; -import { createOptionalPlugin } from '../../../../../server/lib/optional_plugin'; +import { DEFAULT_SPACE_ID } from '../../common/constants'; +import { getSpaceIdFromPath } from '../../common/lib/spaces_url_parser'; import { LegacyAPI } from '../plugin'; -import { getSpaceIdFromPath } from '../../../common'; +import { createOptionalPlugin } from '../../../../legacy/server/lib/optional_plugin'; +import { spacesConfig } from '../lib/__fixtures__'; const mockLogger = { trace: jest.fn(), @@ -29,9 +31,7 @@ const mockLogger = { const createService = async (serverBasePath: string = '') => { const legacyAPI = { - legacyConfig: { - serverBasePath, - }, + legacyConfig: {}, savedObjects: ({ getSavedObjectsRepository: jest.fn().mockReturnValue({ get: jest.fn().mockImplementation((type, id) => { @@ -63,6 +63,9 @@ const createService = async (serverBasePath: string = '') => { const spacesService = new SpacesService(mockLogger, () => legacyAPI); const httpSetup = coreMock.createSetup().http; + httpSetup.basePath = { + serverBasePath, + } as HttpServiceSetup['basePath']; httpSetup.basePath.get = jest.fn().mockImplementation((request: KibanaRequest) => { const spaceId = getSpaceIdFromPath(request.url.path); @@ -75,8 +78,8 @@ const createService = async (serverBasePath: string = '') => { const spacesServiceSetup = await spacesService.setup({ http: httpSetup, elasticsearch: elasticsearchServiceMock.createSetupContract(), - config$: Rx.of({ maxSpaces: 10 }), - security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), + config$: Rx.of(spacesConfig), + getSecurity: () => createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), getSpacesAuditLogger: () => new SpacesAuditLogger({}), }); diff --git a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts similarity index 81% rename from x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts rename to x-pack/plugins/spaces/server/spaces_service/spaces_service.ts index 08ebc2cb31748..83a62f91ade01 100644 --- a/x-pack/legacy/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.ts @@ -8,15 +8,15 @@ import { map, take } from 'rxjs/operators'; import { Observable, Subscription, combineLatest } from 'rxjs'; import { Legacy } from 'kibana'; import { Logger, KibanaRequest, CoreSetup } from 'src/core/server'; -import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; -import { DEFAULT_SPACE_ID } from '../../../common/constants'; -import { SecurityPlugin } from '../../../../security'; -import { SpacesClient } from '../../lib/spaces_client'; -import { SpacesConfigType } from '../config'; -import { namespaceToSpaceId, spaceIdToNamespace } from '../../lib/utils/namespace'; +import { SecurityPlugin } from '../../../../legacy/plugins/security'; +import { OptionalPlugin } from '../../../../legacy/server/lib/optional_plugin'; import { LegacyAPI } from '../plugin'; -import { Space } from '../../../common/model/space'; -import { getSpaceIdFromPath, addSpaceIdToPath } from '../../../common'; +import { SpacesClient } from '../lib/spaces_client'; +import { ConfigType } from '../config'; +import { getSpaceIdFromPath, addSpaceIdToPath } from '../../common/lib/spaces_url_parser'; +import { DEFAULT_SPACE_ID } from '../../common/constants'; +import { spaceIdToNamespace, namespaceToSpaceId } from '../lib/utils/namespace'; +import { Space } from '../../common/model/space'; type RequestFacade = KibanaRequest | Legacy.Request; @@ -39,8 +39,8 @@ export interface SpacesServiceSetup { interface SpacesServiceDeps { http: CoreSetup['http']; elasticsearch: CoreSetup['elasticsearch']; - security: OptionalPlugin; - config$: Observable; + getSecurity: () => OptionalPlugin; + config$: Observable; getSpacesAuditLogger(): any; } @@ -52,7 +52,7 @@ export class SpacesService { public async setup({ http, elasticsearch, - security, + getSecurity, config$, getSpacesAuditLogger, }: SpacesServiceDeps): Promise { @@ -64,7 +64,7 @@ export class SpacesService { ? (request as Record).getBasePath() : http.basePath.get(request); - const spaceId = getSpaceIdFromPath(basePath, this.getServerBasePath()); + const spaceId = getSpaceIdFromPath(basePath, http.basePath.serverBasePath); return spaceId; }; @@ -85,6 +85,8 @@ export class SpacesService { ['space'] ); + const security = getSecurity(); + const authorization = security.isEnabled ? security.authorization : null; return new SpacesClient( @@ -110,7 +112,7 @@ export class SpacesService { if (!spaceId) { throw new TypeError(`spaceId is required to retrieve base path`); } - return addSpaceIdToPath(this.getServerBasePath(), spaceId); + return addSpaceIdToPath(http.basePath.serverBasePath, spaceId); }, isInDefaultSpace: (request: RequestFacade) => { const spaceId = getSpaceId(request); @@ -134,8 +136,4 @@ export class SpacesService { this.configSubscription$ = undefined; } } - - private getServerBasePath() { - return this.getLegacyAPI().legacyConfig.serverBasePath; - } } diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index c453b5aaa71f5..76956401122bc 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7256,27 +7256,18 @@ "xpack.ml.dataframe.analytics.create.errorGettingDataFrameIndexNames": "获取现有索引名称时发生错误:", "xpack.ml.dataframe.analytics.create.errorGettingIndexPatternTitles": "获取现有索引模式标题时发生错误:", "xpack.ml.dataframe.analytics.create.errorStartingDataFrameAnalyticsJob": "启动数据帧分析作业时发生错误:", - "xpack.ml.dataframe.analytics.create.indexPatternTitleError": "具有此名称的索引模式已存在。", "xpack.ml.dataframe.analytics.create.jobIdExistsError": "已存在具有此 ID 的分析作业。", "xpack.ml.dataframe.analytics.create.jobIdInputAriaLabel": "选择唯一的分析作业 ID。", "xpack.ml.dataframe.analytics.create.jobIdInvalidError": "只能包含小写字母数字字符(a-z 和 0-9)、连字符和下划线,并且必须以字母数字字符开头和结尾。", "xpack.ml.dataframe.analytics.create.jobIdLabel": "作业 ID", "xpack.ml.dataframe.analytics.create.jobIdPlaceholder": "作业 ID", - "xpack.ml.dataframe.analytics.create.jobTypeHelpText": "离群值检测作业需要映射为类表数据结构的源索引,将仅分析数值和布尔值字段。请使用“{advancedEditorButton}”应用定制选项,如模型内存限制和分析类型。您不能从高级编辑器切换回到此表单。", "xpack.ml.dataframe.analytics.create.jobTypeLabel": "作业类型", - "xpack.ml.dataframe.analytics.create.modalCancelButton": "取消", - "xpack.ml.dataframe.analytics.create.modalCloseButton": "关闭", - "xpack.ml.dataframe.analytics.create.modalCreateButton": "创建", - "xpack.ml.dataframe.analytics.create.modalHeaderTitle": "创建分析作业", - "xpack.ml.dataframe.analytics.create.modalStartButton": "开始", - "xpack.ml.dataframe.analytics.create.outlierDetectionText": "离群值检测", "xpack.ml.dataframe.analytics.create.sourceIndexHelpText": "此索引模式不包含任何数值类型字段。分析作业可能无法提供任何离群值。", "xpack.ml.dataframe.analytics.create.sourceIndexInputAriaLabel": "源索引模式或搜索。", "xpack.ml.dataframe.analytics.create.sourceIndexInvalidError": "源索引名称无效,其不能包含空格或以下字符:{characterList}", "xpack.ml.dataframe.analytics.create.sourceIndexLabel": "源索引", "xpack.ml.dataframe.analytics.create.sourceIndexPlaceholder": "选择源索引模式或已保存搜索。", "xpack.ml.dataframe.analytics.create.startDataFrameAnalyticsSuccessMessage": "分析作业 {jobId} 已启动。", - "xpack.ml.dataframe.analytics.create.switchToAdvancedEditorButton": "高级编辑器", "xpack.ml.dataframe.analytics.exploration.experimentalBadgeLabel": "实验性", "xpack.ml.dataframe.analytics.exploration.experimentalBadgeTooltipContent": "数据帧分析为实验功能。我们很乐意听取您的反馈意见。", "xpack.ml.dataframe.analytics.exploration.fieldSelection": "已选择 {selectedFieldsLength, number} 个{docFieldsCount, plural, one {字段} other {字段}},共 {docFieldsCount, number} 个", diff --git a/x-pack/test/api_integration/apis/spaces/space_attributes.ts b/x-pack/test/api_integration/apis/spaces/space_attributes.ts index b3863cd82835c..8b68ad8c9ccca 100644 --- a/x-pack/test/api_integration/apis/spaces/space_attributes.ts +++ b/x-pack/test/api_integration/apis/spaces/space_attributes.ts @@ -63,13 +63,8 @@ export default function({ getService }: FtrProviderContext) { }) .expect(400, { error: 'Bad Request', - message: - 'child "imageUrl" fails because ["imageUrl" with value "invalidImage" fails to match the Image URL should start with \'data:image\' pattern]', + message: "[request body.imageUrl]: must start with 'data:image'", statusCode: 400, - validation: { - keys: ['imageUrl'], - source: 'payload', - }, }); }); }); diff --git a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts index 61f1ab2190a09..85e877912ab6c 100644 --- a/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/common/suites/copy_to_space.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; import { SuperTest } from 'supertest'; import { EsArchiver } from 'src/es_archiver'; -import { DEFAULT_SPACE_ID } from '../../../../legacy/plugins/spaces/common/constants'; -import { CopyResponse } from '../../../../legacy/plugins/spaces/server/lib/copy_to_spaces'; +import { DEFAULT_SPACE_ID } from '../../../../plugins/spaces/common/constants'; +import { CopyResponse } from '../../../../plugins/spaces/server/lib/copy_to_spaces'; import { getUrlPrefix } from '../lib/space_test_utils'; import { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; diff --git a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts index 5d32d9f8adcf2..20b4d024803d7 100644 --- a/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts +++ b/x-pack/test/spaces_api_integration/common/suites/resolve_copy_to_space_conflicts.ts @@ -9,7 +9,7 @@ import { SuperTest } from 'supertest'; import { EsArchiver } from 'src/es_archiver'; import { SavedObject } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../../legacy/plugins/spaces/common/constants'; -import { CopyResponse } from '../../../../legacy/plugins/spaces/server/lib/copy_to_spaces'; +import { CopyResponse } from '../../../../plugins/spaces/server/lib/copy_to_spaces'; import { getUrlPrefix } from '../lib/space_test_utils'; import { DescribeFn, TestDefinitionAuthentication } from '../lib/types'; diff --git a/yarn.lock b/yarn.lock index 0a7a6f6d17cc9..8567d135248f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1153,10 +1153,10 @@ tabbable "^1.1.0" uuid "^3.1.0" -"@elastic/eui@14.4.0": - version "14.4.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-14.4.0.tgz#ac09a476798dcdb1005616cccc149eda23ea2a90" - integrity sha512-dR7lYwUaIRXZjlUrJBq8GcGLPh6QfM3waQxUFI8lOnMVayJe3OOMNADCn8Oty6wNYIOrBWzZbW6w4bzInWF6oA== +"@elastic/eui@14.5.0": + version "14.5.0" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-14.5.0.tgz#1b27559cd644403e2692cab1549082cbd3421dab" + integrity sha512-QpmfO6Unt4evb4P18CyWzassLFrw/4CUPFYZXQK12IChDOs6GrwQ6xZM8f0wjN/NXwjRjlWzMhtCWHYmrI6NGg== dependencies: "@types/lodash" "^4.14.116" "@types/numeral" "^0.0.25"