mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Add server rendering service to enable standalone route rendering (#52161)
* Add server rendering service to enable standalone route rendering * Update renovate config * Move legacy rendering functionality to legacy service * Use config for exposed variable in new platform * Lint changes from rebase * Rebase artifact * Remove RenderingProvider, add tests for legacy vars implementation, review notes * Add UI app functionality to legacy service * Update rendering snapshots * Update docs * Fix up functional tests * Clean up legacy types * Revise types from reverting injected metadata changes * Update translations and broken tests * Mock legacy internals in legacy tests * Add missing doc types * Rename InternalRenderOptions to LegacyRenderOptions * Remove extraneous legacy exports, review nits * Functional tests fixes * Rebase, attempt CI test fixes * Only allow specified appIds in testbed rendering integration test * Update snapshot names * Review nits
This commit is contained in:
parent
3ed5264cc3
commit
054ec7036d
95 changed files with 3399 additions and 1397 deletions
|
@ -9,5 +9,5 @@ Search for objects
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
find: <T extends SavedObjectAttributes>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "perPage" | "sortField" | "fields" | "searchFields" | "hasReference" | "defaultSearchOperator">) => Promise<SavedObjectsFindResponsePublic<T>>;
|
||||
find: <T extends SavedObjectAttributes>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "fields" | "searchFields" | "defaultSearchOperator" | "hasReference" | "sortField" | "perPage">) => Promise<SavedObjectsFindResponsePublic<T>>;
|
||||
```
|
||||
|
|
|
@ -20,7 +20,7 @@ export declare class SavedObjectsClient
|
|||
| [bulkGet](./kibana-plugin-public.savedobjectsclient.bulkget.md) | | <code>(objects?: {</code><br/><code> id: string;</code><br/><code> type: string;</code><br/><code> }[]) => Promise<SavedObjectsBatchResponse<SavedObjectAttributes>></code> | Returns an array of objects by id |
|
||||
| [create](./kibana-plugin-public.savedobjectsclient.create.md) | | <code><T extends SavedObjectAttributes>(type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise<SimpleSavedObject<T>></code> | Persists an object |
|
||||
| [delete](./kibana-plugin-public.savedobjectsclient.delete.md) | | <code>(type: string, id: string) => Promise<{}></code> | Deletes an object |
|
||||
| [find](./kibana-plugin-public.savedobjectsclient.find.md) | | <code><T extends SavedObjectAttributes>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "perPage" | "sortField" | "fields" | "searchFields" | "hasReference" | "defaultSearchOperator">) => Promise<SavedObjectsFindResponsePublic<T>></code> | Search for objects |
|
||||
| [find](./kibana-plugin-public.savedobjectsclient.find.md) | | <code><T extends SavedObjectAttributes>(options: Pick<SavedObjectFindOptionsServer, "search" | "filter" | "type" | "page" | "fields" | "searchFields" | "defaultSearchOperator" | "hasReference" | "sortField" | "perPage">) => Promise<SavedObjectsFindResponsePublic<T>></code> | Search for objects |
|
||||
| [get](./kibana-plugin-public.savedobjectsclient.get.md) | | <code><T extends SavedObjectAttributes>(type: string, id: string) => Promise<SimpleSavedObject<T>></code> | Fetches a single object |
|
||||
|
||||
## Methods
|
||||
|
|
|
@ -9,5 +9,5 @@ returns `basePath` value, specific for an incoming request.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
(request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest) => string;
|
||||
get: (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest) => string;
|
||||
```
|
||||
|
|
|
@ -9,5 +9,5 @@ sets `basePath` value, specific for an incoming request.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
(request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest, requestSpecificBasePath: string) => void;
|
||||
set: (request: KibanaRequest<unknown, unknown, unknown, any> | LegacyRequest, requestSpecificBasePath: string) => void;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IRenderOptions](./kibana-plugin-server.irenderoptions.md) > [includeUserSettings](./kibana-plugin-server.irenderoptions.includeusersettings.md)
|
||||
|
||||
## IRenderOptions.includeUserSettings property
|
||||
|
||||
Set whether to output user settings in the page metadata. `true` by default.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
includeUserSettings?: boolean;
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IRenderOptions](./kibana-plugin-server.irenderoptions.md)
|
||||
|
||||
## IRenderOptions interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IRenderOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [includeUserSettings](./kibana-plugin-server.irenderoptions.includeusersettings.md) | <code>boolean</code> | Set whether to output user settings in the page metadata. <code>true</code> by default. |
|
||||
|
|
@ -9,5 +9,5 @@ Wrap a router handler to catch and converts legacy boom errors to proper custom
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
<P, Q, B>(handler: RequestHandler<P, Q, B>) => RequestHandler<P, Q, B>;
|
||||
handleLegacyErrors: <P, Q, B>(handler: RequestHandler<P, Q, B>) => RequestHandler<P, Q, B>;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IScopedRenderingClient](./kibana-plugin-server.iscopedrenderingclient.md)
|
||||
|
||||
## IScopedRenderingClient interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IScopedRenderingClient
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [render(options)](./kibana-plugin-server.iscopedrenderingclient.render.md) | Generate a <code>KibanaResponse</code> which renders an HTML page bootstrapped with the <code>core</code> bundle. Intended as a response body for HTTP route handlers. |
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [IScopedRenderingClient](./kibana-plugin-server.iscopedrenderingclient.md) > [render](./kibana-plugin-server.iscopedrenderingclient.render.md)
|
||||
|
||||
## IScopedRenderingClient.render() method
|
||||
|
||||
Generate a `KibanaResponse` which renders an HTML page bootstrapped with the `core` bundle. Intended as a response body for HTTP route handlers.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
render(options?: IRenderOptions): Promise<string>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| options | <code>IRenderOptions</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<string>`
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
```ts
|
||||
router.get(
|
||||
{ path: '/', validate: false },
|
||||
(context, request, response) =>
|
||||
response.ok({
|
||||
body: await context.core.rendering.render(),
|
||||
headers: {
|
||||
'content-security-policy': context.core.http.csp.header,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
```
|
||||
|
|
@ -7,7 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
core: InternalCoreSetup & {
|
||||
plugins: PluginsServiceSetup;
|
||||
};
|
||||
core: LegacyCoreSetup;
|
||||
```
|
||||
|
|
|
@ -18,6 +18,6 @@ export interface LegacyServiceSetupDeps
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [core](./kibana-plugin-server.legacyservicesetupdeps.core.md) | <code>InternalCoreSetup & {</code><br/><code> plugins: PluginsServiceSetup;</code><br/><code> }</code> | |
|
||||
| [core](./kibana-plugin-server.legacyservicesetupdeps.core.md) | <code>LegacyCoreSetup</code> | |
|
||||
| [plugins](./kibana-plugin-server.legacyservicesetupdeps.plugins.md) | <code>Record<string, unknown></code> | |
|
||||
|
||||
|
|
|
@ -7,7 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
core: InternalCoreStart & {
|
||||
plugins: PluginsServiceStart;
|
||||
};
|
||||
core: LegacyCoreStart;
|
||||
```
|
||||
|
|
|
@ -18,6 +18,6 @@ export interface LegacyServiceStartDeps
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [core](./kibana-plugin-server.legacyservicestartdeps.core.md) | <code>InternalCoreStart & {</code><br/><code> plugins: PluginsServiceStart;</code><br/><code> }</code> | |
|
||||
| [core](./kibana-plugin-server.legacyservicestartdeps.core.md) | <code>LegacyCoreStart</code> | |
|
||||
| [plugins](./kibana-plugin-server.legacyservicestartdeps.plugins.md) | <code>Record<string, unknown></code> | |
|
||||
|
||||
|
|
|
@ -70,7 +70,9 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [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) | |
|
||||
| [IRenderOptions](./kibana-plugin-server.irenderoptions.md) | |
|
||||
| [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. |
|
||||
| [IScopedRenderingClient](./kibana-plugin-server.iscopedrenderingclient.md) | |
|
||||
| [IUiSettingsClient](./kibana-plugin-server.iuisettingsclient.md) | Server-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. |
|
||||
| [KibanaRequestRoute](./kibana-plugin-server.kibanarequestroute.md) | Request specific route information exposed to a handler. |
|
||||
| [LegacyRequest](./kibana-plugin-server.legacyrequest.md) | |
|
||||
|
@ -91,7 +93,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [PluginManifest](./kibana-plugin-server.pluginmanifest.md) | Describes the set of required and optional properties plugin can define in its mandatory JSON manifest file. |
|
||||
| [PluginsServiceSetup](./kibana-plugin-server.pluginsservicesetup.md) | |
|
||||
| [PluginsServiceStart](./kibana-plugin-server.pluginsservicestart.md) | |
|
||||
| [RequestHandlerContext](./kibana-plugin-server.requesthandlercontext.md) | Plugin specific context passed to a route handler.<!-- -->Provides the following clients: - [savedObjects.client](./kibana-plugin-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [elasticsearch.dataClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [elasticsearch.adminClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch admin client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request |
|
||||
| [RequestHandlerContext](./kibana-plugin-server.requesthandlercontext.md) | Plugin specific context passed to a route handler.<!-- -->Provides the following clients: - [rendering](./kibana-plugin-server.iscopedrenderingclient.md) - Rendering client which uses the data of the incoming request - [savedObjects.client](./kibana-plugin-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [elasticsearch.dataClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [elasticsearch.adminClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch admin client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request |
|
||||
| [RouteConfig](./kibana-plugin-server.routeconfig.md) | Route specific configuration. |
|
||||
| [RouteConfigOptions](./kibana-plugin-server.routeconfigoptions.md) | Additional route options. |
|
||||
| [RouteConfigOptionsBody](./kibana-plugin-server.routeconfigoptionsbody.md) | Additional body options for a route |
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
```typescript
|
||||
core: {
|
||||
rendering: IScopedRenderingClient;
|
||||
savedObjects: {
|
||||
client: SavedObjectsClientContract;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Plugin specific context passed to a route handler.
|
||||
|
||||
Provides the following clients: - [savedObjects.client](./kibana-plugin-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [elasticsearch.dataClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [elasticsearch.adminClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch admin client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request
|
||||
Provides the following clients: - [rendering](./kibana-plugin-server.iscopedrenderingclient.md) - Rendering client which uses the data of the incoming request - [savedObjects.client](./kibana-plugin-server.savedobjectsclient.md) - Saved Objects client which uses the credentials of the incoming request - [elasticsearch.dataClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch data client which uses the credentials of the incoming request - [elasticsearch.adminClient](./kibana-plugin-server.scopedclusterclient.md) - Elasticsearch admin client which uses the credentials of the incoming request - [uiSettings.client](./kibana-plugin-server.iuisettingsclient.md) - uiSettings client which uses the credentials of the incoming request
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
@ -18,5 +18,5 @@ export interface RequestHandlerContext
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [core](./kibana-plugin-server.requesthandlercontext.core.md) | <code>{</code><br/><code> savedObjects: {</code><br/><code> client: SavedObjectsClientContract;</code><br/><code> };</code><br/><code> elasticsearch: {</code><br/><code> dataClient: IScopedClusterClient;</code><br/><code> adminClient: IScopedClusterClient;</code><br/><code> };</code><br/><code> uiSettings: {</code><br/><code> client: IUiSettingsClient;</code><br/><code> };</code><br/><code> }</code> | |
|
||||
| [core](./kibana-plugin-server.requesthandlercontext.core.md) | <code>{</code><br/><code> rendering: IScopedRenderingClient;</code><br/><code> savedObjects: {</code><br/><code> client: SavedObjectsClientContract;</code><br/><code> };</code><br/><code> elasticsearch: {</code><br/><code> dataClient: IScopedClusterClient;</code><br/><code> adminClient: IScopedClusterClient;</code><br/><code> };</code><br/><code> uiSettings: {</code><br/><code> client: IUiSettingsClient;</code><br/><code> };</code><br/><code> }</code> | |
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ A schema created with `@kbn/config-schema` that every request will be validated
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
RouteValidatorFullConfig<P, Q, B> | false;
|
||||
validate: RouteValidatorFullConfig<P, Q, B> | false;
|
||||
```
|
||||
|
||||
## Remarks
|
||||
|
|
|
@ -9,7 +9,7 @@ Constructs a new instance of the `RouteValidationError` class
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor(error;: Error | string, path?: string[];)
|
||||
constructor(error: Error | string, path?: string[]);
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
(error: Error | string, path?: string[]) => {
|
||||
RouteValidationError;
|
||||
badRequest: (error: Error | string, path?: string[]) => {
|
||||
error: RouteValidationError;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
<T>(value: T) => {
|
||||
T;
|
||||
ok: <T>(value: T) => {
|
||||
value: T;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -13,6 +13,5 @@ unsafe?: {
|
|||
params?: boolean;
|
||||
query?: boolean;
|
||||
body?: boolean;
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
|
|
@ -26,7 +26,7 @@ import { first, mapTo, filter, map, take } from 'rxjs/operators';
|
|||
import { REPO_ROOT } from '@kbn/dev-utils';
|
||||
import { FSWatcher } from 'chokidar';
|
||||
|
||||
import { LegacyConfig } from '../../core/server/legacy/config';
|
||||
import { LegacyConfig } from '../../core/server/legacy';
|
||||
import { BasePathProxyServer } from '../../core/server/http';
|
||||
|
||||
// @ts-ignore
|
||||
|
|
|
@ -80,9 +80,6 @@ export interface InjectedMetadataParams {
|
|||
user?: Record<string, UserProvidedValues>;
|
||||
};
|
||||
};
|
||||
apm: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,18 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { UiNavLink } from './ui_nav_link';
|
||||
import { Config } from './config';
|
||||
|
||||
export function uiNavLinksMixin(kbnServer, server) {
|
||||
const uiApps = server.getAllUiApps();
|
||||
type ConfigMock = jest.Mocked<Config>;
|
||||
|
||||
const { navLinkSpecs = [] } = kbnServer.uiExports;
|
||||
const createConfigMock = (): ConfigMock => ({
|
||||
has: jest.fn(),
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
getFlattenedPaths: jest.fn(),
|
||||
toRaw: jest.fn(),
|
||||
});
|
||||
|
||||
const fromSpecs = navLinkSpecs.map(navLinkSpec => new UiNavLink(navLinkSpec));
|
||||
|
||||
const fromApps = uiApps.map(app => app.getNavLink()).filter(Boolean);
|
||||
|
||||
const uiNavLinks = fromSpecs.concat(fromApps).sort((a, b) => a.getOrder() - b.getOrder());
|
||||
|
||||
server.decorate('server', 'getUiNavLinks', () => uiNavLinks.slice(0));
|
||||
}
|
||||
export const configMock = {
|
||||
create: createConfigMock,
|
||||
};
|
|
@ -20,6 +20,7 @@
|
|||
import { Server } from 'hapi';
|
||||
import { CspConfig } from '../csp';
|
||||
import { mockRouter } from './router/router.mock';
|
||||
import { configMock } from '../config/config.mock';
|
||||
import { InternalHttpServiceSetup } from './types';
|
||||
import { HttpService } from './http_service';
|
||||
import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';
|
||||
|
@ -28,13 +29,14 @@ import { sessionStorageMock } from './cookie_session_storage.mocks';
|
|||
import { OnPostAuthToolkit } from './lifecycle/on_post_auth';
|
||||
import { OnPreResponseToolkit } from './lifecycle/on_pre_response';
|
||||
|
||||
type BasePathMocked = jest.Mocked<InternalHttpServiceSetup['basePath']>;
|
||||
export type HttpServiceSetupMock = jest.Mocked<InternalHttpServiceSetup> & {
|
||||
basePath: jest.Mocked<InternalHttpServiceSetup['basePath']>;
|
||||
basePath: BasePathMocked;
|
||||
};
|
||||
|
||||
const createBasePathMock = (): jest.Mocked<InternalHttpServiceSetup['basePath']> => ({
|
||||
serverBasePath: '/mock-server-basepath',
|
||||
get: jest.fn(),
|
||||
const createBasePathMock = (serverBasePath = '/mock-server-basepath'): BasePathMocked => ({
|
||||
serverBasePath,
|
||||
get: jest.fn().mockReturnValue(serverBasePath),
|
||||
set: jest.fn(),
|
||||
prepend: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
|
@ -44,9 +46,12 @@ const createSetupContractMock = () => {
|
|||
const setupContract: HttpServiceSetupMock = {
|
||||
// we can mock other hapi server methods when we need it
|
||||
server: ({
|
||||
name: 'http-server-test',
|
||||
version: 'kibana',
|
||||
route: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
config: jest.fn().mockReturnValue(configMock.create()),
|
||||
} as unknown) as jest.MockedClass<Server>,
|
||||
createCookieSessionStorageFactory: jest.fn(),
|
||||
registerOnPreAuth: jest.fn(),
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
import { ElasticsearchServiceSetup, IScopedClusterClient } from './elasticsearch';
|
||||
import { HttpServiceSetup } from './http';
|
||||
import { IScopedRenderingClient } from './rendering';
|
||||
import { PluginsServiceSetup, PluginsServiceStart, PluginOpaqueId } from './plugins';
|
||||
import { ContextSetup } from './context';
|
||||
import { IUiSettingsClient, UiSettingsServiceSetup, UiSettingsServiceStart } from './ui_settings';
|
||||
|
@ -149,6 +150,7 @@ export {
|
|||
SessionCookieValidationResult,
|
||||
SessionStorageFactory,
|
||||
} from './http';
|
||||
export { RenderingServiceSetup, IRenderOptions, LegacyRenderOptions } from './rendering';
|
||||
export { Logger, LoggerFactory, LogMeta, LogRecord, LogLevel } from './logging';
|
||||
|
||||
export {
|
||||
|
@ -229,12 +231,21 @@ export {
|
|||
SavedObjectsMigrationVersion,
|
||||
} from './types';
|
||||
|
||||
export { LegacyServiceSetupDeps, LegacyServiceStartDeps } from './legacy';
|
||||
export {
|
||||
LegacyServiceSetupDeps,
|
||||
LegacyServiceStartDeps,
|
||||
LegacyServiceDiscoverPlugins,
|
||||
LegacyConfig,
|
||||
LegacyUiExports,
|
||||
LegacyInternals,
|
||||
} from './legacy';
|
||||
|
||||
/**
|
||||
* Plugin specific context passed to a route handler.
|
||||
*
|
||||
* Provides the following clients:
|
||||
* - {@link IScopedRenderingClient | rendering} - Rendering client
|
||||
* which uses the data of the incoming request
|
||||
* - {@link SavedObjectsClient | savedObjects.client} - Saved Objects client
|
||||
* which uses the credentials of the incoming request
|
||||
* - {@link ScopedClusterClient | elasticsearch.dataClient} - Elasticsearch
|
||||
|
@ -248,6 +259,7 @@ export { LegacyServiceSetupDeps, LegacyServiceStartDeps } from './legacy';
|
|||
*/
|
||||
export interface RequestHandlerContext {
|
||||
core: {
|
||||
rendering: IScopedRenderingClient;
|
||||
savedObjects: {
|
||||
client: SavedObjectsClientContract;
|
||||
};
|
||||
|
@ -301,6 +313,7 @@ export {
|
|||
CapabilitiesSetup,
|
||||
CapabilitiesStart,
|
||||
ContextSetup,
|
||||
IScopedRenderingClient,
|
||||
PluginsServiceSetup,
|
||||
PluginsServiceStart,
|
||||
PluginOpaqueId,
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
|
||||
import { ContextSetup } from './context';
|
||||
import { InternalElasticsearchServiceSetup } from './elasticsearch';
|
||||
import { InternalHttpServiceSetup } from './http';
|
||||
import { InternalUiSettingsServiceSetup, InternalUiSettingsServiceStart } from './ui_settings';
|
||||
import { ContextSetup } from './context';
|
||||
import {
|
||||
InternalSavedObjectsServiceStart,
|
||||
InternalSavedObjectsServiceSetup,
|
||||
InternalSavedObjectsServiceStart,
|
||||
} from './saved_objects';
|
||||
import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
|
||||
import { InternalUiSettingsServiceSetup, InternalUiSettingsServiceStart } from './ui_settings';
|
||||
import { UuidServiceSetup } from './uuid';
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import { getUnusedConfigKeys } from './get_unused_config_keys';
|
||||
import { ConfigService } from '../../config';
|
||||
import { LegacyServiceDiscoverPlugins } from '../legacy_service';
|
||||
import { LegacyServiceDiscoverPlugins } from '../types';
|
||||
import { CriticalError } from '../../errors';
|
||||
|
||||
export async function ensureValidConfiguration(
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyPluginSpec } from '../plugins/find_legacy_plugin_specs';
|
||||
import { LegacyConfig } from './types';
|
||||
import { LegacyPluginSpec, LegacyConfig, LegacyVars } from '../types';
|
||||
import { getUnusedConfigKeys } from './get_unused_config_keys';
|
||||
|
||||
describe('getUnusedConfigKeys', () => {
|
||||
|
@ -26,7 +25,7 @@ describe('getUnusedConfigKeys', () => {
|
|||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
const getConfig = (values: Record<string, any> = {}): LegacyConfig =>
|
||||
const getConfig = (values: LegacyVars = {}): LegacyConfig =>
|
||||
({
|
||||
get: () => values as any,
|
||||
} as LegacyConfig);
|
||||
|
|
|
@ -22,8 +22,7 @@ import { difference, get, set } from 'lodash';
|
|||
import { getTransform } from '../../../../legacy/deprecation/index';
|
||||
import { unset, getFlattenedObject } from '../../../../legacy/utils';
|
||||
import { hasConfigPathIntersection } from '../../config';
|
||||
import { LegacyPluginSpec } from '../plugins/find_legacy_plugin_specs';
|
||||
import { LegacyConfig } from './types';
|
||||
import { LegacyPluginSpec, LegacyConfig, LegacyVars } from '../types';
|
||||
|
||||
const getFlattenedKeys = (object: object) => Object.keys(getFlattenedObject(object));
|
||||
|
||||
|
@ -37,7 +36,7 @@ export async function getUnusedConfigKeys({
|
|||
coreHandledConfigPaths: string[];
|
||||
pluginSpecs: LegacyPluginSpec[];
|
||||
disabledPluginSpecs: LegacyPluginSpec[];
|
||||
settings: Record<string, any>;
|
||||
settings: LegacyVars;
|
||||
legacyConfig: LegacyConfig;
|
||||
}) {
|
||||
// transform deprecated plugin settings
|
||||
|
|
|
@ -20,9 +20,3 @@
|
|||
export { ensureValidConfiguration } from './ensure_valid_configuration';
|
||||
export { LegacyObjectToConfigAdapter } from './legacy_object_to_config_adapter';
|
||||
export { convertLegacyDeprecationProvider } from './legacy_deprecation_adapters';
|
||||
export {
|
||||
LegacyConfig,
|
||||
LegacyConfigDeprecation,
|
||||
LegacyConfigDeprecationFactory,
|
||||
LegacyConfigDeprecationProvider,
|
||||
} from './types';
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { convertLegacyDeprecationProvider } from './legacy_deprecation_adapters';
|
||||
import { LegacyConfigDeprecationProvider } from './types';
|
||||
import { ConfigDeprecation } from '../../config';
|
||||
import { configDeprecationFactory } from '../../config/deprecation/deprecation_factory';
|
||||
import { applyDeprecations } from '../../config/deprecation/apply_deprecations';
|
||||
import { LegacyConfigDeprecationProvider } from '../types';
|
||||
import { convertLegacyDeprecationProvider } from './legacy_deprecation_adapters';
|
||||
|
||||
jest.spyOn(configDeprecationFactory, 'unusedFromRoot');
|
||||
jest.spyOn(configDeprecationFactory, 'renameFromRoot');
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
import { ConfigDeprecation, ConfigDeprecationProvider } from '../../config/deprecation';
|
||||
import { LegacyConfigDeprecation, LegacyConfigDeprecationProvider } from './index';
|
||||
import { configDeprecationFactory } from '../../config/deprecation/deprecation_factory';
|
||||
import { LegacyConfigDeprecation, LegacyConfigDeprecationProvider } from '../types';
|
||||
|
||||
const convertLegacyDeprecation = (
|
||||
legacyDeprecation: LegacyConfigDeprecation
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import { ConfigPath } from '../../config';
|
||||
import { ObjectToConfigAdapter } from '../../config/object_to_config_adapter';
|
||||
import { LegacyVars } from '../types';
|
||||
|
||||
/**
|
||||
* Represents logging config supported by the legacy platform.
|
||||
|
@ -77,7 +78,7 @@ export class LegacyObjectToConfigAdapter extends ObjectToConfigAdapter {
|
|||
};
|
||||
}
|
||||
|
||||
private static transformPlugins(configValue: Record<string, any>) {
|
||||
private static transformPlugins(configValue: LegacyVars) {
|
||||
// These properties are the only ones we use from the existing `plugins` config node
|
||||
// since `scanDirs` isn't respected by new platform plugin discovery.
|
||||
return {
|
||||
|
@ -94,7 +95,7 @@ export class LegacyObjectToConfigAdapter extends ObjectToConfigAdapter {
|
|||
case 'server':
|
||||
return LegacyObjectToConfigAdapter.transformServer(configValue);
|
||||
case 'plugins':
|
||||
return LegacyObjectToConfigAdapter.transformPlugins(configValue as Record<string, any>);
|
||||
return LegacyObjectToConfigAdapter.transformPlugins(configValue as LegacyVars);
|
||||
default:
|
||||
return configValue;
|
||||
}
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* New platform representation of the legacy configuration (KibanaConfig)
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface LegacyConfig {
|
||||
get<T>(key?: string): T;
|
||||
has(key: string): boolean;
|
||||
set(key: string, value: any): void;
|
||||
set(config: Record<string, any>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation factory used for
|
||||
* legacy plugin deprecations.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface LegacyConfigDeprecationFactory {
|
||||
rename(oldKey: string, newKey: string): LegacyConfigDeprecation;
|
||||
unused(unusedKey: string): LegacyConfigDeprecation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export type LegacyConfigDeprecation = (
|
||||
settings: Record<string, any>,
|
||||
log: (msg: string) => void
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation provider.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export type LegacyConfigDeprecationProvider = (
|
||||
factory: LegacyConfigDeprecationFactory
|
||||
) => LegacyConfigDeprecation[] | Promise<LegacyConfigDeprecation[]>;
|
|
@ -18,6 +18,10 @@
|
|||
*/
|
||||
|
||||
/** @internal */
|
||||
export { LegacyObjectToConfigAdapter, ensureValidConfiguration, LegacyConfig } from './config';
|
||||
export { LegacyObjectToConfigAdapter, ensureValidConfiguration } from './config';
|
||||
/** @internal */
|
||||
export { LegacyService, LegacyServiceSetupDeps, LegacyServiceStartDeps } from './legacy_service';
|
||||
export { LegacyInternals } from './legacy_internals';
|
||||
/** @internal */
|
||||
export { LegacyService, ILegacyService } from './legacy_service';
|
||||
/** @internal */
|
||||
export * from './types';
|
||||
|
|
211
src/core/server/legacy/legacy_internals.test.ts
Normal file
211
src/core/server/legacy/legacy_internals.test.ts
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Server } from 'hapi';
|
||||
|
||||
import { configMock } from '../config/config.mock';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { httpServerMock } from '../http/http_server.mocks';
|
||||
import { findLegacyPluginSpecsMock } from './legacy_service.test.mocks';
|
||||
import { LegacyInternals } from './legacy_internals';
|
||||
import { ILegacyInternals, LegacyConfig, LegacyVars, LegacyUiExports } from './types';
|
||||
|
||||
function varsProvider(vars: LegacyVars, configValue?: any) {
|
||||
return {
|
||||
fn: jest.fn().mockReturnValue(vars),
|
||||
pluginSpec: {
|
||||
readConfigValue: jest.fn().mockReturnValue(configValue),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('LegacyInternals', () => {
|
||||
describe('getInjectedUiAppVars()', () => {
|
||||
let uiExports: LegacyUiExports;
|
||||
let config: LegacyConfig;
|
||||
let server: Server;
|
||||
let legacyInternals: ILegacyInternals;
|
||||
|
||||
beforeEach(async () => {
|
||||
uiExports = findLegacyPluginSpecsMock().uiExports;
|
||||
config = configMock.create() as any;
|
||||
server = httpServiceMock.createSetupContract().server;
|
||||
legacyInternals = new LegacyInternals(uiExports, config, server);
|
||||
});
|
||||
|
||||
it('gets with no injectors', async () => {
|
||||
await expect(legacyInternals.getInjectedUiAppVars('core')).resolves.toMatchInlineSnapshot(
|
||||
`Object {}`
|
||||
);
|
||||
});
|
||||
|
||||
it('gets with no matching injectors', async () => {
|
||||
const injector = jest.fn().mockResolvedValue({ not: 'core' });
|
||||
legacyInternals.injectUiAppVars('not-core', injector);
|
||||
|
||||
await expect(legacyInternals.getInjectedUiAppVars('core')).resolves.toMatchInlineSnapshot(
|
||||
`Object {}`
|
||||
);
|
||||
expect(injector).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('gets with single matching injector', async () => {
|
||||
const injector = jest.fn().mockResolvedValue({ is: 'core' });
|
||||
legacyInternals.injectUiAppVars('core', injector);
|
||||
|
||||
await expect(legacyInternals.getInjectedUiAppVars('core')).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"is": "core",
|
||||
}
|
||||
`);
|
||||
expect(injector).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('gets with multiple matching injectors', async () => {
|
||||
const injectors = [
|
||||
jest.fn().mockResolvedValue({ is: 'core' }),
|
||||
jest.fn().mockReturnValue({ sync: 'injector' }),
|
||||
jest.fn().mockResolvedValue({ is: 'merged-core' }),
|
||||
];
|
||||
|
||||
injectors.forEach(injector => legacyInternals.injectUiAppVars('core', injector));
|
||||
|
||||
await expect(legacyInternals.getInjectedUiAppVars('core')).resolves.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"is": "merged-core",
|
||||
"sync": "injector",
|
||||
}
|
||||
`);
|
||||
expect(injectors[0]).toHaveBeenCalled();
|
||||
expect(injectors[1]).toHaveBeenCalled();
|
||||
expect(injectors[2]).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVars()', () => {
|
||||
let uiExports: LegacyUiExports;
|
||||
let config: LegacyConfig;
|
||||
let server: Server;
|
||||
let legacyInternals: LegacyInternals;
|
||||
|
||||
beforeEach(async () => {
|
||||
uiExports = findLegacyPluginSpecsMock().uiExports;
|
||||
config = configMock.create() as any;
|
||||
server = httpServiceMock.createSetupContract().server;
|
||||
legacyInternals = new LegacyInternals(uiExports, config, server);
|
||||
});
|
||||
|
||||
it('gets: no default injectors, no injected vars replacers, no ui app injectors, no inject arg', async () => {
|
||||
const vars = await legacyInternals.getVars('core', httpServerMock.createRawRequest());
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`Object {}`);
|
||||
});
|
||||
|
||||
it('gets: with default injectors, no injected vars replacers, no ui app injectors, no inject arg', async () => {
|
||||
uiExports.defaultInjectedVarProviders = [
|
||||
varsProvider({ alpha: 'alpha' }),
|
||||
varsProvider({ gamma: 'gamma' }),
|
||||
varsProvider({ alpha: 'beta' }),
|
||||
];
|
||||
|
||||
const vars = await legacyInternals.getVars('core', httpServerMock.createRawRequest());
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"alpha": "beta",
|
||||
"gamma": "gamma",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('gets: no default injectors, with injected vars replacers, with ui app injectors, no inject arg', async () => {
|
||||
uiExports.injectedVarsReplacers = [
|
||||
jest.fn(async vars => ({ ...vars, added: 'key' })),
|
||||
jest.fn(vars => vars),
|
||||
jest.fn(vars => ({ replaced: 'all' })),
|
||||
jest.fn(async vars => ({ ...vars, added: 'last-key' })),
|
||||
];
|
||||
|
||||
const request = httpServerMock.createRawRequest();
|
||||
const vars = await legacyInternals.getVars('core', request);
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"added": "last-key",
|
||||
"replaced": "all",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('gets: no default injectors, no injected vars replacers, with ui app injectors, no inject arg', async () => {
|
||||
legacyInternals.injectUiAppVars('core', async () => ({ is: 'core' }));
|
||||
legacyInternals.injectUiAppVars('core', () => ({ sync: 'injector' }));
|
||||
legacyInternals.injectUiAppVars('core', async () => ({ is: 'merged-core' }));
|
||||
|
||||
const vars = await legacyInternals.getVars('core', httpServerMock.createRawRequest());
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"is": "merged-core",
|
||||
"sync": "injector",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('gets: no default injectors, no injected vars replacers, no ui app injectors, with inject arg', async () => {
|
||||
const vars = await legacyInternals.getVars('core', httpServerMock.createRawRequest(), {
|
||||
injected: 'arg',
|
||||
});
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"injected": "arg",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('gets: with default injectors, with injected vars replacers, with ui app injectors, with inject arg', async () => {
|
||||
uiExports.defaultInjectedVarProviders = [
|
||||
varsProvider({ alpha: 'alpha' }),
|
||||
varsProvider({ gamma: 'gamma' }),
|
||||
varsProvider({ alpha: 'beta' }),
|
||||
];
|
||||
uiExports.injectedVarsReplacers = [jest.fn(async vars => ({ ...vars, gamma: 'delta' }))];
|
||||
|
||||
legacyInternals.injectUiAppVars('core', async () => ({ is: 'core' }));
|
||||
legacyInternals.injectUiAppVars('core', () => ({ sync: 'injector' }));
|
||||
legacyInternals.injectUiAppVars('core', async () => ({ is: 'merged-core' }));
|
||||
|
||||
const vars = await legacyInternals.getVars('core', httpServerMock.createRawRequest(), {
|
||||
injected: 'arg',
|
||||
sync: 'arg',
|
||||
});
|
||||
|
||||
expect(vars).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"alpha": "beta",
|
||||
"gamma": "delta",
|
||||
"injected": "arg",
|
||||
"is": "merged-core",
|
||||
"sync": "arg",
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
87
src/core/server/legacy/legacy_internals.ts
Normal file
87
src/core/server/legacy/legacy_internals.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Server } from 'hapi';
|
||||
|
||||
import { LegacyRequest } from '../http';
|
||||
import { mergeVars } from './merge_vars';
|
||||
import { ILegacyInternals, LegacyVars, VarsInjector, LegacyConfig, LegacyUiExports } from './types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export class LegacyInternals implements ILegacyInternals {
|
||||
private readonly injectors = new Map<string, Set<VarsInjector>>();
|
||||
private cachedDefaultVars?: LegacyVars;
|
||||
|
||||
constructor(
|
||||
private readonly uiExports: LegacyUiExports,
|
||||
private readonly config: LegacyConfig,
|
||||
private readonly server: Server
|
||||
) {}
|
||||
|
||||
private get defaultVars(): LegacyVars {
|
||||
if (this.cachedDefaultVars) {
|
||||
return this.cachedDefaultVars;
|
||||
}
|
||||
|
||||
const { defaultInjectedVarProviders = [] } = this.uiExports;
|
||||
|
||||
return (this.cachedDefaultVars = defaultInjectedVarProviders.reduce(
|
||||
(vars, { fn, pluginSpec }) =>
|
||||
mergeVars(vars, fn(this.server, pluginSpec.readConfigValue(this.config, []))),
|
||||
{}
|
||||
));
|
||||
}
|
||||
|
||||
private replaceVars(vars: LegacyVars, request: LegacyRequest) {
|
||||
const { injectedVarsReplacers = [] } = this.uiExports;
|
||||
|
||||
return injectedVarsReplacers.reduce(
|
||||
async (injected, replacer) => replacer(await injected, request, this.server),
|
||||
Promise.resolve(vars)
|
||||
);
|
||||
}
|
||||
|
||||
public injectUiAppVars(id: string, injector: VarsInjector) {
|
||||
if (!this.injectors.has(id)) {
|
||||
this.injectors.set(id, new Set());
|
||||
}
|
||||
|
||||
this.injectors.get(id)!.add(injector);
|
||||
}
|
||||
|
||||
public getInjectedUiAppVars(id: string) {
|
||||
return [...(this.injectors.get(id) || [])].reduce(
|
||||
async (promise, injector) => ({
|
||||
...(await promise),
|
||||
...(await injector()),
|
||||
}),
|
||||
Promise.resolve<LegacyVars>({})
|
||||
);
|
||||
}
|
||||
|
||||
public async getVars(id: string, request: LegacyRequest, injected: LegacyVars = {}) {
|
||||
return this.replaceVars(
|
||||
mergeVars(this.defaultVars, await this.getInjectedUiAppVars(id), injected),
|
||||
request
|
||||
);
|
||||
}
|
||||
}
|
|
@ -17,23 +17,33 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyServiceDiscoverPlugins } from './legacy_service';
|
||||
import { LegacyService } from './legacy_service';
|
||||
import { LegacyServiceDiscoverPlugins, LegacyServiceSetupDeps } from './types';
|
||||
|
||||
const createDiscoverMock = () => {
|
||||
const setupContract: DeeplyMockedKeys<LegacyServiceDiscoverPlugins> = {
|
||||
type LegacyServiceMock = jest.Mocked<PublicMethodsOf<LegacyService> & { legacyId: symbol }>;
|
||||
|
||||
const createDiscoverPluginsMock = (): LegacyServiceDiscoverPlugins => ({
|
||||
pluginSpecs: [],
|
||||
disabledPluginSpecs: [],
|
||||
uiExports: {} as any,
|
||||
settings: {},
|
||||
navLinks: [],
|
||||
pluginExtendedConfig: {
|
||||
get: jest.fn(),
|
||||
has: jest.fn(),
|
||||
set: jest.fn(),
|
||||
} as any,
|
||||
};
|
||||
return setupContract;
|
||||
};
|
||||
},
|
||||
disabledPluginSpecs: [],
|
||||
settings: {},
|
||||
});
|
||||
const createLegacyServiceMock = (): LegacyServiceMock => ({
|
||||
legacyId: Symbol(),
|
||||
discoverPlugins: jest.fn().mockResolvedValue(createDiscoverPluginsMock()),
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
});
|
||||
|
||||
export const legacyServiceMock = {
|
||||
createDiscover: createDiscoverMock,
|
||||
create: createLegacyServiceMock,
|
||||
createSetupContract: (deps: LegacyServiceSetupDeps) => createLegacyServiceMock().setup(deps),
|
||||
createDiscoverPlugins: createDiscoverPluginsMock,
|
||||
};
|
||||
|
|
|
@ -17,17 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export const findLegacyPluginSpecsMock = jest
|
||||
.fn()
|
||||
.mockImplementation((settings: Record<string, any>) => ({
|
||||
import { LegacyVars } from './types';
|
||||
|
||||
export const findLegacyPluginSpecsMock = jest.fn().mockImplementation((settings: LegacyVars) => ({
|
||||
pluginSpecs: [],
|
||||
pluginExtendedConfig: {
|
||||
has: jest.fn(),
|
||||
get: jest.fn(() => settings),
|
||||
get: jest.fn().mockReturnValue(settings),
|
||||
set: jest.fn(),
|
||||
},
|
||||
disabledPluginSpecs: [],
|
||||
uiExports: [],
|
||||
uiExports: {},
|
||||
navLinks: [],
|
||||
}));
|
||||
jest.doMock('./plugins/find_legacy_plugin_specs.ts', () => ({
|
||||
findLegacyPluginSpecs: findLegacyPluginSpecsMock,
|
||||
|
|
|
@ -25,7 +25,7 @@ jest.mock('./config/legacy_deprecation_adapters', () => ({
|
|||
import { findLegacyPluginSpecsMock } from './legacy_service.test.mocks';
|
||||
|
||||
import { BehaviorSubject, throwError } from 'rxjs';
|
||||
import { LegacyService, LegacyServiceSetupDeps, LegacyServiceStartDeps } from '.';
|
||||
|
||||
// @ts-ignore: implicit any for JS file
|
||||
import { ClusterManager as MockClusterManager } from '../../../cli/cluster/cluster_manager';
|
||||
import KbnServer from '../../../legacy/server/kbn_server';
|
||||
|
@ -33,7 +33,6 @@ import { Config, Env, ObjectToConfigAdapter } from '../config';
|
|||
import { getEnvOptions } from '../config/__mocks__/env';
|
||||
import { BasePathProxyServer } from '../http';
|
||||
import { DiscoveredPlugin } from '../plugins';
|
||||
import { findLegacyPluginSpecs } from './plugins/find_legacy_plugin_specs';
|
||||
|
||||
import { configServiceMock } from '../config/config_service.mock';
|
||||
import { loggingServiceMock } from '../logging/logging_service.mock';
|
||||
|
@ -42,7 +41,11 @@ import { httpServiceMock } from '../http/http_service.mock';
|
|||
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
||||
import { savedObjectsServiceMock } from '../saved_objects/saved_objects_service.mock';
|
||||
import { capabilitiesServiceMock } from '../capabilities/capabilities_service.mock';
|
||||
import { setupMock as renderingServiceMock } from '../rendering/__mocks__/rendering_service';
|
||||
import { uuidServiceMock } from '../uuid/uuid_service.mock';
|
||||
import { findLegacyPluginSpecs } from './plugins';
|
||||
import { LegacyVars, LegacyServiceSetupDeps, LegacyServiceStartDeps } from './types';
|
||||
import { LegacyService } from './legacy_service';
|
||||
|
||||
const MockKbnServer: jest.Mock<KbnServer> = KbnServer as any;
|
||||
|
||||
|
@ -89,6 +92,7 @@ beforeEach(() => {
|
|||
browserConfigs: new Map(),
|
||||
},
|
||||
},
|
||||
rendering: renderingServiceMock,
|
||||
uuid: uuidSetup,
|
||||
},
|
||||
plugins: { 'plugin-id': 'plugin-value' },
|
||||
|
@ -138,7 +142,7 @@ describe('once LegacyService is set up with connection info', () => {
|
|||
{ path: { autoListen: true }, server: { autoListen: true } }, // Because of the mock, path also gets the value
|
||||
expect.objectContaining({ get: expect.any(Function) }),
|
||||
expect.any(Object),
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: [] }
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: {}, navLinks: [] }
|
||||
);
|
||||
expect(MockKbnServer.mock.calls[0][1].get()).toEqual({
|
||||
path: { autoListen: true },
|
||||
|
@ -168,7 +172,7 @@ describe('once LegacyService is set up with connection info', () => {
|
|||
{ path: { autoListen: false }, server: { autoListen: true } },
|
||||
expect.objectContaining({ get: expect.any(Function) }),
|
||||
expect.any(Object),
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: [] }
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: {}, navLinks: [] }
|
||||
);
|
||||
expect(MockKbnServer.mock.calls[0][1].get()).toEqual({
|
||||
path: { autoListen: false },
|
||||
|
@ -309,7 +313,7 @@ describe('once LegacyService is set up without connection info', () => {
|
|||
{ path: {}, server: { autoListen: true } },
|
||||
expect.objectContaining({ get: expect.any(Function) }),
|
||||
expect.any(Object),
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: [] }
|
||||
{ disabledPluginSpecs: [], pluginSpecs: [], uiExports: {}, navLinks: [] }
|
||||
);
|
||||
expect(MockKbnServer.mock.calls[0][1].get()).toEqual({
|
||||
path: {},
|
||||
|
@ -395,6 +399,7 @@ describe('once LegacyService is set up in `devClusterMaster` mode', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('start', () => {
|
||||
test('Cannot start without setup phase', async () => {
|
||||
const legacyService = new LegacyService({
|
||||
coreId,
|
||||
|
@ -406,6 +411,7 @@ test('Cannot start without setup phase', async () => {
|
|||
`"Legacy service is not setup yet."`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#discoverPlugins()', () => {
|
||||
it('calls findLegacyPluginSpecs with correct parameters', async () => {
|
||||
|
@ -438,7 +444,8 @@ describe('#discoverPlugins()', () => {
|
|||
],
|
||||
pluginExtendedConfig: settings,
|
||||
disabledPluginSpecs: [],
|
||||
uiExports: [],
|
||||
uiExports: {},
|
||||
navLinks: [],
|
||||
}) as any
|
||||
);
|
||||
|
||||
|
@ -469,15 +476,16 @@ test('Sets the server.uuid property on the legacy configuration', async () => {
|
|||
|
||||
const configSetMock = jest.fn();
|
||||
|
||||
findLegacyPluginSpecsMock.mockImplementation((settings: Record<string, any>) => ({
|
||||
findLegacyPluginSpecsMock.mockImplementation((settings: LegacyVars) => ({
|
||||
pluginSpecs: [],
|
||||
pluginExtendedConfig: {
|
||||
has: jest.fn(),
|
||||
get: jest.fn(() => settings),
|
||||
get: jest.fn().mockReturnValue(settings),
|
||||
set: configSetMock,
|
||||
},
|
||||
disabledPluginSpecs: [],
|
||||
uiExports: [],
|
||||
uiExports: {},
|
||||
navLinks: [],
|
||||
}));
|
||||
|
||||
await legacyService.discoverPlugins();
|
||||
|
|
|
@ -19,24 +19,30 @@
|
|||
|
||||
import { combineLatest, ConnectableObservable, EMPTY, Observable, Subscription } from 'rxjs';
|
||||
import { first, map, publishReplay, tap } from 'rxjs/operators';
|
||||
|
||||
import { CoreService } from '../../types';
|
||||
import { CoreSetup, CoreStart } from '../';
|
||||
import { InternalCoreSetup, InternalCoreStart } from '../internal_types';
|
||||
import { SavedObjectsLegacyUiExports } from '../types';
|
||||
import { Config, ConfigDeprecationProvider } from '../config';
|
||||
import { CoreContext } from '../core_context';
|
||||
import { CspConfigType, config as cspConfig } from '../csp';
|
||||
import { DevConfig, DevConfigType, config as devConfig } from '../dev';
|
||||
import { BasePathProxyServer, HttpConfig, HttpConfigType, config as httpConfig } from '../http';
|
||||
import { Logger } from '../logging';
|
||||
import { PluginsServiceSetup, PluginsServiceStart } from '../plugins';
|
||||
import { findLegacyPluginSpecs } from './plugins';
|
||||
import { LegacyPluginSpec } from './plugins/find_legacy_plugin_specs';
|
||||
import { PathConfigType } from '../path';
|
||||
import { LegacyConfig, convertLegacyDeprecationProvider } from './config';
|
||||
import { findLegacyPluginSpecs } from './plugins';
|
||||
import { convertLegacyDeprecationProvider } from './config';
|
||||
import {
|
||||
LegacyServiceSetupDeps,
|
||||
LegacyServiceStartDeps,
|
||||
LegacyPlugins,
|
||||
LegacyServiceDiscoverPlugins,
|
||||
LegacyConfig,
|
||||
LegacyVars,
|
||||
} from './types';
|
||||
import { LegacyInternals } from './legacy_internals';
|
||||
import { CoreSetup, CoreStart } from '..';
|
||||
|
||||
interface LegacyKbnServer {
|
||||
applyLoggingConfiguration: (settings: Readonly<Record<string, any>>) => void;
|
||||
applyLoggingConfiguration: (settings: Readonly<LegacyVars>) => void;
|
||||
listen: () => Promise<void>;
|
||||
ready: () => Promise<void>;
|
||||
close: () => Promise<void>;
|
||||
|
@ -53,43 +59,14 @@ function getLegacyRawConfig(config: Config, pathConfig: PathConfigType) {
|
|||
|
||||
return {
|
||||
...rawConfig,
|
||||
path: pathConfig, // We rely heavily in the default value of 'path.data' in the legacy world and, since it has been moved to NP, it won't show up in RawConfig
|
||||
// We rely heavily in the default value of 'path.data' in the legacy world and,
|
||||
// since it has been moved to NP, it won't show up in RawConfig.
|
||||
path: pathConfig,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyServiceSetupDeps {
|
||||
core: InternalCoreSetup & {
|
||||
plugins: PluginsServiceSetup;
|
||||
};
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyServiceStartDeps {
|
||||
core: InternalCoreStart & {
|
||||
plugins: PluginsServiceStart;
|
||||
};
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface LegacyServiceDiscoverPlugins {
|
||||
pluginSpecs: LegacyPluginSpec[];
|
||||
disabledPluginSpecs: LegacyPluginSpec[];
|
||||
uiExports: SavedObjectsLegacyUiExports;
|
||||
pluginExtendedConfig: LegacyConfig;
|
||||
settings: Record<string, any>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type ILegacyService = Pick<LegacyService, keyof LegacyService>;
|
||||
export type ILegacyService = PublicMethodsOf<LegacyService>;
|
||||
|
||||
/** @internal */
|
||||
export class LegacyService implements CoreService {
|
||||
|
@ -101,16 +78,10 @@ export class LegacyService implements CoreService {
|
|||
private kbnServer?: LegacyKbnServer;
|
||||
private configSubscription?: Subscription;
|
||||
private setupDeps?: LegacyServiceSetupDeps;
|
||||
private update$: ConnectableObservable<[Config, PathConfigType]> | undefined;
|
||||
private legacyRawConfig: LegacyConfig | undefined;
|
||||
private legacyPlugins:
|
||||
| {
|
||||
pluginSpecs: LegacyPluginSpec[];
|
||||
disabledPluginSpecs: LegacyPluginSpec[];
|
||||
uiExports: SavedObjectsLegacyUiExports;
|
||||
}
|
||||
| undefined;
|
||||
private settings: Record<string, any> | undefined;
|
||||
private update$?: ConnectableObservable<[Config, PathConfigType]>;
|
||||
private legacyRawConfig?: LegacyConfig;
|
||||
private legacyPlugins?: LegacyPlugins;
|
||||
private settings?: LegacyVars;
|
||||
|
||||
constructor(private readonly coreContext: CoreContext) {
|
||||
const { logger, configService, env } = coreContext;
|
||||
|
@ -153,12 +124,14 @@ export class LegacyService implements CoreService {
|
|||
pluginExtendedConfig,
|
||||
disabledPluginSpecs,
|
||||
uiExports,
|
||||
navLinks,
|
||||
} = await findLegacyPluginSpecs(this.settings, this.coreContext.logger);
|
||||
|
||||
this.legacyPlugins = {
|
||||
pluginSpecs,
|
||||
disabledPluginSpecs,
|
||||
uiExports,
|
||||
navLinks,
|
||||
};
|
||||
|
||||
const deprecationProviders = await pluginSpecs
|
||||
|
@ -188,6 +161,7 @@ export class LegacyService implements CoreService {
|
|||
pluginSpecs,
|
||||
disabledPluginSpecs,
|
||||
uiExports,
|
||||
navLinks,
|
||||
pluginExtendedConfig,
|
||||
settings: this.settings,
|
||||
};
|
||||
|
@ -195,35 +169,37 @@ export class LegacyService implements CoreService {
|
|||
|
||||
public async setup(setupDeps: LegacyServiceSetupDeps) {
|
||||
this.log.debug('setting up legacy service');
|
||||
if (!this.legacyRawConfig || !this.legacyPlugins || !this.settings) {
|
||||
|
||||
if (!this.legacyPlugins) {
|
||||
throw new Error(
|
||||
'Legacy service has not discovered legacy plugins yet. Ensure LegacyService.discoverPlugins() is called before LegacyService.setup()'
|
||||
);
|
||||
}
|
||||
// propagate the instance uuid to the legacy config, as it was the legacy way to access it.
|
||||
this.legacyRawConfig.set('server.uuid', setupDeps.core.uuid.getInstanceUuid());
|
||||
|
||||
// propagate the instance uuid to the legacy config, as it was the legacy way to access it.
|
||||
this.legacyRawConfig!.set('server.uuid', setupDeps.core.uuid.getInstanceUuid());
|
||||
this.setupDeps = setupDeps;
|
||||
}
|
||||
|
||||
public async start(startDeps: LegacyServiceStartDeps) {
|
||||
const { setupDeps } = this;
|
||||
if (!setupDeps || !this.legacyRawConfig || !this.legacyPlugins || !this.settings) {
|
||||
|
||||
if (!setupDeps || !this.legacyPlugins) {
|
||||
throw new Error('Legacy service is not setup yet.');
|
||||
}
|
||||
|
||||
this.log.debug('starting legacy service');
|
||||
|
||||
// Receive initial config and create kbnServer/ClusterManager.
|
||||
|
||||
if (this.coreContext.env.isDevClusterMaster) {
|
||||
await this.createClusterManager(this.legacyRawConfig);
|
||||
await this.createClusterManager(this.legacyRawConfig!);
|
||||
} else {
|
||||
this.kbnServer = await this.createKbnServer(
|
||||
this.settings,
|
||||
this.legacyRawConfig,
|
||||
this.settings!,
|
||||
this.legacyRawConfig!,
|
||||
setupDeps,
|
||||
startDeps,
|
||||
this.legacyPlugins
|
||||
this.legacyPlugins!
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -263,15 +239,11 @@ export class LegacyService implements CoreService {
|
|||
}
|
||||
|
||||
private async createKbnServer(
|
||||
settings: Record<string, any>,
|
||||
settings: LegacyVars,
|
||||
config: LegacyConfig,
|
||||
setupDeps: LegacyServiceSetupDeps,
|
||||
startDeps: LegacyServiceStartDeps,
|
||||
legacyPlugins: {
|
||||
pluginSpecs: LegacyPluginSpec[];
|
||||
disabledPluginSpecs: LegacyPluginSpec[];
|
||||
uiExports: SavedObjectsLegacyUiExports;
|
||||
}
|
||||
legacyPlugins: LegacyPlugins
|
||||
) {
|
||||
const coreSetup: CoreSetup = {
|
||||
capabilities: setupDeps.core.capabilities,
|
||||
|
@ -338,8 +310,10 @@ export class LegacyService implements CoreService {
|
|||
kibanaMigrator: startDeps.core.savedObjects.migrator,
|
||||
uiPlugins: setupDeps.core.plugins.uiPlugins,
|
||||
elasticsearch: setupDeps.core.elasticsearch,
|
||||
rendering: setupDeps.core.rendering,
|
||||
uiSettings: setupDeps.core.uiSettings,
|
||||
savedObjectsClientProvider: startDeps.core.savedObjects.clientProvider,
|
||||
legacy: new LegacyInternals(legacyPlugins.uiExports, config, setupDeps.core.http.server),
|
||||
},
|
||||
logger: this.coreContext.logger,
|
||||
},
|
||||
|
|
|
@ -21,6 +21,7 @@ import { schema } from '@kbn/config-schema';
|
|||
import { DisposableAppender } from '../../../logging/appenders/appenders';
|
||||
import { LogRecord } from '../../../logging/log_record';
|
||||
import { LegacyLoggingServer } from '../legacy_logging_server';
|
||||
import { LegacyVars } from '../../types';
|
||||
|
||||
/**
|
||||
* Simple appender that just forwards `LogRecord` to the legacy KbnServer log.
|
||||
|
@ -34,7 +35,7 @@ export class LegacyAppender implements DisposableAppender {
|
|||
|
||||
private readonly loggingServer: LegacyLoggingServer;
|
||||
|
||||
constructor(legacyLoggingConfig: Readonly<Record<string, any>>) {
|
||||
constructor(legacyLoggingConfig: Readonly<LegacyVars>) {
|
||||
this.loggingServer = new LegacyLoggingServer(legacyLoggingConfig);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,10 @@ import { Config } from '../../../../legacy/server/config';
|
|||
import { setupLogging } from '../../../../legacy/server/logging';
|
||||
import { LogLevel } from '../../logging/log_level';
|
||||
import { LogRecord } from '../../logging/log_record';
|
||||
import { LegacyVars } from '../../types';
|
||||
|
||||
export const metadataSymbol = Symbol('log message with metadata');
|
||||
export function attachMetaData(message: string, metadata: Record<string, any> = {}) {
|
||||
export function attachMetaData(message: string, metadata: LegacyVars = {}) {
|
||||
return {
|
||||
[metadataSymbol]: {
|
||||
message,
|
||||
|
@ -50,7 +51,7 @@ interface PluginRegisterParams {
|
|||
options: PluginRegisterParams['options']
|
||||
) => Promise<void>;
|
||||
};
|
||||
options: Record<string, any>;
|
||||
options: LegacyVars;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +85,7 @@ export class LegacyLoggingServer {
|
|||
|
||||
private onPostStopCallback?: () => void;
|
||||
|
||||
constructor(legacyLoggingConfig: Readonly<Record<string, any>>) {
|
||||
constructor(legacyLoggingConfig: Readonly<LegacyVars>) {
|
||||
// We set `ops.interval` to max allowed number and `ops` filter to value
|
||||
// that doesn't exist to avoid logging of ops at all, if turned on it will be
|
||||
// logged by the "legacy" Kibana.
|
||||
|
|
|
@ -17,11 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { mergeVariables } from './merge_variables';
|
||||
import { mergeVars } from './merge_vars';
|
||||
|
||||
describe('mergeVariables', () => {
|
||||
describe('mergeVars', () => {
|
||||
it('merges two objects together', () => {
|
||||
const someVariables = {
|
||||
const first = {
|
||||
otherName: 'value',
|
||||
otherCanFoo: true,
|
||||
otherNested: {
|
||||
otherAnotherVariable: 'ok',
|
||||
},
|
||||
};
|
||||
const second = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
nested: {
|
||||
|
@ -29,17 +36,7 @@ describe('mergeVariables', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const otherVariables = {
|
||||
otherName: 'value',
|
||||
otherCanFoo: true,
|
||||
otherNested: {
|
||||
otherAnotherVariable: 'ok',
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeVariables(someVariables, otherVariables);
|
||||
|
||||
expect(result).toEqual({
|
||||
expect(mergeVars(first, second)).toEqual({
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
nested: {
|
||||
|
@ -54,71 +51,68 @@ describe('mergeVariables', () => {
|
|||
});
|
||||
|
||||
it('does not mutate the source objects', () => {
|
||||
const original = {
|
||||
var1: 'original',
|
||||
const first = {
|
||||
var1: 'first',
|
||||
};
|
||||
const second = {
|
||||
var1: 'second',
|
||||
var2: 'second',
|
||||
};
|
||||
const third = {
|
||||
var1: 'third',
|
||||
var2: 'third',
|
||||
var3: 'third',
|
||||
};
|
||||
const fourth = {
|
||||
var1: 'fourth',
|
||||
var2: 'fourth',
|
||||
var3: 'fourth',
|
||||
var4: 'fourth',
|
||||
};
|
||||
|
||||
const set1 = {
|
||||
var1: 'value1',
|
||||
var2: 'value1',
|
||||
};
|
||||
mergeVars(first, second, third, fourth);
|
||||
|
||||
const set2 = {
|
||||
var1: 'value2',
|
||||
var2: 'value2',
|
||||
var3: 'value2',
|
||||
};
|
||||
|
||||
const set3 = {
|
||||
var1: 'value3',
|
||||
var2: 'value3',
|
||||
var3: 'value3',
|
||||
var4: 'value3',
|
||||
};
|
||||
|
||||
mergeVariables(original, set1, set2, set3);
|
||||
|
||||
expect(original).toEqual({ var1: 'original' });
|
||||
expect(set1).toEqual({ var1: 'value1', var2: 'value1' });
|
||||
expect(set2).toEqual({ var1: 'value2', var2: 'value2', var3: 'value2' });
|
||||
expect(set3).toEqual({ var1: 'value3', var2: 'value3', var3: 'value3', var4: 'value3' });
|
||||
expect(first).toEqual({ var1: 'first' });
|
||||
expect(second).toEqual({ var1: 'second', var2: 'second' });
|
||||
expect(third).toEqual({ var1: 'third', var2: 'third', var3: 'third' });
|
||||
expect(fourth).toEqual({ var1: 'fourth', var2: 'fourth', var3: 'fourth', var4: 'fourth' });
|
||||
});
|
||||
|
||||
it('merges multiple objects together, preferring the leftmost values', () => {
|
||||
const original = {
|
||||
var1: 'original',
|
||||
it('merges multiple objects together with precedence increasing from left-to-right', () => {
|
||||
const first = {
|
||||
var1: 'first',
|
||||
var2: 'first',
|
||||
var3: 'first',
|
||||
var4: 'first',
|
||||
};
|
||||
const second = {
|
||||
var1: 'second',
|
||||
var2: 'second',
|
||||
var3: 'second',
|
||||
};
|
||||
const third = {
|
||||
var1: 'third',
|
||||
var2: 'third',
|
||||
};
|
||||
const fourth = {
|
||||
var1: 'fourth',
|
||||
};
|
||||
|
||||
const set1 = {
|
||||
var1: 'value1',
|
||||
var2: 'value1',
|
||||
};
|
||||
|
||||
const set2 = {
|
||||
var1: 'value2',
|
||||
var2: 'value2',
|
||||
var3: 'value2',
|
||||
};
|
||||
|
||||
const set3 = {
|
||||
var1: 'value3',
|
||||
var2: 'value3',
|
||||
var3: 'value3',
|
||||
var4: 'value3',
|
||||
};
|
||||
|
||||
const result = mergeVariables(original, set1, set2, set3);
|
||||
|
||||
expect(result).toEqual({
|
||||
var1: 'original',
|
||||
var2: 'value1',
|
||||
var3: 'value2',
|
||||
var4: 'value3',
|
||||
expect(mergeVars(first, second, third, fourth)).toEqual({
|
||||
var1: 'fourth',
|
||||
var2: 'third',
|
||||
var3: 'second',
|
||||
var4: 'first',
|
||||
});
|
||||
});
|
||||
|
||||
it('retains the original variable value if a duplicate entry is found', () => {
|
||||
const someVariables = {
|
||||
it('overwrites the original variable value if a duplicate entry is found', () => {
|
||||
const first = {
|
||||
nested: {
|
||||
otherAnotherVariable: 'ok',
|
||||
},
|
||||
};
|
||||
const second = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
nested: {
|
||||
|
@ -126,14 +120,7 @@ describe('mergeVariables', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const otherVariables = {
|
||||
nested: {
|
||||
otherAnotherVariable: 'ok',
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeVariables(someVariables, otherVariables);
|
||||
expect(result).toEqual({
|
||||
expect(mergeVars(first, second)).toEqual({
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
nested: {
|
||||
|
@ -143,55 +130,61 @@ describe('mergeVariables', () => {
|
|||
});
|
||||
|
||||
it('combines entries within "uiCapabilities"', () => {
|
||||
const someVariables = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
const first = {
|
||||
uiCapabilities: {
|
||||
firstCapability: 'ok',
|
||||
sharedCapability: 'shared',
|
||||
},
|
||||
};
|
||||
|
||||
const otherVariables = {
|
||||
const second = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
uiCapabilities: {
|
||||
secondCapability: 'ok',
|
||||
},
|
||||
};
|
||||
const third = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
uiCapabilities: {
|
||||
thirdCapability: 'ok',
|
||||
sharedCapability: 'blocked',
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeVariables(someVariables, otherVariables);
|
||||
|
||||
expect(result).toEqual({
|
||||
expect(mergeVars(first, second, third)).toEqual({
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
uiCapabilities: {
|
||||
firstCapability: 'ok',
|
||||
secondCapability: 'ok',
|
||||
thirdCapability: 'ok',
|
||||
sharedCapability: 'blocked',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('does not deeply combine entries within "uiCapabilities"', () => {
|
||||
const someVariables = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
const first = {
|
||||
uiCapabilities: {
|
||||
firstCapability: 'ok',
|
||||
nestedCapability: {
|
||||
nestedProp: 'nestedValue',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const otherVariables = {
|
||||
uiCapabilities: {
|
||||
secondCapability: 'ok',
|
||||
nestedCapability: {
|
||||
otherNestedProp: 'otherNestedValue',
|
||||
},
|
||||
},
|
||||
};
|
||||
const second = {
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
uiCapabilities: {
|
||||
secondCapability: 'ok',
|
||||
nestedCapability: {
|
||||
nestedProp: 'nestedValue',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeVariables(someVariables, otherVariables);
|
||||
expect(result).toEqual({
|
||||
expect(mergeVars(first, second)).toEqual({
|
||||
name: 'value',
|
||||
canFoo: true,
|
||||
uiCapabilities: {
|
|
@ -17,23 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyVars } from './types';
|
||||
|
||||
const ELIGIBLE_FLAT_MERGE_KEYS = ['uiCapabilities'];
|
||||
|
||||
export function mergeVariables(...sources: Array<Record<string, any>>) {
|
||||
const result: Record<string, any> = {};
|
||||
|
||||
for (const source of sources) {
|
||||
Object.entries(source).forEach(([key, value]) => {
|
||||
if (ELIGIBLE_FLAT_MERGE_KEYS.includes(key)) {
|
||||
result[key] = {
|
||||
...value,
|
||||
...result[key],
|
||||
};
|
||||
} else if (!result.hasOwnProperty(key)) {
|
||||
result[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
export function mergeVars(...sources: LegacyVars[]): LegacyVars {
|
||||
return Object.assign(
|
||||
{},
|
||||
...sources,
|
||||
...ELIGIBLE_FLAT_MERGE_KEYS.flatMap(key =>
|
||||
sources.some(source => key in source)
|
||||
? [{ [key]: Object.assign({}, ...sources.map(source => source[key] || {})) }]
|
||||
: []
|
||||
)
|
||||
);
|
||||
}
|
|
@ -19,25 +19,77 @@
|
|||
|
||||
import { Observable, merge, forkJoin } from 'rxjs';
|
||||
import { toArray, tap, distinct, map } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
findPluginSpecs,
|
||||
defaultConfig,
|
||||
// @ts-ignore
|
||||
} from '../../../../legacy/plugin_discovery/find_plugin_specs.js';
|
||||
import { LoggerFactory } from '../../logging';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { collectUiExports as collectLegacyUiExports } from '../../../../legacy/ui/ui_exports/collect_ui_exports';
|
||||
import { LegacyConfig, LegacyConfigDeprecationProvider } from '../config';
|
||||
|
||||
export interface LegacyPluginPack {
|
||||
getPath(): string;
|
||||
import { LoggerFactory } from '../../logging';
|
||||
import {
|
||||
LegacyUiExports,
|
||||
LegacyNavLink,
|
||||
LegacyPluginSpec,
|
||||
LegacyPluginPack,
|
||||
LegacyConfig,
|
||||
} from '../types';
|
||||
|
||||
const REMOVE_FROM_ARRAY: LegacyNavLink[] = [];
|
||||
|
||||
function getUiAppsNavLinks({ uiAppSpecs = [] }: LegacyUiExports, pluginSpecs: LegacyPluginSpec[]) {
|
||||
return uiAppSpecs.flatMap(spec => {
|
||||
if (!spec) {
|
||||
return REMOVE_FROM_ARRAY;
|
||||
}
|
||||
|
||||
export interface LegacyPluginSpec {
|
||||
getId: () => unknown;
|
||||
getExpectedKibanaVersion: () => string;
|
||||
getConfigPrefix: () => string;
|
||||
getDeprecationsProvider: () => LegacyConfigDeprecationProvider | undefined;
|
||||
const id = spec.pluginId || spec.id;
|
||||
|
||||
if (!id) {
|
||||
throw new Error('Every app must specify an id');
|
||||
}
|
||||
|
||||
if (spec.pluginId && !pluginSpecs.some(plugin => plugin.getId() === spec.pluginId)) {
|
||||
throw new Error(`Unknown plugin id "${spec.pluginId}"`);
|
||||
}
|
||||
|
||||
const listed = typeof spec.listed === 'boolean' ? spec.listed : true;
|
||||
|
||||
if (spec.hidden || !listed) {
|
||||
return REMOVE_FROM_ARRAY;
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
title: spec.title,
|
||||
order: typeof spec.order === 'number' ? spec.order : 0,
|
||||
icon: spec.icon,
|
||||
euiIconType: spec.euiIconType,
|
||||
url: spec.url || `/app/${id}`,
|
||||
linkToLastSubUrl: spec.linkToLastSubUrl,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getNavLinks(uiExports: LegacyUiExports, pluginSpecs: LegacyPluginSpec[]) {
|
||||
return (uiExports.navLinkSpecs || [])
|
||||
.map<LegacyNavLink>(spec => ({
|
||||
id: spec.id,
|
||||
title: spec.title,
|
||||
order: typeof spec.order === 'number' ? spec.order : 0,
|
||||
url: spec.url,
|
||||
subUrlBase: spec.subUrlBase || spec.url,
|
||||
icon: spec.icon,
|
||||
euiIconType: spec.euiIconType,
|
||||
linkToLastSub: 'linkToLastSubUrl' in spec ? spec.linkToLastSubUrl : false,
|
||||
hidden: 'hidden' in spec ? spec.hidden : false,
|
||||
disabled: 'disabled' in spec ? spec.disabled : false,
|
||||
tooltip: spec.tooltip || '',
|
||||
}))
|
||||
.concat(getUiAppsNavLinks(uiExports, pluginSpecs))
|
||||
.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
|
||||
export async function findLegacyPluginSpecs(settings: unknown, loggerFactory: LoggerFactory) {
|
||||
|
@ -128,11 +180,14 @@ export async function findLegacyPluginSpecs(settings: unknown, loggerFactory: Lo
|
|||
spec$.pipe(toArray()),
|
||||
log$.pipe(toArray())
|
||||
).toPromise();
|
||||
const uiExports = collectLegacyUiExports(pluginSpecs);
|
||||
const navLinks = getNavLinks(uiExports, pluginSpecs);
|
||||
|
||||
return {
|
||||
disabledPluginSpecs,
|
||||
pluginSpecs,
|
||||
pluginExtendedConfig: configToMutate,
|
||||
uiExports: collectLegacyUiExports(pluginSpecs),
|
||||
uiExports,
|
||||
navLinks,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { findLegacyPluginSpecs } from './find_legacy_plugin_specs';
|
||||
|
|
222
src/core/server/legacy/types.ts
Normal file
222
src/core/server/legacy/types.ts
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Server } from 'hapi';
|
||||
|
||||
import { ChromeNavLink } from '../../public';
|
||||
import { LegacyRequest } from '../http';
|
||||
import { InternalCoreSetup, InternalCoreStart } from '../internal_types';
|
||||
import { PluginsServiceSetup, PluginsServiceStart } from '../plugins';
|
||||
import { RenderingServiceSetup } from '../rendering';
|
||||
import { SavedObjectsLegacyUiExports } from '../types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyVars = Record<string, any>;
|
||||
|
||||
type LegacyCoreSetup = InternalCoreSetup & {
|
||||
plugins: PluginsServiceSetup;
|
||||
rendering: RenderingServiceSetup;
|
||||
};
|
||||
type LegacyCoreStart = InternalCoreStart & { plugins: PluginsServiceStart };
|
||||
|
||||
/**
|
||||
* New platform representation of the legacy configuration (KibanaConfig)
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyConfig {
|
||||
get<T>(key?: string): T;
|
||||
has(key: string): boolean;
|
||||
set(key: string, value: any): void;
|
||||
set(config: LegacyVars): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation factory used for
|
||||
* legacy plugin deprecations.
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyConfigDeprecationFactory {
|
||||
rename(oldKey: string, newKey: string): LegacyConfigDeprecation;
|
||||
unused(unusedKey: string): LegacyConfigDeprecation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation.
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyConfigDeprecation = (settings: LegacyVars, log: (msg: string) => void) => void;
|
||||
|
||||
/**
|
||||
* Representation of a legacy configuration deprecation provider.
|
||||
*
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyConfigDeprecationProvider = (
|
||||
factory: LegacyConfigDeprecationFactory
|
||||
) => LegacyConfigDeprecation[] | Promise<LegacyConfigDeprecation[]>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyPluginPack {
|
||||
getPath(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyPluginSpec {
|
||||
getId: () => unknown;
|
||||
getExpectedKibanaVersion: () => string;
|
||||
getConfigPrefix: () => string;
|
||||
getDeprecationsProvider: () => LegacyConfigDeprecationProvider | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface VarsProvider {
|
||||
fn: (server: Server, configValue: any) => LegacyVars;
|
||||
pluginSpec: {
|
||||
readConfigValue(config: any, key: string | string[]): any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type VarsInjector = () => LegacyVars;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type VarsReplacer = (
|
||||
vars: LegacyVars,
|
||||
request: LegacyRequest,
|
||||
server: Server
|
||||
) => LegacyVars | Promise<LegacyVars>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyNavLinkSpec = Record<string, unknown> & ChromeNavLink;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyAppSpec = Pick<
|
||||
ChromeNavLink,
|
||||
'title' | 'order' | 'icon' | 'euiIconType' | 'url' | 'linkToLastSubUrl' | 'hidden'
|
||||
> & { pluginId?: string; id?: string; listed?: boolean };
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyNavLink = Omit<ChromeNavLink, 'baseUrl' | 'legacy' | 'order'> & {
|
||||
order: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export type LegacyUiExports = SavedObjectsLegacyUiExports & {
|
||||
defaultInjectedVarProviders?: VarsProvider[];
|
||||
injectedVarsReplacers?: VarsReplacer[];
|
||||
navLinkSpecs?: LegacyNavLinkSpec[] | null;
|
||||
uiAppSpecs?: Array<LegacyAppSpec | undefined>;
|
||||
unknown?: [{ pluginSpec: LegacyPluginSpec; type: unknown }];
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyServiceSetupDeps {
|
||||
core: LegacyCoreSetup;
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyServiceStartDeps {
|
||||
core: LegacyCoreStart;
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface ILegacyInternals {
|
||||
/**
|
||||
* Inject UI app vars for a particular plugin
|
||||
*/
|
||||
injectUiAppVars(id: string, injector: VarsInjector): void;
|
||||
|
||||
/**
|
||||
* Get all the merged injected UI app vars for a particular plugin
|
||||
*/
|
||||
getInjectedUiAppVars(id: string): Promise<LegacyVars>;
|
||||
|
||||
/**
|
||||
* Get the metadata vars for a particular plugin
|
||||
*/
|
||||
getVars(id: string, request: LegacyRequest, injected?: LegacyVars): Promise<LegacyVars>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyPlugins {
|
||||
disabledPluginSpecs: LegacyPluginSpec[];
|
||||
pluginSpecs: LegacyPluginSpec[];
|
||||
uiExports: LegacyUiExports;
|
||||
navLinks: LegacyNavLink[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
*/
|
||||
export interface LegacyServiceDiscoverPlugins extends LegacyPlugins {
|
||||
pluginExtendedConfig: LegacyConfig;
|
||||
settings: LegacyVars;
|
||||
}
|
|
@ -17,17 +17,11 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginsService } from './plugins_service';
|
||||
import { PluginsService, PluginsServiceSetup } from './plugins_service';
|
||||
|
||||
type ServiceContract = PublicMethodsOf<PluginsService>;
|
||||
const createServiceMock = () => {
|
||||
const mocked: jest.Mocked<ServiceContract> = {
|
||||
discover: jest.fn(),
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
};
|
||||
mocked.setup.mockResolvedValue({
|
||||
type PluginsServiceMock = jest.Mocked<PublicMethodsOf<PluginsService>>;
|
||||
|
||||
const createSetupContractMock = (): PluginsServiceSetup => ({
|
||||
contracts: new Map(),
|
||||
uiPlugins: {
|
||||
browserConfigs: new Map(),
|
||||
|
@ -35,10 +29,16 @@ const createServiceMock = () => {
|
|||
public: new Map(),
|
||||
},
|
||||
});
|
||||
mocked.start.mockResolvedValue({ contracts: new Map() });
|
||||
return mocked;
|
||||
};
|
||||
const createStartContractMock = () => ({ contracts: new Map() });
|
||||
const createServiceMock = (): PluginsServiceMock => ({
|
||||
discover: jest.fn(),
|
||||
setup: jest.fn().mockResolvedValue(createSetupContractMock()),
|
||||
start: jest.fn().mockResolvedValue(createStartContractMock()),
|
||||
stop: jest.fn(),
|
||||
});
|
||||
|
||||
export const pluginServiceMock = {
|
||||
create: createServiceMock,
|
||||
createSetupContract: createSetupContractMock,
|
||||
createStartContract: createStartContractMock,
|
||||
};
|
||||
|
|
35
src/core/server/rendering/__mocks__/params.ts
Normal file
35
src/core/server/rendering/__mocks__/params.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { mockCoreContext } from '../../core_context.mock';
|
||||
import { httpServiceMock } from '../../http/http_service.mock';
|
||||
import { pluginServiceMock } from '../../plugins/plugins_service.mock';
|
||||
import { legacyServiceMock } from '../../legacy/legacy_service.mock';
|
||||
|
||||
const context = mockCoreContext.create();
|
||||
const http = httpServiceMock.createSetupContract();
|
||||
const plugins = pluginServiceMock.createSetupContract();
|
||||
const legacyPlugins = legacyServiceMock.createDiscoverPlugins();
|
||||
|
||||
export const mockRenderingServiceParams = context;
|
||||
export const mockRenderingSetupDeps = {
|
||||
http,
|
||||
legacyPlugins,
|
||||
plugins,
|
||||
};
|
39
src/core/server/rendering/__mocks__/rendering_service.ts
Normal file
39
src/core/server/rendering/__mocks__/rendering_service.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { RenderingService as Service } from '../rendering_service';
|
||||
import { RenderingServiceSetup } from '../types';
|
||||
import { mockRenderingServiceParams } from './params';
|
||||
|
||||
type IRenderingService = PublicMethodsOf<Service>;
|
||||
|
||||
export const setupMock: jest.Mocked<RenderingServiceSetup> = {
|
||||
render: jest.fn(),
|
||||
};
|
||||
export const mockSetup = jest.fn().mockResolvedValue(setupMock);
|
||||
export const mockStart = jest.fn();
|
||||
export const mockStop = jest.fn();
|
||||
export const mockRenderingService: jest.Mocked<IRenderingService> = {
|
||||
setup: mockSetup,
|
||||
start: mockStart,
|
||||
stop: mockStop,
|
||||
};
|
||||
export const RenderingService = jest.fn<IRenderingService, [typeof mockRenderingServiceParams]>(
|
||||
() => mockRenderingService
|
||||
);
|
719
src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap
generated
Normal file
719
src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap
generated
Normal file
|
@ -0,0 +1,719 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`RenderingService setup() render() renders "core" from legacy request 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:core",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": false,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "core" page 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:core",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": false,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "core" page driven by settings 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:core",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {
|
||||
"theme:darkMode": Object {
|
||||
"userValue": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": false,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "core" page for blank basepath 1`] = `
|
||||
Object {
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:core",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": false,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "core" with excluded user settings 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:core",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": false,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "legacy" page 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:legacy",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": true,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "legacy" page for blank basepath 1`] = `
|
||||
Object {
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:legacy",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": true,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "legacy" with custom vars 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:legacy",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": true,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {
|
||||
"fake": "__TEST_TOKEN__",
|
||||
},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "legacy" with excluded user settings 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:legacy",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": true,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`RenderingService setup() render() renders "legacy" with excluded user settings and custom vars 1`] = `
|
||||
Object {
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNumber": Any<Number>,
|
||||
"csp": Object {
|
||||
"warnLegacyBrowsers": true,
|
||||
},
|
||||
"env": Object {
|
||||
"binDir": Any<String>,
|
||||
"cliArgs": Object {
|
||||
"basePath": false,
|
||||
"dev": true,
|
||||
"open": false,
|
||||
"optimize": false,
|
||||
"oss": false,
|
||||
"quiet": false,
|
||||
"repl": false,
|
||||
"silent": false,
|
||||
"watch": false,
|
||||
},
|
||||
"configDir": Any<String>,
|
||||
"configs": Array [],
|
||||
"homeDir": Any<String>,
|
||||
"isDevClusterMaster": false,
|
||||
"logDir": Any<String>,
|
||||
"mode": Object {
|
||||
"dev": true,
|
||||
"name": "development",
|
||||
"prod": false,
|
||||
},
|
||||
"packageInfo": Object {
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"dist": false,
|
||||
"version": Any<String>,
|
||||
},
|
||||
"pluginSearchPaths": Any<Array>,
|
||||
"staticFilesDir": Any<String>,
|
||||
},
|
||||
"i18n": Object {
|
||||
"translationsUrl": "/mock-server-basepath/translations/en.json",
|
||||
},
|
||||
"legacyMetadata": Object {
|
||||
"app": Object {},
|
||||
"basePath": "/mock-server-basepath",
|
||||
"branch": Any<String>,
|
||||
"buildNum": Any<Number>,
|
||||
"buildSha": Any<String>,
|
||||
"bundleId": "app:legacy",
|
||||
"devMode": true,
|
||||
"nav": Array [],
|
||||
"serverName": "http-server-test",
|
||||
"uiSettings": Object {
|
||||
"defaults": Object {
|
||||
"registered": Object {
|
||||
"name": "title",
|
||||
},
|
||||
},
|
||||
"user": Object {},
|
||||
},
|
||||
"version": Any<String>,
|
||||
},
|
||||
"legacyMode": true,
|
||||
"uiPlugins": Array [],
|
||||
"vars": Object {
|
||||
"fake": "__TEST_TOKEN__",
|
||||
},
|
||||
"version": Any<String>,
|
||||
}
|
||||
`;
|
21
src/core/server/rendering/index.ts
Normal file
21
src/core/server/rendering/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { RenderingService } from './rendering_service';
|
||||
export * from './types';
|
185
src/core/server/rendering/rendering_service.test.ts
Normal file
185
src/core/server/rendering/rendering_service.test.ts
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { httpServerMock } from '../http/http_server.mocks';
|
||||
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
||||
import { mockRenderingServiceParams, mockRenderingSetupDeps } from './__mocks__/params';
|
||||
import { RenderingServiceSetup } from './types';
|
||||
import { RenderingService } from './rendering_service';
|
||||
|
||||
const INJECTED_METADATA = {
|
||||
version: expect.any(String),
|
||||
branch: expect.any(String),
|
||||
buildNumber: expect.any(Number),
|
||||
env: {
|
||||
binDir: expect.any(String),
|
||||
configDir: expect.any(String),
|
||||
homeDir: expect.any(String),
|
||||
logDir: expect.any(String),
|
||||
packageInfo: {
|
||||
branch: expect.any(String),
|
||||
buildNum: expect.any(Number),
|
||||
buildSha: expect.any(String),
|
||||
version: expect.any(String),
|
||||
},
|
||||
pluginSearchPaths: expect.any(Array),
|
||||
staticFilesDir: expect.any(String),
|
||||
},
|
||||
legacyMetadata: {
|
||||
branch: expect.any(String),
|
||||
buildNum: expect.any(Number),
|
||||
buildSha: expect.any(String),
|
||||
version: expect.any(String),
|
||||
},
|
||||
};
|
||||
const { createKibanaRequest, createRawRequest } = httpServerMock;
|
||||
const legacyApp = { getId: () => 'legacy' };
|
||||
|
||||
describe('RenderingService', () => {
|
||||
let service: RenderingService;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
service = new RenderingService(mockRenderingServiceParams);
|
||||
});
|
||||
|
||||
describe('setup()', () => {
|
||||
it('creates instance of RenderingServiceSetup', async () => {
|
||||
const rendering = await service.setup(mockRenderingSetupDeps);
|
||||
|
||||
expect(rendering.render).toBeInstanceOf(Function);
|
||||
});
|
||||
|
||||
describe('render()', () => {
|
||||
let uiSettings: ReturnType<typeof uiSettingsServiceMock.createClient>;
|
||||
let render: RenderingServiceSetup['render'];
|
||||
|
||||
beforeEach(async () => {
|
||||
uiSettings = uiSettingsServiceMock.createClient();
|
||||
uiSettings.getRegistered.mockReturnValue({
|
||||
registered: { name: 'title' },
|
||||
});
|
||||
render = (await service.setup(mockRenderingSetupDeps)).render;
|
||||
});
|
||||
|
||||
it('renders "core" page', async () => {
|
||||
const content = await render(createKibanaRequest(), uiSettings);
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "core" page for blank basepath', async () => {
|
||||
mockRenderingSetupDeps.http.basePath.get.mockReturnValueOnce('');
|
||||
|
||||
const content = await render(createKibanaRequest(), uiSettings);
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "core" page driven by settings', async () => {
|
||||
uiSettings.getUserProvided.mockResolvedValue({ 'theme:darkMode': { userValue: true } });
|
||||
const content = await render(createKibanaRequest(), uiSettings);
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "core" with excluded user settings', async () => {
|
||||
const content = await render(createKibanaRequest(), uiSettings, {
|
||||
includeUserSettings: false,
|
||||
});
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "core" from legacy request', async () => {
|
||||
const content = await render(createRawRequest(), uiSettings);
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "legacy" page', async () => {
|
||||
const content = await render(createRawRequest(), uiSettings, { app: legacyApp });
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "legacy" page for blank basepath', async () => {
|
||||
mockRenderingSetupDeps.http.basePath.get.mockReturnValueOnce('');
|
||||
|
||||
const content = await render(createRawRequest(), uiSettings, { app: legacyApp });
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "legacy" with custom vars', async () => {
|
||||
const content = await render(createRawRequest(), uiSettings, {
|
||||
app: legacyApp,
|
||||
vars: {
|
||||
fake: '__TEST_TOKEN__',
|
||||
},
|
||||
});
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "legacy" with excluded user settings', async () => {
|
||||
const content = await render(createRawRequest(), uiSettings, {
|
||||
app: legacyApp,
|
||||
includeUserSettings: false,
|
||||
});
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
|
||||
it('renders "legacy" with excluded user settings and custom vars', async () => {
|
||||
const content = await render(createRawRequest(), uiSettings, {
|
||||
app: legacyApp,
|
||||
includeUserSettings: false,
|
||||
vars: {
|
||||
fake: '__TEST_TOKEN__',
|
||||
},
|
||||
});
|
||||
const dom = load(content);
|
||||
const data = JSON.parse(dom('kbn-injected-metadata').attr('data'));
|
||||
|
||||
expect(data).toMatchSnapshot(INJECTED_METADATA);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
120
src/core/server/rendering/rendering_service.tsx
Normal file
120
src/core/server/rendering/rendering_service.tsx
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { CoreService } from '../../types';
|
||||
import { CoreContext } from '../core_context';
|
||||
import { Template } from './views';
|
||||
import {
|
||||
RenderingSetupDeps,
|
||||
RenderingServiceSetup,
|
||||
RenderingMetadata,
|
||||
LegacyRenderOptions,
|
||||
} from './types';
|
||||
|
||||
/** @internal */
|
||||
export class RenderingService implements CoreService<RenderingServiceSetup> {
|
||||
constructor(private readonly coreContext: CoreContext) {}
|
||||
|
||||
public async setup({
|
||||
http,
|
||||
legacyPlugins,
|
||||
plugins,
|
||||
}: RenderingSetupDeps): Promise<RenderingServiceSetup> {
|
||||
async function getUiConfig(pluginId: string) {
|
||||
const browserConfig = plugins.uiPlugins.browserConfigs.get(pluginId);
|
||||
|
||||
return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {}) as Record<string, any>;
|
||||
}
|
||||
|
||||
return {
|
||||
render: async (
|
||||
request,
|
||||
uiSettings,
|
||||
{
|
||||
app = { getId: () => 'core' },
|
||||
includeUserSettings = true,
|
||||
vars = {},
|
||||
}: LegacyRenderOptions = {}
|
||||
) => {
|
||||
const { env } = this.coreContext;
|
||||
const basePath = http.basePath.get(request);
|
||||
const settings = {
|
||||
defaults: uiSettings.getRegistered(),
|
||||
user: includeUserSettings ? await uiSettings.getUserProvided() : {},
|
||||
};
|
||||
const appId = app.getId();
|
||||
const metadata: RenderingMetadata = {
|
||||
strictCsp: http.csp.strict,
|
||||
uiPublicUrl: `${basePath}/ui`,
|
||||
bootstrapScriptUrl: `${basePath}/bundles/app/${appId}/bootstrap.js`,
|
||||
i18n: i18n.translate,
|
||||
locale: i18n.getLocale(),
|
||||
darkMode: settings.user?.['theme:darkMode']?.userValue
|
||||
? Boolean(settings.user['theme:darkMode'].userValue)
|
||||
: false,
|
||||
injectedMetadata: {
|
||||
version: env.packageInfo.version,
|
||||
buildNumber: env.packageInfo.buildNum,
|
||||
branch: env.packageInfo.branch,
|
||||
basePath,
|
||||
env,
|
||||
legacyMode: appId !== 'core',
|
||||
i18n: {
|
||||
translationsUrl: `${basePath}/translations/${i18n.getLocale()}.json`,
|
||||
},
|
||||
csp: { warnLegacyBrowsers: http.csp.warnLegacyBrowsers },
|
||||
vars,
|
||||
uiPlugins: await Promise.all(
|
||||
[...plugins.uiPlugins.public].map(async ([id, plugin]) => ({
|
||||
id,
|
||||
plugin,
|
||||
config: await getUiConfig(id),
|
||||
}))
|
||||
),
|
||||
legacyMetadata: {
|
||||
app,
|
||||
bundleId: `app:${appId}`,
|
||||
nav: legacyPlugins.navLinks,
|
||||
version: env.packageInfo.version,
|
||||
branch: env.packageInfo.branch,
|
||||
buildNum: env.packageInfo.buildNum,
|
||||
buildSha: env.packageInfo.buildSha,
|
||||
serverName: http.server.name,
|
||||
devMode: env.mode.dev,
|
||||
basePath,
|
||||
uiSettings: settings,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return `<!DOCTYPE html>${renderToStaticMarkup(<Template metadata={metadata} />)}`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public async start() {}
|
||||
|
||||
public async stop() {}
|
||||
}
|
145
src/core/server/rendering/types.ts
Normal file
145
src/core/server/rendering/types.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Env } from '../config';
|
||||
import { ICspConfig } from '../csp';
|
||||
import { InternalHttpServiceSetup, KibanaRequest, LegacyRequest } from '../http';
|
||||
import { LegacyNavLink, LegacyServiceDiscoverPlugins } from '../legacy';
|
||||
import { PluginsServiceSetup, DiscoveredPlugin } from '../plugins';
|
||||
import { IUiSettingsClient, UserProvidedValues } from '../ui_settings';
|
||||
|
||||
/** @internal */
|
||||
export interface RenderingMetadata {
|
||||
strictCsp: ICspConfig['strict'];
|
||||
uiPublicUrl: string;
|
||||
bootstrapScriptUrl: string;
|
||||
i18n: typeof i18n.translate;
|
||||
locale: string;
|
||||
darkMode: boolean;
|
||||
injectedMetadata: {
|
||||
version: string;
|
||||
buildNumber: number;
|
||||
branch: string;
|
||||
basePath: string;
|
||||
env: Env;
|
||||
legacyMode: boolean;
|
||||
i18n: {
|
||||
translationsUrl: string;
|
||||
};
|
||||
csp: Pick<ICspConfig, 'warnLegacyBrowsers'>;
|
||||
vars: Record<string, any>;
|
||||
uiPlugins: Array<{
|
||||
id: string;
|
||||
plugin: DiscoveredPlugin;
|
||||
config?: Record<string, unknown>;
|
||||
}>;
|
||||
legacyMetadata: {
|
||||
app: { getId(): string };
|
||||
bundleId: string;
|
||||
nav: LegacyNavLink[];
|
||||
version: string;
|
||||
branch: string;
|
||||
buildNum: number;
|
||||
buildSha: string;
|
||||
serverName: string;
|
||||
devMode: boolean;
|
||||
basePath: string;
|
||||
uiSettings: {
|
||||
defaults: Record<string, any>;
|
||||
user: Record<string, UserProvidedValues<any>>;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface RenderingSetupDeps {
|
||||
http: InternalHttpServiceSetup;
|
||||
legacyPlugins: LegacyServiceDiscoverPlugins;
|
||||
plugins: PluginsServiceSetup;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface IRenderOptions {
|
||||
/**
|
||||
* Set whether to output user settings in the page metadata.
|
||||
* `true` by default.
|
||||
*/
|
||||
includeUserSettings?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated for legacy use only, remove with ui_render_mixin
|
||||
*/
|
||||
export interface LegacyRenderOptions extends IRenderOptions {
|
||||
/**
|
||||
* Render the bootstrapped HTML content for an optional legacy application.
|
||||
* Defaults to `core`.
|
||||
*/
|
||||
app?: { getId(): string };
|
||||
|
||||
/**
|
||||
* Inject custom vars into the page metadata.
|
||||
*/
|
||||
vars?: Record<string, any>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface IScopedRenderingClient {
|
||||
/**
|
||||
* Generate a `KibanaResponse` which renders an HTML page bootstrapped
|
||||
* with the `core` bundle. Intended as a response body for HTTP route handlers.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* router.get(
|
||||
* { path: '/', validate: false },
|
||||
* (context, request, response) =>
|
||||
* response.ok({
|
||||
* body: await context.core.rendering.render(),
|
||||
* headers: {
|
||||
* 'content-security-policy': context.core.http.csp.header,
|
||||
* },
|
||||
* })
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
render(options?: IRenderOptions): Promise<string>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface RenderingServiceSetup {
|
||||
/**
|
||||
* Generate a `KibanaResponse` which renders an HTML page bootstrapped
|
||||
* with the `core` bundle or the ID of another specified legacy bundle.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const html = await rendering.render(request, uiSettings);
|
||||
* ```
|
||||
*/
|
||||
render<R extends KibanaRequest | LegacyRequest>(
|
||||
request: R,
|
||||
uiSettings: IUiSettingsClient,
|
||||
options?: R extends LegacyRequest ? LegacyRenderOptions : IRenderOptions
|
||||
): Promise<string>;
|
||||
}
|
336
src/core/server/rendering/views/fonts.tsx
Normal file
336
src/core/server/rendering/views/fonts.tsx
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/no-danger */
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { RenderingMetadata } from '../types';
|
||||
|
||||
interface Props {
|
||||
url: RenderingMetadata['uiPublicUrl'];
|
||||
}
|
||||
|
||||
interface FontFace {
|
||||
family: string;
|
||||
variants: Array<{
|
||||
style: 'normal' | 'italic';
|
||||
weight: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
|
||||
sources: string[];
|
||||
unicodeRange?: string;
|
||||
format?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export const Fonts: FunctionComponent<Props> = ({ url }) => {
|
||||
const interUi: FontFace = {
|
||||
family: 'Inter UI',
|
||||
variants: [
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 100,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Thin-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Thin-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 100,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-ThinItalic-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-ThinItalic-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 200,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraLight-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraLight-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 200,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraLightItalic-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraLightItalic-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 300,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Light-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Light-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 300,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-LightItalic-BETA.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-LightItalic-BETA.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 400,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Regular.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Regular.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 400,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Italic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Italic.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 500,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Medium.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Medium.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 500,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-MediumItalic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-MediumItalic.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 600,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-SemiBold.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-SemiBold.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 600,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-SemiBoldItalic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-SemiBoldItalic.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 700,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Bold.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Bold.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 700,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-BoldItalic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-BoldItalic.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 800,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraBold.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraBold.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 800,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraBoldItalic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-ExtraBoldItalic.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 900,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-Black.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-Black.woff`,
|
||||
],
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 900,
|
||||
sources: [
|
||||
`${url}/fonts/inter_ui/Inter-UI-BlackItalic.woff2`,
|
||||
`${url}/fonts/inter_ui/Inter-UI-BlackItalic.woff`,
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const roboto: FontFace = {
|
||||
family: 'Roboto Mono',
|
||||
variants: [
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 400,
|
||||
format: 'woff2',
|
||||
sources: [
|
||||
'Roboto Mono',
|
||||
'RobotoMono-Regular',
|
||||
`${url}/fonts/roboto_mono/RobotoMono-Regular.ttf`,
|
||||
],
|
||||
unicodeRange:
|
||||
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 400,
|
||||
sources: [
|
||||
'Roboto Mono Italic',
|
||||
'RobotoMono-Italic',
|
||||
`${url}/fonts/roboto_mono/RobotoMono-Italic.ttf`,
|
||||
],
|
||||
unicodeRange:
|
||||
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
|
||||
},
|
||||
{
|
||||
style: 'normal',
|
||||
weight: 700,
|
||||
format: 'woff2',
|
||||
sources: [
|
||||
'Roboto Mono Bold',
|
||||
'RobotoMono-Bold',
|
||||
`${url}/fonts/roboto_mono/RobotoMono-Bold.ttf`,
|
||||
],
|
||||
unicodeRange:
|
||||
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
|
||||
},
|
||||
{
|
||||
style: 'italic',
|
||||
weight: 700,
|
||||
format: 'woff2',
|
||||
sources: [
|
||||
'Roboto Mono Bold Italic',
|
||||
'RobotoMono-BoldItalic',
|
||||
`${url}/fonts/roboto_mono/RobotoMono-BoldItalic.ttf`,
|
||||
],
|
||||
unicodeRange:
|
||||
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
${[interUi, roboto]
|
||||
.flatMap(({ family, variants }) =>
|
||||
variants.map(({ style, weight, format, sources, unicodeRange }) => {
|
||||
const src = sources
|
||||
.map(source =>
|
||||
source.startsWith(url)
|
||||
? `url('${source}') format('${format || source.split('.').pop()}')`
|
||||
: `local('${source}')`
|
||||
)
|
||||
.join(', ');
|
||||
|
||||
return `
|
||||
@font-face {
|
||||
font-family: '${family}';
|
||||
font-style: ${style};
|
||||
font-weight: ${weight};
|
||||
src: ${src};${
|
||||
unicodeRange
|
||||
? `
|
||||
unicode-range: ${unicodeRange};`
|
||||
: ''
|
||||
}
|
||||
}`;
|
||||
})
|
||||
)
|
||||
.join('\n')}
|
||||
/*
|
||||
Single variable font.
|
||||
|
||||
Note that you may want to do something like this to make sure you're serving
|
||||
constant fonts to older browsers:
|
||||
html {
|
||||
font-family: 'Inter UI', sans-serif;
|
||||
}
|
||||
@supports (font-variation-settings: normal) {
|
||||
html {
|
||||
font-family: 'Inter UI var', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
BUGS:
|
||||
- Safari 12.0 will default to italic instead of regular when font-weight
|
||||
is provided in a @font-face declaration.
|
||||
Workaround: Use 'Inter UI var alt' for Safari, or explicitly set
|
||||
\`font-variation-settings: 'slnt' DEGREE\`.
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI var';
|
||||
font-weight: 100 900;
|
||||
font-style: oblique 0deg 10deg;
|
||||
src:
|
||||
url('${url}/fonts/inter_ui/Inter-UI.var.woff2') format('woff2-variations'),
|
||||
url('${url}/fonts/inter_ui/Inter-UI.var.woff2') format('woff2');
|
||||
}
|
||||
|
||||
'Inter UI var alt' is recommended for Safari and Edge, for reliable italics.
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
html {
|
||||
font-family: 'Inter UI var alt', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI var alt';
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-named-instance: 'Regular';
|
||||
src:
|
||||
url('${url}/fonts/inter_ui/Inter-UI-upright.var.woff2') format('woff2 supports variations(gvar)'),
|
||||
url('${url}/fonts/inter_ui/Inter-UI-upright.var.woff2') format('woff2-variations'),
|
||||
url('${url}/fonts/inter_ui/Inter-UI-upright.var.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI var alt';
|
||||
font-weight: 100 900;
|
||||
font-style: italic;
|
||||
font-named-instance: 'Italic';
|
||||
src:
|
||||
url('${url}/fonts/inter_ui/Inter-UI-italic.var.woff2') format('woff2 supports variations(gvar)'),
|
||||
url('${url}/fonts/inter_ui/Inter-UI-italic.var.woff2') format('woff2-variations'),
|
||||
url('${url}/fonts/inter_ui/Inter-UI-italic.var.woff2') format('woff2');
|
||||
}
|
||||
*/
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { mergeVariables } from './merge_variables';
|
||||
export { Template } from './template';
|
175
src/core/server/rendering/views/styles.tsx
Normal file
175
src/core/server/rendering/views/styles.tsx
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable react/no-danger */
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { RenderingMetadata } from '../types';
|
||||
|
||||
interface Props {
|
||||
darkMode: RenderingMetadata['darkMode'];
|
||||
}
|
||||
|
||||
export const Styles: FunctionComponent<Props> = ({ darkMode }) => {
|
||||
const themeBackground = darkMode ? '#25262e' : '#f5f7fa';
|
||||
|
||||
return (
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-color: ${themeBackground};
|
||||
}
|
||||
|
||||
.kibanaWelcomeView {
|
||||
background-color: ${themeBackground};
|
||||
height: 100%;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: 1 0 auto;
|
||||
-ms-flex: 1 0 auto;
|
||||
flex: 1 0 auto;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.kibanaWelcomeLogo {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 10px 0 10px 20px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
/* SVG optimized according to http://codepen.io/tigt/post/optimizing-svgs-in-data-uris */
|
||||
background-image: url'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg==');
|
||||
}
|
||||
|
||||
.kibanaWelcomeTitle {
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
font-family: sans-serif;
|
||||
margin-top: 20px;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
animation-delay: 1.0s;
|
||||
}
|
||||
|
||||
.kibanaWelcomeText {
|
||||
font-size: 14px;
|
||||
font-family: sans-serif;
|
||||
color: #98a2b3;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
animation-delay: 1.0s;
|
||||
}
|
||||
|
||||
.kibanaLoaderWrap {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.kibanaLoaderWrap + * {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.kibanaLoader {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
border: 2px solid transparent;
|
||||
border-top: 2px solid #017d73;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
animation: rotation .75s .5s infinite linear, fadeIn 1s .5s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.kibanaWelcomeLogoCircle {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: bounceIn .5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes bounceIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(.1);
|
||||
}
|
||||
80% {
|
||||
opacity: .5;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
144
src/core/server/rendering/views/template.tsx
Normal file
144
src/core/server/rendering/views/template.tsx
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent, createElement } from 'react';
|
||||
|
||||
import { RenderingMetadata } from '../types';
|
||||
import { Fonts } from './fonts';
|
||||
import { Styles } from './styles';
|
||||
|
||||
interface Props {
|
||||
metadata: RenderingMetadata;
|
||||
}
|
||||
|
||||
export const Template: FunctionComponent<Props> = ({
|
||||
metadata: {
|
||||
uiPublicUrl,
|
||||
locale,
|
||||
darkMode,
|
||||
injectedMetadata,
|
||||
i18n,
|
||||
bootstrapScriptUrl,
|
||||
strictCsp,
|
||||
},
|
||||
}) => {
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Kibana</title>
|
||||
<Fonts url={uiPublicUrl} />
|
||||
{/* Favicons (generated from http://realfavicongenerator.net/) */}
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href={`${uiPublicUrl}/favicons/apple-touch-icon.png`}
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href={`${uiPublicUrl}/favicons/favicon-32x32.png`}
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href={`${uiPublicUrl}/favicons/favicon-16x16.png`}
|
||||
/>
|
||||
<link rel="manifest" href={`${uiPublicUrl}/favicons/manifest.json`} />
|
||||
<link
|
||||
rel="mask-icon"
|
||||
color="#e8488b"
|
||||
href={`${uiPublicUrl}/favicons/safari-pinned-tab.svg`}
|
||||
/>
|
||||
<link rel="shortcut icon" href={`${uiPublicUrl}/favicons/favicon.ico`} />
|
||||
<meta name="msapplication-config" content={`${uiPublicUrl}/favicons/browserconfig.xml`} />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<Styles darkMode={darkMode} />
|
||||
</head>
|
||||
<body>
|
||||
{createElement('kbn-csp', {
|
||||
data: JSON.stringify({ strictCsp }),
|
||||
})}
|
||||
{createElement('kbn-injected-metadata', { data: JSON.stringify(injectedMetadata) })}
|
||||
<div
|
||||
className="kibanaWelcomeView"
|
||||
id="kbn_loading_message"
|
||||
style={{ display: 'none' }}
|
||||
data-test-subj="kbnLoadingMessage"
|
||||
>
|
||||
<div className="kibanaLoaderWrap">
|
||||
<div className="kibanaLoader" />
|
||||
<div className="kibanaWelcomeLogoCircle">
|
||||
<div className="kibanaWelcomeLogo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="kibanaWelcomeText"
|
||||
data-error-message={i18n('core.ui.welcomeErrorMessage', {
|
||||
defaultMessage:
|
||||
'Kibana did not load properly. Check the server output for more information.',
|
||||
})}
|
||||
>
|
||||
{i18n('core.ui.welcomeMessage', { defaultMessage: 'Loading Kibana' })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="kibanaWelcomeView"
|
||||
id="kbn_legacy_browser_error"
|
||||
style={{ display: 'none' }}
|
||||
>
|
||||
<div className="kibanaLoaderWrap">
|
||||
<div className="kibanaWelcomeLogoCircle">
|
||||
<div className="kibanaWelcomeLogo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="kibanaWelcomeTitle">
|
||||
{i18n('core.ui.legacyBrowserTitle', {
|
||||
defaultMessage: 'Please upgrade your browser',
|
||||
})}
|
||||
</h2>
|
||||
<div className="kibanaWelcomeText">
|
||||
{i18n('core.ui.legacyBrowserMessage', {
|
||||
defaultMessage:
|
||||
'This Kibana installation has strict security requirements enabled that your current browser does not meet.',
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
{`
|
||||
// Since this is an unsafe inline script, this code will not run
|
||||
// in browsers that support content security policy(CSP). This is
|
||||
// intentional as we check for the existence of __kbnCspNotEnforced__ in
|
||||
// bootstrap.
|
||||
window.__kbnCspNotEnforced__ = true;
|
||||
`}
|
||||
</script>
|
||||
<script src={bootstrapScriptUrl} />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
};
|
|
@ -20,7 +20,7 @@
|
|||
import { createIndexMap } from './build_index_map';
|
||||
import { ObjectToConfigAdapter } from '../../../config';
|
||||
import { SavedObjectsSchema } from '../../schema';
|
||||
import { LegacyConfig } from '../../../legacy/config';
|
||||
import { LegacyConfig } from '../../../legacy';
|
||||
|
||||
const config = (new ObjectToConfigAdapter({}) as unknown) as LegacyConfig;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import { MappingProperties } from '../../mappings';
|
||||
import { SavedObjectsSchema } from '../../schema';
|
||||
import { LegacyConfig } from '../../../legacy/config';
|
||||
import { LegacyConfig } from '../../../legacy';
|
||||
|
||||
export interface CreateIndexMapOptions {
|
||||
config: LegacyConfig;
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
} from '../core/document_migrator';
|
||||
import { createIndexMap } from '../core/build_index_map';
|
||||
import { SavedObjectsConfigType } from '../../saved_objects_config';
|
||||
import { LegacyConfig } from '../../../legacy/config';
|
||||
import { LegacyConfig } from '../../../legacy';
|
||||
|
||||
export interface KibanaMigratorOptions {
|
||||
callCluster: CallCluster;
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
} from './';
|
||||
import { KibanaMigrator, IKibanaMigrator } from './migrations';
|
||||
import { CoreContext } from '../core_context';
|
||||
import { LegacyServiceDiscoverPlugins } from '../legacy/legacy_service';
|
||||
import { LegacyServiceDiscoverPlugins } from '../legacy';
|
||||
import { ElasticsearchServiceSetup, APICaller } from '../elasticsearch';
|
||||
import { KibanaConfigType } from '../kibana_config';
|
||||
import { migrationsRetryCallCluster } from '../elasticsearch/retry_call_cluster';
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyConfig } from '../../legacy/config';
|
||||
import { LegacyConfig } from '../../legacy';
|
||||
|
||||
interface SavedObjectsSchemaTypeDefinition {
|
||||
isNamespaceAgnostic: boolean;
|
||||
|
|
|
@ -52,7 +52,7 @@ import {
|
|||
MutatingOperationRefreshSetting,
|
||||
} from '../../types';
|
||||
import { validateConvertFilterToKueryNode } from './filter_utils';
|
||||
import { LegacyConfig } from '../../../legacy/config';
|
||||
import { LegacyConfig } from '../../../legacy';
|
||||
|
||||
// BEWARE: The SavedObjectClient depends on the implementation details of the SavedObjectsRepository
|
||||
// so any breaking changes to this repository are considered breaking changes to the SavedObjectsClient.
|
||||
|
|
|
@ -20,7 +20,7 @@ import { SavedObjectsRepository } from './repository';
|
|||
import { mockKibanaMigrator } from '../../migrations/kibana/kibana_migrator.mock';
|
||||
import { SavedObjectsSchema } from '../../schema';
|
||||
import { KibanaMigrator } from '../../migrations';
|
||||
import { LegacyConfig } from '../../../legacy/config';
|
||||
import { LegacyConfig } from '../../../legacy';
|
||||
jest.mock('./repository');
|
||||
|
||||
const { SavedObjectsRepository: originalRepository } = jest.requireActual('./repository');
|
||||
|
|
|
@ -236,7 +236,6 @@ export type SavedObjectsClientContract = Pick<SavedObjectsClient, keyof SavedObj
|
|||
* @deprecated
|
||||
*/
|
||||
export interface SavedObjectsLegacyUiExports {
|
||||
unknown: [{ pluginSpec: { getId: () => unknown }; type: unknown }] | undefined;
|
||||
savedObjectMappings: SavedObjectsMapping[];
|
||||
savedObjectMigrations: MigrationDefinition;
|
||||
savedObjectSchemas: SavedObjectsSchemaDefinition;
|
||||
|
|
|
@ -798,6 +798,11 @@ export interface IndexSettingsDeprecationInfo {
|
|||
[indexName: string]: DeprecationInfo[];
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface IRenderOptions {
|
||||
includeUserSettings?: boolean;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface IRouter {
|
||||
delete: RouteRegistrar<'delete'>;
|
||||
|
@ -822,6 +827,11 @@ export type ISavedObjectsRepository = Pick<SavedObjectsRepository, keyof SavedOb
|
|||
// @public
|
||||
export type IScopedClusterClient = Pick<ScopedClusterClient, 'callAsCurrentUser' | 'callAsInternalUser'>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface IScopedRenderingClient {
|
||||
render(options?: IRenderOptions): Promise<string>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface IUiSettingsClient {
|
||||
get: <T = any>(key: string) => Promise<T>;
|
||||
|
@ -897,34 +907,92 @@ export const kibanaResponseFactory: {
|
|||
// @public
|
||||
export type KnownHeaders = KnownKeys<IncomingHttpHeaders>;
|
||||
|
||||
// @internal @deprecated
|
||||
export interface LegacyConfig {
|
||||
// (undocumented)
|
||||
get<T>(key?: string): T;
|
||||
// (undocumented)
|
||||
has(key: string): boolean;
|
||||
// (undocumented)
|
||||
set(key: string, value: any): void;
|
||||
// Warning: (ae-forgotten-export) The symbol "LegacyVars" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
set(config: LegacyVars): void;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "ILegacyInternals" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @internal @deprecated (undocumented)
|
||||
export class LegacyInternals implements ILegacyInternals {
|
||||
constructor(uiExports: LegacyUiExports, config: LegacyConfig, server: Server);
|
||||
// (undocumented)
|
||||
getInjectedUiAppVars(id: string): Promise<Record<string, any>>;
|
||||
// (undocumented)
|
||||
getVars(id: string, request: LegacyRequest, injected?: LegacyVars): Promise<Record<string, any>>;
|
||||
private get defaultVars();
|
||||
// Warning: (ae-forgotten-export) The symbol "VarsInjector" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
injectUiAppVars(id: string, injector: VarsInjector): void;
|
||||
}
|
||||
|
||||
// @internal @deprecated (undocumented)
|
||||
export interface LegacyRenderOptions extends IRenderOptions {
|
||||
app?: {
|
||||
getId(): string;
|
||||
};
|
||||
vars?: Record<string, any>;
|
||||
}
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export interface LegacyRequest extends Request {
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "LegacyPlugins" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @internal @deprecated (undocumented)
|
||||
export interface LegacyServiceDiscoverPlugins extends LegacyPlugins {
|
||||
// (undocumented)
|
||||
pluginExtendedConfig: LegacyConfig;
|
||||
// (undocumented)
|
||||
settings: LegacyVars;
|
||||
}
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export interface LegacyServiceSetupDeps {
|
||||
// Warning: (ae-forgotten-export) The symbol "InternalCoreSetup" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "LegacyCoreSetup" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
core: InternalCoreSetup & {
|
||||
plugins: PluginsServiceSetup;
|
||||
};
|
||||
core: LegacyCoreSetup;
|
||||
// (undocumented)
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export interface LegacyServiceStartDeps {
|
||||
// Warning: (ae-forgotten-export) The symbol "InternalCoreStart" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "LegacyCoreStart" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
core: InternalCoreStart & {
|
||||
plugins: PluginsServiceStart;
|
||||
};
|
||||
core: LegacyCoreStart;
|
||||
// (undocumented)
|
||||
plugins: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "SavedObjectsLegacyUiExports" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @internal @deprecated (undocumented)
|
||||
export type LegacyUiExports = SavedObjectsLegacyUiExports & {
|
||||
defaultInjectedVarProviders?: VarsProvider[];
|
||||
injectedVarsReplacers?: VarsReplacer[];
|
||||
navLinkSpecs?: LegacyNavLinkSpec[] | null;
|
||||
uiAppSpecs?: Array<LegacyAppSpec | undefined>;
|
||||
unknown?: [{
|
||||
pluginSpec: LegacyPluginSpec;
|
||||
type: unknown;
|
||||
}];
|
||||
};
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "lifecycleResponseFactory" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public
|
||||
|
@ -1161,6 +1229,11 @@ export type RedirectResponseOptions = HttpResponseOptions & {
|
|||
};
|
||||
};
|
||||
|
||||
// @internal (undocumented)
|
||||
export interface RenderingServiceSetup {
|
||||
render<R extends KibanaRequest | LegacyRequest>(request: R, uiSettings: IUiSettingsClient, options?: R extends LegacyRequest ? LegacyRenderOptions : IRenderOptions): Promise<string>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type RequestHandler<P = unknown, Q = unknown, B = unknown, Method extends RouteMethod = any> = (context: RequestHandlerContext, request: KibanaRequest<P, Q, B, Method>, response: KibanaResponseFactory) => IKibanaResponse<any> | Promise<IKibanaResponse<any>>;
|
||||
|
||||
|
@ -1168,6 +1241,7 @@ export type RequestHandler<P = unknown, Q = unknown, B = unknown, Method extends
|
|||
export interface RequestHandlerContext {
|
||||
// (undocumented)
|
||||
core: {
|
||||
rendering: IScopedRenderingClient;
|
||||
savedObjects: {
|
||||
client: SavedObjectsClientContract;
|
||||
};
|
||||
|
@ -1718,7 +1792,6 @@ export class SavedObjectsRepository {
|
|||
bulkUpdate<T extends SavedObjectAttributes = any>(objects: Array<SavedObjectsBulkUpdateObject<T>>, options?: SavedObjectsBulkUpdateOptions): Promise<SavedObjectsBulkUpdateResponse<T>>;
|
||||
create<T extends SavedObjectAttributes>(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise<SavedObject<T>>;
|
||||
// Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "LegacyConfig" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @internal
|
||||
static createRepository(migrator: KibanaMigrator, schema: SavedObjectsSchema, config: LegacyConfig, indexName: string, callCluster: APICaller, extraTypes?: string[], injectedConstructor?: any): any;
|
||||
|
@ -1893,6 +1966,11 @@ export const validBodyOutput: readonly ["data", "stream"];
|
|||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/core/server/http/router/response.ts:316:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/legacy/types.ts:158:3 - (ae-forgotten-export) The symbol "VarsProvider" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/legacy/types.ts:159:3 - (ae-forgotten-export) The symbol "VarsReplacer" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/legacy/types.ts:160:3 - (ae-forgotten-export) The symbol "LegacyNavLinkSpec" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/legacy/types.ts:161:3 - (ae-forgotten-export) The symbol "LegacyAppSpec" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/legacy/types.ts:162:16 - (ae-forgotten-export) The symbol "LegacyPluginSpec" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/plugins_service.ts:43:5 - (ae-forgotten-export) The symbol "InternalPluginInfo" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:221:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/types.ts:221:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts
|
||||
|
|
|
@ -35,14 +35,8 @@ jest.doMock('./elasticsearch/elasticsearch_service', () => ({
|
|||
ElasticsearchService: jest.fn(() => mockElasticsearchService),
|
||||
}));
|
||||
|
||||
import { ILegacyService } from './legacy/legacy_service';
|
||||
export const mockLegacyService: ILegacyService = {
|
||||
legacyId: Symbol(),
|
||||
discoverPlugins: jest.fn().mockReturnValue({ uiExports: {} }),
|
||||
setup: jest.fn(),
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
};
|
||||
import { legacyServiceMock } from './legacy/legacy_service.mock';
|
||||
export const mockLegacyService = legacyServiceMock.create();
|
||||
jest.mock('./legacy/legacy_service', () => ({
|
||||
LegacyService: jest.fn(() => mockLegacyService),
|
||||
}));
|
||||
|
@ -76,6 +70,10 @@ jest.doMock('./legacy/config/ensure_valid_configuration', () => ({
|
|||
ensureValidConfiguration: mockEnsureValidConfiguration,
|
||||
}));
|
||||
|
||||
import { RenderingService, mockRenderingService } from './rendering/__mocks__/rendering_service';
|
||||
export { mockRenderingService };
|
||||
jest.doMock('./rendering/rendering_service', () => ({ RenderingService }));
|
||||
|
||||
import { uuidServiceMock } from './uuid/uuid_service.mock';
|
||||
export const mockUuidService = uuidServiceMock.create();
|
||||
jest.doMock('./uuid/uuid_service', () => ({
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
mockContextService,
|
||||
mockEnsureValidConfiguration,
|
||||
mockUiSettingsService,
|
||||
mockRenderingService,
|
||||
} from './server.test.mocks';
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
@ -59,6 +60,7 @@ test('sets up services on "setup"', async () => {
|
|||
expect(mockLegacyService.setup).not.toHaveBeenCalled();
|
||||
expect(mockSavedObjectsService.setup).not.toHaveBeenCalled();
|
||||
expect(mockUiSettingsService.setup).not.toHaveBeenCalled();
|
||||
expect(mockRenderingService.setup).not.toHaveBeenCalled();
|
||||
|
||||
await server.setup();
|
||||
|
||||
|
@ -68,6 +70,7 @@ test('sets up services on "setup"', async () => {
|
|||
expect(mockLegacyService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockSavedObjectsService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockUiSettingsService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockRenderingService.setup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('injects legacy dependency to context#setup()', async () => {
|
||||
|
@ -155,6 +158,7 @@ test(`doesn't setup core services if config validation fails`, async () => {
|
|||
expect(mockPluginsService.setup).not.toHaveBeenCalled();
|
||||
expect(mockLegacyService.setup).not.toHaveBeenCalled();
|
||||
expect(mockUiSettingsService.setup).not.toHaveBeenCalled();
|
||||
expect(mockRenderingService.setup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test(`doesn't setup core services if legacy config validation fails`, async () => {
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
} from './config';
|
||||
import { ElasticsearchService } from './elasticsearch';
|
||||
import { HttpService, InternalHttpServiceSetup } from './http';
|
||||
import { RenderingService, RenderingServiceSetup } from './rendering';
|
||||
import { LegacyService, ensureValidConfiguration } from './legacy';
|
||||
import { Logger, LoggerFactory } from './logging';
|
||||
import { UiSettingsService } from './ui_settings';
|
||||
|
@ -44,7 +45,7 @@ import { config as pathConfig } from './path';
|
|||
import { config as kibanaConfig } from './kibana_config';
|
||||
import { config as savedObjectsConfig } from './saved_objects';
|
||||
import { config as uiSettingsConfig } from './ui_settings';
|
||||
import { mapToObject } from '../utils/';
|
||||
import { mapToObject } from '../utils';
|
||||
import { ContextService } from './context';
|
||||
import { RequestHandlerContext } from '.';
|
||||
import { InternalCoreSetup } from './internal_types';
|
||||
|
@ -60,6 +61,7 @@ export class Server {
|
|||
private readonly context: ContextService;
|
||||
private readonly elasticsearch: ElasticsearchService;
|
||||
private readonly http: HttpService;
|
||||
private readonly rendering: RenderingService;
|
||||
private readonly legacy: LegacyService;
|
||||
private readonly log: Logger;
|
||||
private readonly plugins: PluginsService;
|
||||
|
@ -78,6 +80,7 @@ export class Server {
|
|||
const core = { coreId, configService: this.configService, env, logger };
|
||||
this.context = new ContextService(core);
|
||||
this.http = new HttpService(core);
|
||||
this.rendering = new RenderingService(core);
|
||||
this.plugins = new PluginsService(core);
|
||||
this.legacy = new LegacyService(core);
|
||||
this.elasticsearch = new ElasticsearchService(core);
|
||||
|
@ -144,12 +147,18 @@ export class Server {
|
|||
|
||||
const pluginsSetup = await this.plugins.setup(coreSetup);
|
||||
|
||||
const renderingSetup = await this.rendering.setup({
|
||||
http: httpSetup,
|
||||
legacyPlugins,
|
||||
plugins: pluginsSetup,
|
||||
});
|
||||
|
||||
await this.legacy.setup({
|
||||
core: { ...coreSetup, plugins: pluginsSetup },
|
||||
core: { ...coreSetup, plugins: pluginsSetup, rendering: renderingSetup },
|
||||
plugins: mapToObject(pluginsSetup.contracts),
|
||||
});
|
||||
|
||||
this.registerCoreContext(coreSetup);
|
||||
this.registerCoreContext(coreSetup, renderingSetup);
|
||||
|
||||
return coreSetup;
|
||||
}
|
||||
|
@ -178,6 +187,7 @@ export class Server {
|
|||
});
|
||||
|
||||
await this.http.start();
|
||||
await this.rendering.start();
|
||||
|
||||
return coreStart;
|
||||
}
|
||||
|
@ -191,6 +201,7 @@ export class Server {
|
|||
await this.elasticsearch.stop();
|
||||
await this.http.stop();
|
||||
await this.uiSettings.stop();
|
||||
await this.rendering.stop();
|
||||
}
|
||||
|
||||
private registerDefaultRoute(httpSetup: InternalHttpServiceSetup) {
|
||||
|
@ -200,16 +211,20 @@ export class Server {
|
|||
);
|
||||
}
|
||||
|
||||
private registerCoreContext(coreSetup: InternalCoreSetup) {
|
||||
private registerCoreContext(coreSetup: InternalCoreSetup, rendering: RenderingServiceSetup) {
|
||||
coreSetup.http.registerRouteHandlerContext(
|
||||
coreId,
|
||||
'core',
|
||||
async (context, req): Promise<RequestHandlerContext['core']> => {
|
||||
async (context, req, res): Promise<RequestHandlerContext['core']> => {
|
||||
const adminClient = await coreSetup.elasticsearch.adminClient$.pipe(take(1)).toPromise();
|
||||
const dataClient = await coreSetup.elasticsearch.dataClient$.pipe(take(1)).toPromise();
|
||||
const savedObjectsClient = coreSetup.savedObjects.getScopedClient(req);
|
||||
const uiSettingsClient = coreSetup.uiSettings.asScopedToClient(savedObjectsClient);
|
||||
|
||||
return {
|
||||
rendering: {
|
||||
render: rendering.render.bind(rendering, req, uiSettingsClient),
|
||||
},
|
||||
savedObjects: {
|
||||
// Note: the client provider doesn't support new ES clients
|
||||
// emitted from adminClient$
|
||||
|
@ -220,7 +235,7 @@ export class Server {
|
|||
dataClient: dataClient.asScoped(req),
|
||||
},
|
||||
uiSettings: {
|
||||
client: coreSetup.uiSettings.asScopedToClient(savedObjectsClient),
|
||||
client: uiSettingsClient,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@
|
|||
export { PluginOpaqueId } from './plugins/types';
|
||||
export * from './saved_objects/types';
|
||||
export * from './ui_settings/types';
|
||||
export * from './legacy/types';
|
||||
export { EnvironmentMode, PackageInfo } from './config/types';
|
||||
export { ICspConfig } from './csp';
|
||||
|
|
|
@ -37,6 +37,9 @@ const createClientMock = () => {
|
|||
isOverridden: jest.fn(),
|
||||
};
|
||||
mocked.get.mockResolvedValue(false);
|
||||
mocked.getAll.mockResolvedValue({});
|
||||
mocked.getRegistered.mockReturnValue({});
|
||||
mocked.getUserProvided.mockResolvedValue({});
|
||||
return mocked;
|
||||
};
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ const telemetry = (kibana: any) => {
|
|||
isNamespaceAgnostic: true,
|
||||
},
|
||||
},
|
||||
async replaceInjectedVars(originalInjectedVars: any, request: any) {
|
||||
const telemetryInjectedVars = await replaceTelemetryInjectedVars(request);
|
||||
async replaceInjectedVars(originalInjectedVars: any, request: any, server: any) {
|
||||
const telemetryInjectedVars = await replaceTelemetryInjectedVars(request, server);
|
||||
return Object.assign({}, originalInjectedVars, telemetryInjectedVars);
|
||||
},
|
||||
injectDefaultVars(server: Server) {
|
||||
|
|
|
@ -23,8 +23,8 @@ import { getTelemetrySendUsageFrom } from './get_telemetry_send_usage_from';
|
|||
import { getTelemetryAllowChangingOptInStatus } from './get_telemetry_allow_changing_opt_in_status';
|
||||
import { getNotifyUserAboutOptInDefault } from './get_telemetry_notify_user_about_optin_default';
|
||||
|
||||
export async function replaceTelemetryInjectedVars(request: any) {
|
||||
const config = request.server.config();
|
||||
export async function replaceTelemetryInjectedVars(request: any, server: any) {
|
||||
const config = server.config();
|
||||
const configTelemetrySendUsageFrom = config.get('telemetry.sendUsageFrom');
|
||||
const configTelemetryOptIn = config.get('telemetry.optIn');
|
||||
const configTelemetryAllowChangingOptInStatus = config.get('telemetry.allowChangingOptInStatus');
|
||||
|
@ -38,7 +38,7 @@ export async function replaceTelemetryInjectedVars(request: any) {
|
|||
}
|
||||
|
||||
const currentKibanaVersion = config.get('pkg.version');
|
||||
const savedObjectsClient = request.getSavedObjectsClient();
|
||||
const savedObjectsClient = server.savedObjects.getScopedSavedObjectsClient(request);
|
||||
const telemetrySavedObject = await getTelemetrySavedObject(savedObjectsClient);
|
||||
const allowChangingOptInStatus = getTelemetryAllowChangingOptInStatus({
|
||||
configTelemetryAllowChangingOptInStatus,
|
||||
|
|
62
src/legacy/server/kbn_server.d.ts
vendored
62
src/legacy/server/kbn_server.d.ts
vendored
|
@ -20,24 +20,29 @@
|
|||
import { ResponseObject, Server } from 'hapi';
|
||||
import { UnwrapPromise } from '@kbn/utility-types';
|
||||
|
||||
import { SavedObjectsClientProviderOptions, CoreSetup, CoreStart } from 'src/core/server';
|
||||
import {
|
||||
ConfigService,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
ElasticsearchServiceSetup,
|
||||
EnvironmentMode,
|
||||
LoggerFactory,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsLegacyService,
|
||||
SavedObjectsClientProviderOptions,
|
||||
IUiSettingsClient,
|
||||
PackageInfo,
|
||||
LegacyRequest,
|
||||
LegacyServiceSetupDeps,
|
||||
LegacyServiceStartDeps,
|
||||
LegacyServiceDiscoverPlugins,
|
||||
} from '../../core/server';
|
||||
|
||||
import { LegacyServiceSetupDeps, LegacyServiceStartDeps } from '../../core/server/';
|
||||
// Disable lint errors for imports from src/core/server/saved_objects until SavedObjects migration is complete
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { SavedObjectsManagement } from '../../core/server/saved_objects/management';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { LegacyConfig } from '../../core/server/legacy';
|
||||
import { LegacyConfig, ILegacyService, ILegacyInternals } from '../../core/server/legacy';
|
||||
import { ApmOssPlugin } from '../core_plugins/apm_oss';
|
||||
import { CallClusterWithRequest, ElasticsearchPlugin } from '../core_plugins/elasticsearch';
|
||||
import { UsageCollectionSetup } from '../../plugins/usage_collection/server';
|
||||
|
@ -104,38 +109,61 @@ export interface PluginsSetup {
|
|||
[key: string]: object;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default class KbnServer {
|
||||
public readonly newPlatform: {
|
||||
export interface KibanaCore {
|
||||
__internals: {
|
||||
hapiServer: LegacyServiceSetupDeps['core']['http']['server'];
|
||||
uiPlugins: LegacyServiceSetupDeps['core']['plugins']['uiPlugins'];
|
||||
elasticsearch: LegacyServiceSetupDeps['core']['elasticsearch'];
|
||||
uiSettings: LegacyServiceSetupDeps['core']['uiSettings'];
|
||||
hapiServer: LegacyServiceSetupDeps['core']['http']['server'];
|
||||
kibanaMigrator: LegacyServiceStartDeps['core']['savedObjects']['migrator'];
|
||||
legacy: ILegacyInternals;
|
||||
rendering: LegacyServiceSetupDeps['core']['rendering'];
|
||||
uiPlugins: LegacyServiceSetupDeps['core']['plugins']['uiPlugins'];
|
||||
uiSettings: LegacyServiceSetupDeps['core']['uiSettings'];
|
||||
savedObjectsClientProvider: LegacyServiceStartDeps['core']['savedObjects']['clientProvider'];
|
||||
};
|
||||
env: {
|
||||
mode: Readonly<EnvironmentMode>;
|
||||
packageInfo: Readonly<PackageInfo>;
|
||||
};
|
||||
coreContext: {
|
||||
logger: LoggerFactory;
|
||||
};
|
||||
setup: {
|
||||
setupDeps: {
|
||||
core: CoreSetup;
|
||||
plugins: PluginsSetup;
|
||||
};
|
||||
start: {
|
||||
core: CoreStart;
|
||||
startDeps: {
|
||||
core: CoreSetup;
|
||||
plugins: Record<string, object>;
|
||||
};
|
||||
stop: null;
|
||||
logger: LoggerFactory;
|
||||
}
|
||||
|
||||
export interface NewPlatform {
|
||||
__internals: KibanaCore['__internals'];
|
||||
env: KibanaCore['env'];
|
||||
coreContext: {
|
||||
logger: KibanaCore['logger'];
|
||||
};
|
||||
setup: KibanaCore['setupDeps'];
|
||||
start: KibanaCore['startDeps'];
|
||||
stop: null;
|
||||
}
|
||||
|
||||
export type LegacyPlugins = Pick<
|
||||
LegacyServiceDiscoverPlugins,
|
||||
'pluginSpecs' | 'disabledPluginSpecs' | 'uiExports'
|
||||
>;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default class KbnServer {
|
||||
public readonly newPlatform: NewPlatform;
|
||||
public server: Server;
|
||||
public inject: Server['inject'];
|
||||
public pluginSpecs: any[];
|
||||
|
||||
constructor(settings: any, core: any);
|
||||
constructor(
|
||||
settings: Record<string, any>,
|
||||
config: KibanaConfig,
|
||||
core: KibanaCore,
|
||||
legacyPlugins: LegacyPlugins
|
||||
);
|
||||
|
||||
public ready(): Promise<void>;
|
||||
public mixin(...fns: KbnMixinFunc[]): Promise<void>;
|
||||
|
|
|
@ -42,9 +42,21 @@ import { uiMixin } from '../ui';
|
|||
import { sassMixin } from './sass';
|
||||
import { i18nMixin } from './i18n';
|
||||
|
||||
/**
|
||||
* @typedef {import('./kbn_server').KibanaConfig} KibanaConfig
|
||||
* @typedef {import('./kbn_server').KibanaCore} KibanaCore
|
||||
* @typedef {import('./kbn_server').LegacyPlugins} LegacyPlugins
|
||||
*/
|
||||
|
||||
const rootDir = fromRoot('.');
|
||||
|
||||
export default class KbnServer {
|
||||
/**
|
||||
* @param {Record<string, any>} settings
|
||||
* @param {KibanaConfig} config
|
||||
* @param {KibanaCore} core
|
||||
* @param {LegacyPlugins} legacyPlugins
|
||||
*/
|
||||
constructor(settings, config, core, legacyPlugins) {
|
||||
this.name = pkg.name;
|
||||
this.version = pkg.version;
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { delay } from 'bluebird';
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
import cheerio from 'cheerio';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
import * as getUiSettingsServiceForRequestNS from '../ui_settings/ui_settings_service_for_request';
|
||||
import { createRoot, getKbnServer, request } from '../../../test_utils/kbn_server';
|
||||
|
||||
const getInjectedVarsFromResponse = resp => {
|
||||
expect(resp.statusCode).to.be(200);
|
||||
const $ = cheerio.load(resp.text);
|
||||
const data = $('kbn-injected-metadata').attr('data');
|
||||
return JSON.parse(data).vars;
|
||||
};
|
||||
|
||||
const injectReplacer = (kbnServer, replacer) => {
|
||||
// normally the replacer would be defined in a plugin's uiExports,
|
||||
// but that requires stubbing out an entire plugin directory for
|
||||
// each test, so we fake it and jam the replacer into uiExports
|
||||
const { injectedVarsReplacers = [] } = kbnServer.uiExports;
|
||||
kbnServer.uiExports.injectedVarsReplacers = [...injectedVarsReplacers, replacer];
|
||||
};
|
||||
|
||||
describe('UiExports', function() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
|
||||
let root;
|
||||
let kbnServer;
|
||||
before(async () => {
|
||||
this.slow(2000);
|
||||
this.timeout(30000);
|
||||
|
||||
root = root = createRoot({
|
||||
// inject an app so we can hit /app/{id}
|
||||
plugins: { paths: [resolve(__dirname, './fixtures/test_app')] },
|
||||
});
|
||||
|
||||
await root.setup();
|
||||
await root.start();
|
||||
|
||||
kbnServer = getKbnServer(root);
|
||||
|
||||
// Mock out the ui settings which depends on ES
|
||||
sandbox.stub(getUiSettingsServiceForRequestNS, 'getUiSettingsServiceForRequest').returns({
|
||||
getRegistered: noop,
|
||||
getUserProvided: noop,
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await root.shutdown();
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
let originalInjectedVarsReplacers;
|
||||
beforeEach(() => {
|
||||
originalInjectedVarsReplacers = kbnServer.uiExports.injectedVarsReplacers;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
kbnServer.uiExports.injectedVarsReplacers = originalInjectedVarsReplacers;
|
||||
});
|
||||
|
||||
describe('#replaceInjectedVars', function() {
|
||||
it('allows sync replacing of injected vars', async () => {
|
||||
injectReplacer(kbnServer, () => ({ a: 1 }));
|
||||
|
||||
const resp = await request.get(root, '/app/test_app').expect(200);
|
||||
const injectedVars = getInjectedVarsFromResponse(resp);
|
||||
|
||||
expect(injectedVars).to.eql({ a: 1 });
|
||||
});
|
||||
|
||||
it('allows async replacing of injected vars', async () => {
|
||||
const asyncThing = () => delay(100).return('world');
|
||||
|
||||
injectReplacer(kbnServer, async () => {
|
||||
return {
|
||||
hello: await asyncThing(),
|
||||
};
|
||||
});
|
||||
|
||||
const resp = await request.get(root, '/app/test_app').expect(200);
|
||||
const injectedVars = getInjectedVarsFromResponse(resp);
|
||||
|
||||
expect(injectedVars).to.eql({
|
||||
hello: 'world',
|
||||
});
|
||||
});
|
||||
|
||||
it('passes originalInjectedVars, request, and server to replacer', async () => {
|
||||
const stub = sinon.stub();
|
||||
injectReplacer(kbnServer, () => ({ foo: 'bar' }));
|
||||
injectReplacer(kbnServer, stub);
|
||||
|
||||
await await request.get(root, '/app/test_app').expect(200);
|
||||
|
||||
sinon.assert.calledOnce(stub);
|
||||
expect(stub.firstCall.args[0]).to.eql({ foo: 'bar' }); // originalInjectedVars
|
||||
expect(stub.firstCall.args[1]).to.have.property('path', '/app/test_app'); // request
|
||||
expect(stub.firstCall.args[1]).to.have.property('server', kbnServer.server); // request
|
||||
expect(stub.firstCall.args[2]).to.be(kbnServer.server);
|
||||
});
|
||||
|
||||
it('calls the methods sequentially', async () => {
|
||||
injectReplacer(kbnServer, () => ({ name: '' }));
|
||||
injectReplacer(kbnServer, orig => ({ name: orig.name + 's' }));
|
||||
injectReplacer(kbnServer, orig => ({ name: orig.name + 'a' }));
|
||||
injectReplacer(kbnServer, orig => ({ name: orig.name + 'm' }));
|
||||
|
||||
const resp = await request.get(root, '/app/test_app').expect(200);
|
||||
const injectedVars = getInjectedVarsFromResponse(resp);
|
||||
|
||||
expect(injectedVars).to.eql({ name: 'sam' });
|
||||
});
|
||||
|
||||
it('propagates errors thrown in replacers', async () => {
|
||||
injectReplacer(kbnServer, async () => {
|
||||
await delay(100);
|
||||
throw new Error('replacer failed');
|
||||
});
|
||||
|
||||
await request.get(root, '/app/test_app').expect(500);
|
||||
});
|
||||
|
||||
it('starts off with the injected vars for the app merged with the default injected vars', async () => {
|
||||
const stub = sinon.stub();
|
||||
injectReplacer(kbnServer, stub);
|
||||
|
||||
await request.get(root, '/app/test_app').expect(200);
|
||||
|
||||
sinon.assert.calledOnce(stub);
|
||||
const args = stub.lastCall.args[0];
|
||||
expect(args.from_defaults).to.be(true);
|
||||
expect(args.from_test_app).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -19,6 +19,15 @@
|
|||
|
||||
import { UiApp } from './ui_app';
|
||||
|
||||
/**
|
||||
* @typedef {import('../../server/kbn_server').default} KbnServer
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {KbnServer} kbnServer
|
||||
* @param {KbnServer['server']} server
|
||||
*/
|
||||
export function uiAppsMixin(kbnServer, server) {
|
||||
const { uiAppSpecs = [] } = kbnServer.uiExports;
|
||||
const existingIds = new Set();
|
||||
|
@ -47,21 +56,12 @@ export function uiAppsMixin(kbnServer, server) {
|
|||
server.decorate('server', 'getAllUiApps', () => kbnServer.uiApps.slice(0));
|
||||
server.decorate('server', 'getUiAppById', id => appsById.get(id));
|
||||
server.decorate('server', 'getHiddenUiAppById', id => hiddenAppsById.get(id));
|
||||
|
||||
const injectedVarProviders = [];
|
||||
server.decorate('server', 'injectUiAppVars', (appId, provider) => {
|
||||
injectedVarProviders.push({ appId, provider });
|
||||
});
|
||||
|
||||
server.decorate('server', 'getInjectedUiAppVars', async appId => {
|
||||
return await injectedVarProviders
|
||||
.filter(p => p.appId === appId)
|
||||
.reduce(
|
||||
async (acc, { provider }) => ({
|
||||
...(await acc),
|
||||
...(await provider(server)),
|
||||
}),
|
||||
{}
|
||||
server.decorate('server', 'injectUiAppVars', (appId, provider) =>
|
||||
kbnServer.newPlatform.__internals.legacy.injectUiAppVars(appId, provider)
|
||||
);
|
||||
server.decorate(
|
||||
'server',
|
||||
'getInjectedUiAppVars',
|
||||
async appId => await kbnServer.newPlatform.__internals.legacy.getInjectedUiAppVars(appId)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { LegacyInternals } from '../../../core/server';
|
||||
|
||||
import { uiAppsMixin } from './ui_apps_mixin';
|
||||
|
||||
jest.mock('./ui_app', () => ({
|
||||
|
@ -37,10 +39,10 @@ jest.mock('./ui_app', () => ({
|
|||
describe('UiAppsMixin', () => {
|
||||
let kbnServer;
|
||||
let server;
|
||||
let uiExports;
|
||||
|
||||
beforeEach(() => {
|
||||
kbnServer = {
|
||||
uiExports: {
|
||||
uiExports = {
|
||||
uiAppSpecs: [
|
||||
{
|
||||
id: 'foo',
|
||||
|
@ -51,9 +53,7 @@ describe('UiAppsMixin', () => {
|
|||
hidden: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
server = {
|
||||
decorate: jest.fn((type, name, value) => {
|
||||
if (type !== 'server') {
|
||||
|
@ -63,6 +63,14 @@ describe('UiAppsMixin', () => {
|
|||
server[name] = value;
|
||||
}),
|
||||
};
|
||||
kbnServer = {
|
||||
uiExports,
|
||||
newPlatform: {
|
||||
__internals: {
|
||||
legacy: new LegacyInternals(uiExports, {}, server),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
uiAppsMixin(kbnServer, server);
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ import { CoreSystem } from '__kibanaCore__'
|
|||
|
||||
const injectedMetadata = JSON.parse(document.querySelector('kbn-injected-metadata').getAttribute('data'));
|
||||
|
||||
${apmInit('injectedMetadata.apm')}
|
||||
${apmInit('injectedMetadata.vars.apmConfig')}
|
||||
|
||||
i18n.load(injectedMetadata.i18n.translationsUrl)
|
||||
.catch(e => e)
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { SavedObjectsLegacyUiExports } from 'src/core/server/types';
|
||||
import { LegacyUiExports } from '../../../core/server';
|
||||
|
||||
// @ts-ignore
|
||||
import { UI_EXPORT_DEFAULTS } from './ui_export_defaults';
|
||||
// @ts-ignore
|
||||
|
@ -26,6 +26,6 @@ import * as uiExportTypeReducers from './ui_export_types';
|
|||
// @ts-ignore
|
||||
import { reduceExportSpecs } from '../../plugin_discovery';
|
||||
|
||||
export function collectUiExports(pluginSpecs: unknown[]): SavedObjectsLegacyUiExports {
|
||||
export function collectUiExports(pluginSpecs: unknown[]): LegacyUiExports {
|
||||
return reduceExportSpecs(pluginSpecs, uiExportTypeReducers, UI_EXPORT_DEFAULTS);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import { fieldFormatsMixin } from './field_formats';
|
|||
import { tutorialsMixin } from './tutorials_mixin';
|
||||
import { uiAppsMixin } from './ui_apps';
|
||||
import { uiBundlesMixin } from './ui_bundles';
|
||||
import { uiNavLinksMixin } from './ui_nav_links';
|
||||
import { uiRenderMixin } from './ui_render';
|
||||
import { uiSettingsMixin } from './ui_settings';
|
||||
|
||||
|
@ -31,6 +30,5 @@ export async function uiMixin(kbnServer) {
|
|||
await kbnServer.mixin(uiSettingsMixin);
|
||||
await kbnServer.mixin(fieldFormatsMixin);
|
||||
await kbnServer.mixin(tutorialsMixin);
|
||||
await kbnServer.mixin(uiNavLinksMixin);
|
||||
await kbnServer.mixin(uiRenderMixin);
|
||||
}
|
||||
|
|
|
@ -18,4 +18,3 @@
|
|||
*/
|
||||
|
||||
export { UiNavLink } from './ui_nav_link';
|
||||
export { uiNavLinksMixin } from './ui_nav_links_mixin';
|
||||
|
|
|
@ -17,43 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { take } from 'rxjs/operators';
|
||||
import { createHash } from 'crypto';
|
||||
import { props, reduce as reduceAsync } from 'bluebird';
|
||||
import Boom from 'boom';
|
||||
import { resolve } from 'path';
|
||||
import { get } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AppBootstrap } from './bootstrap';
|
||||
import { mergeVariables } from './lib';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { fromRoot } from '../../../core/server/utils';
|
||||
import { getApmConfig } from '../apm';
|
||||
|
||||
/**
|
||||
* @typedef {import('../../server/kbn_server').default} KbnServer
|
||||
* @typedef {import('../../server/kbn_server').ResponseToolkit} ResponseToolkit
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {KbnServer} kbnServer
|
||||
* @param {KbnServer['server']} server
|
||||
* @param {KbnServer['config']} config
|
||||
*/
|
||||
export function uiRenderMixin(kbnServer, server, config) {
|
||||
function replaceInjectedVars(request, injectedVars) {
|
||||
const { injectedVarsReplacers = [] } = kbnServer.uiExports;
|
||||
|
||||
return reduceAsync(
|
||||
injectedVarsReplacers,
|
||||
async (acc, replacer) => await replacer(acc, request, kbnServer.server),
|
||||
injectedVars
|
||||
);
|
||||
}
|
||||
|
||||
let defaultInjectedVars = {};
|
||||
kbnServer.afterPluginsInit(() => {
|
||||
const { defaultInjectedVarProviders = [] } = kbnServer.uiExports;
|
||||
defaultInjectedVars = defaultInjectedVarProviders.reduce(
|
||||
(allDefaults, { fn, pluginSpec }) =>
|
||||
mergeVariables(
|
||||
allDefaults,
|
||||
fn(kbnServer.server, pluginSpec.readConfigValue(kbnServer.config, []))
|
||||
),
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
// render all views from ./views
|
||||
server.setupViews(resolve(__dirname, 'views'));
|
||||
|
||||
|
@ -192,121 +176,41 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
},
|
||||
});
|
||||
|
||||
async function getUiSettings({ request, includeUserProvidedConfig }) {
|
||||
const uiSettings = request.getUiSettingsService();
|
||||
return props({
|
||||
defaults: uiSettings.getRegistered(),
|
||||
user: includeUserProvidedConfig && uiSettings.getUserProvided(),
|
||||
});
|
||||
}
|
||||
|
||||
function getLegacyKibanaPayload({ app, basePath, uiSettings }) {
|
||||
return {
|
||||
app,
|
||||
bundleId: `app:${app.getId()}`,
|
||||
nav: server.getUiNavLinks(),
|
||||
version: kbnServer.version,
|
||||
branch: config.get('pkg.branch'),
|
||||
buildNum: config.get('pkg.buildNum'),
|
||||
buildSha: config.get('pkg.buildSha'),
|
||||
serverName: config.get('server.name'),
|
||||
devMode: config.get('env.dev'),
|
||||
basePath,
|
||||
uiSettings,
|
||||
};
|
||||
}
|
||||
|
||||
async function renderApp({
|
||||
app,
|
||||
async function renderApp(
|
||||
h,
|
||||
includeUserProvidedConfig = true,
|
||||
injectedVarsOverrides = {},
|
||||
}) {
|
||||
const request = h.request;
|
||||
const basePath = request.getBasePath();
|
||||
const uiSettings = await getUiSettings({ request, includeUserProvidedConfig });
|
||||
app = app || { getId: () => 'core' };
|
||||
|
||||
const legacyMetadata = getLegacyKibanaPayload({
|
||||
app = { getId: () => 'core' },
|
||||
includeUserSettings = true,
|
||||
overrides = {}
|
||||
) {
|
||||
const { http } = kbnServer.newPlatform.setup.core;
|
||||
const {
|
||||
rendering,
|
||||
legacy,
|
||||
savedObjectsClientProvider: savedObjects,
|
||||
uiSettings: { asScopedToClient },
|
||||
} = kbnServer.newPlatform.__internals;
|
||||
const uiSettings = asScopedToClient(savedObjects.getClient(h.request));
|
||||
const vars = await legacy.getVars(app.getId(), h.request, {
|
||||
apmConfig: getApmConfig(app),
|
||||
...overrides,
|
||||
});
|
||||
const content = await rendering.render(h.request, uiSettings, {
|
||||
app,
|
||||
basePath,
|
||||
uiSettings,
|
||||
includeUserSettings,
|
||||
vars,
|
||||
});
|
||||
|
||||
// Get the list of new platform plugins.
|
||||
// Convert the Map into an array of objects so it is JSON serializable and order is preserved.
|
||||
const uiPluginConfigs = kbnServer.newPlatform.__internals.uiPlugins.browserConfigs;
|
||||
const uiPlugins = await Promise.all(
|
||||
[...kbnServer.newPlatform.__internals.uiPlugins.public.entries()].map(
|
||||
async ([id, plugin]) => {
|
||||
const config$ = uiPluginConfigs.get(id);
|
||||
if (config$) {
|
||||
return { id, plugin, config: await config$.pipe(take(1)).toPromise() };
|
||||
} else {
|
||||
return { id, plugin, config: {} };
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
const { strict, warnLegacyBrowsers, header } = kbnServer.newPlatform.setup.core.http.csp;
|
||||
|
||||
const response = h.view('ui_app', {
|
||||
strictCsp: strict,
|
||||
uiPublicUrl: `${basePath}/ui`,
|
||||
bootstrapScriptUrl: `${basePath}/bundles/app/${app.getId()}/bootstrap.js`,
|
||||
i18n: (id, options) => i18n.translate(id, options),
|
||||
locale: i18n.getLocale(),
|
||||
darkMode: get(uiSettings.user, ['theme:darkMode', 'userValue'], false),
|
||||
|
||||
injectedMetadata: {
|
||||
version: kbnServer.version,
|
||||
buildNumber: config.get('pkg.buildNum'),
|
||||
branch: config.get('pkg.branch'),
|
||||
basePath,
|
||||
env: kbnServer.newPlatform.env,
|
||||
legacyMode: app.getId() !== 'core',
|
||||
i18n: {
|
||||
translationsUrl: `${basePath}/translations/${i18n.getLocale()}.json`,
|
||||
},
|
||||
csp: {
|
||||
warnLegacyBrowsers,
|
||||
},
|
||||
vars: await replaceInjectedVars(
|
||||
request,
|
||||
mergeVariables(
|
||||
injectedVarsOverrides,
|
||||
app ? await server.getInjectedUiAppVars(app.getId()) : {},
|
||||
defaultInjectedVars
|
||||
)
|
||||
),
|
||||
|
||||
uiPlugins,
|
||||
|
||||
legacyMetadata,
|
||||
|
||||
apm: getApmConfig(legacyMetadata.app),
|
||||
},
|
||||
});
|
||||
|
||||
response.header('content-security-policy', header);
|
||||
|
||||
return response;
|
||||
return h
|
||||
.response(content)
|
||||
.type('text/html')
|
||||
.header('content-security-policy', http.csp.header);
|
||||
}
|
||||
|
||||
server.decorate('toolkit', 'renderApp', function(app, injectedVarsOverrides) {
|
||||
return renderApp({
|
||||
app,
|
||||
h: this,
|
||||
includeUserProvidedConfig: true,
|
||||
injectedVarsOverrides,
|
||||
});
|
||||
server.decorate('toolkit', 'renderApp', function(app, overrides) {
|
||||
return renderApp(this, app, true, overrides);
|
||||
});
|
||||
|
||||
server.decorate('toolkit', 'renderAppWithDefaultConfig', function(app) {
|
||||
return renderApp({
|
||||
app,
|
||||
h: this,
|
||||
includeUserProvidedConfig: false,
|
||||
});
|
||||
return renderApp(this, app, false);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,305 +0,0 @@
|
|||
block vars
|
||||
|
||||
doctype html
|
||||
html(lang=locale)
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
meta(http-equiv='X-UA-Compatible', content='IE=edge,chrome=1')
|
||||
meta(name='viewport', content='width=device-width')
|
||||
title Kibana
|
||||
style.
|
||||
/* INTER UI FONT */
|
||||
/* INTER UI FONT */
|
||||
/* INTER UI FONT */
|
||||
/* INTER UI FONT */
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Thin-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Thin-BETA.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ThinItalic-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ThinItalic-BETA.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraLight-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraLight-BETA.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraLightItalic-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraLightItalic-BETA.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Light-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Light-BETA.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-LightItalic-BETA.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-LightItalic-BETA.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Regular.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Regular.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Italic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Italic.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Medium.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Medium.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-MediumItalic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-MediumItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-SemiBold.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-SemiBold.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-SemiBoldItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Bold.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Bold.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-BoldItalic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-BoldItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraBold.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraBold.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraBoldItalic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-ExtraBoldItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Black.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-Black.woff") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI';
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-BlackItalic.woff2") format("woff2"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-BlackItalic.woff") format("woff");
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Single variable font.
|
||||
|
||||
Note that you may want to do something like this to make sure you're serving
|
||||
constant fonts to older browsers:
|
||||
html {
|
||||
font-family: 'Inter UI', sans-serif;
|
||||
}
|
||||
@supports (font-variation-settings: normal) {
|
||||
html {
|
||||
font-family: 'Inter UI var', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
BUGS:
|
||||
- Safari 12.0 will default to italic instead of regular when font-weight
|
||||
is provided in a @font-face declaration.
|
||||
Workaround: Use "Inter UI var alt" for Safari, or explicitly set
|
||||
`font-variation-settings:"slnt" DEGREE`.
|
||||
@font-face {
|
||||
font-family: 'Inter UI var';
|
||||
font-weight: 100 900;
|
||||
font-style: oblique 0deg 10deg;
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI.var.woff2") format("woff2-variations"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI.var.woff2") format("woff2");
|
||||
}
|
||||
|
||||
"Inter UI var alt" is recommended for Safari and Edge, for reliable italics.
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
html {
|
||||
font-family: 'Inter UI var alt', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter UI var alt';
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-named-instance: 'Regular';
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-upright.var.woff2") format("woff2 supports variations(gvar)"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-upright.var.woff2") format("woff2-variations"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-upright.var.woff2") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter UI var alt';
|
||||
font-weight: 100 900;
|
||||
font-style: italic;
|
||||
font-named-instance: 'Italic';
|
||||
src: url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-italic.var.woff2") format("woff2 supports variations(gvar)"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-italic.var.woff2") format("woff2-variations"),
|
||||
url("#{uiPublicUrl}/fonts/inter_ui/Inter-UI-italic.var.woff2") format("woff2");
|
||||
}
|
||||
*/
|
||||
|
||||
/* ROBOTO MONO FONTS */
|
||||
/* ROBOTO MONO FONTS */
|
||||
/* ROBOTO MONO FONTS */
|
||||
/* ROBOTO MONO FONTS */
|
||||
/* ROBOTO MONO FONTS */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono Italic'), local('RobotoMono-Italic'), url("#{uiPublicUrl}/fonts/roboto_mono/RobotoMono-Italic.ttf") format('ttf');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('Roboto Mono Bold Italic'), local('RobotoMono-BoldItalic'), url("#{uiPublicUrl}/fonts/roboto_mono/RobotoMono-BoldItalic.ttf") format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url("#{uiPublicUrl}/fonts/roboto_mono/RobotoMono-Regular.ttf") format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Roboto Mono Bold'), local('RobotoMono-Bold'), url("#{uiPublicUrl}/fonts/roboto_mono/RobotoMono-Bold.ttf") format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
//- Favicons (generated from http://realfavicongenerator.net/)
|
||||
link(
|
||||
rel='apple-touch-icon' sizes='180x180' href=`${uiPublicUrl}/favicons/apple-touch-icon.png`
|
||||
)
|
||||
link(
|
||||
rel='icon' type='image/png' href=`${uiPublicUrl}/favicons/favicon-32x32.png` sizes='32x32'
|
||||
)
|
||||
link(
|
||||
rel='icon' type='image/png' href=`${uiPublicUrl}/favicons/favicon-16x16.png` sizes='16x16'
|
||||
)
|
||||
link(
|
||||
rel='manifest' href=`${uiPublicUrl}/favicons/manifest.json`
|
||||
)
|
||||
link(
|
||||
rel='mask-icon' href=`${uiPublicUrl}/favicons/safari-pinned-tab.svg` color='#e8488b'
|
||||
)
|
||||
link(
|
||||
rel='shortcut icon' href=`${uiPublicUrl}/favicons/favicon.ico`
|
||||
)
|
||||
meta(
|
||||
name='msapplication-config' content=`${uiPublicUrl}/favicons/browserconfig.xml`
|
||||
)
|
||||
meta(
|
||||
name='theme-color' content='#ffffff'
|
||||
)
|
||||
|
||||
style.
|
||||
.kibanaWelcomeView {
|
||||
height: 100%;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: 1 0 auto;
|
||||
-ms-flex: 1 0 auto;
|
||||
flex: 1 0 auto;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.kibanaWelcomeLogo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
/* SVG optimized according to http://codepen.io/tigt/post/optimizing-svgs-in-data-uris */
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OSIgaGVpZ2h0PSI2NCIgdmlld0JveD0iMCAwIDQ5IDY0Ij4KICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgPHBhdGggZmlsbD0iIzNFQkVCMCIgZD0iTTEuNDE2MzE1NzMsNjQgTDQ4LjY0MDA4MTEsNjQgQzQ4LjY0MDA4MTEsNTEuMTI2NCA0MS4yMzYyNjI0LDM5LjY4NDggMjkuNzQ3NDk0NCwzMi4zNzA0IEwxLjQxNjMxNTczLDY0IFoiLz4KICAgIDxwYXRoIGZpbGw9IiMzN0E1OTUiIGQ9Ik0wLDQxLjYgTDAsNjQgTDMuMDM3NTY4LDY0IEwyOS43NTA2NTYsMzIuMzY1NiBDMjcuOTI1ODQ1MywzMS4yMDMyIDI1Ljk5MjQwNTMsMzAuMTUyIDIzLjk3NTQ2NjcsMjkuMjA4IEwwLDQxLjYgWiIvPgogICAgPHBhdGggZmlsbD0iIzM1MzUzNCIgZD0iTTAsMjAuOCBMMCw1Ny42IEwyMy45Nzk1MiwyOS4yMDMyIEMxNi45MDA3Nzg3LDI1Ljg5NzYgMjQuOTM1Mjk2LDIyLjQgMTYuMjEzMzMzMywyMi40IEwwLDIwLjggWiIvPgogICAgPHBhdGggZmlsbD0iI0U5NDc4QiIgZD0iTTQ4LjY0LDAgTDAsMCBMMCwyNCBDOC43MjE5NjI2NywyNCAxNi45MDA3Nzg3LDI1Ljg5NzYgMjMuOTc5NTIsMjkuMjAzMiBMNDguNjQsMCBaIi8+CiAgPC9nPgo8L3N2Zz4K");
|
||||
}
|
||||
|
||||
block head
|
||||
|
||||
body
|
||||
kbn-csp(data=JSON.stringify({ strictCsp }))
|
||||
kbn-injected-metadata(data=JSON.stringify(injectedMetadata))
|
||||
block content
|
|
@ -1,140 +0,0 @@
|
|||
extends ./chrome
|
||||
|
||||
block content
|
||||
style.
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-color: #{darkMode ? '#25262E' : '#F5F7FA'};
|
||||
}
|
||||
.kibanaWelcomeView {
|
||||
background-color: #{darkMode ? '#25262E' : '#F5F7FA'};
|
||||
}
|
||||
|
||||
.kibanaWelcomeTitle {
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
font-family: Sans-serif;
|
||||
margin-top: 20px;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
animation-delay: 1.0s;
|
||||
}
|
||||
|
||||
.kibanaWelcomeText {
|
||||
font-size: 14px;
|
||||
font-family: Sans-serif;
|
||||
color: #98A2B3;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
animation-delay: 1.0s;
|
||||
}
|
||||
|
||||
.kibanaLoaderWrap {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.kibanaLoaderWrap + * {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.kibanaLoader {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
border: 2px solid transparent;
|
||||
border-top: 2px solid #017D73;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
animation: rotation .75s .5s infinite linear, fadeIn 1s .5s ease-in-out forwards;
|
||||
}
|
||||
|
||||
.kibanaWelcomeLogoCircle {
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 4px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
padding: 20px;
|
||||
background-color: #FFF;
|
||||
border-radius: 50%;
|
||||
animation: bounceIn .5s ease-in-out;
|
||||
}
|
||||
|
||||
.kibanaWelcomeLogo {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzOSIgdmlld0JveD0iMCAwIDMwIDM5Ij4gIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgIDxwb2x5Z29uIGZpbGw9IiNGMDRFOTgiIHBvaW50cz0iMCAwIDAgMzQuNTQ3IDI5LjkyMiAuMDIiLz4gICAgPHBhdGggZmlsbD0iIzM0Mzc0MSIgZD0iTTAsMTQuNCBMMCwzNC41NDY4IEwxNC4yODcyLDE4LjA2MTIgQzEwLjA0MTYsMTUuNzM4IDUuMTgwNCwxNC40IDAsMTQuNCIvPiAgICA8cGF0aCBmaWxsPSIjMDBCRkIzIiBkPSJNMTcuMzc0MiwxOS45OTY4IEwyLjcyMSwzNi45MDQ4IEwxLjQzMzQsMzguMzg5MiBMMjkuMjYzOCwzOC4zODkyIEMyNy43NjE0LDMwLjgzODggMjMuNDA0MiwyNC4zMjY0IDE3LjM3NDIsMTkuOTk2OCIvPiAgPC9nPjwvc3ZnPg==");
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 10px 0px 10px 20px;
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounceIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(.1);
|
||||
}
|
||||
80% {
|
||||
opacity: .5;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.kibanaWelcomeView(id="kbn_loading_message", style="display: none;", data-test-subj="kbnLoadingMessage")
|
||||
.kibanaLoaderWrap
|
||||
.kibanaLoader
|
||||
.kibanaWelcomeLogoCircle
|
||||
.kibanaWelcomeLogo
|
||||
.kibanaWelcomeText(data-error-message=i18n('common.ui.welcomeErrorMessage', { defaultMessage: 'Kibana did not load properly. Check the server output for more information.' }))
|
||||
| #{i18n('common.ui.welcomeMessage', { defaultMessage: 'Loading Kibana' })}
|
||||
|
||||
.kibanaWelcomeView(id="kbn_legacy_browser_error", style="display: none;")
|
||||
.kibanaLoaderWrap
|
||||
.kibanaWelcomeLogoCircle
|
||||
.kibanaWelcomeLogo
|
||||
h2.kibanaWelcomeTitle
|
||||
| #{i18n('common.ui.legacyBrowserTitle', { defaultMessage: 'Please upgrade your browser' })}
|
||||
.kibanaWelcomeText
|
||||
| #{i18n('common.ui.legacyBrowserMessage', { defaultMessage: 'This Kibana installation has strict security requirements enabled that your current browser does not meet.' })}
|
||||
|
||||
script.
|
||||
// Since this is an unsafe inline script, this code will not run
|
||||
// in browsers that support content security policy(CSP). This is
|
||||
// intentional as we check for the existence of __kbnCspNotEnforced__ in
|
||||
// bootstrap.
|
||||
window.__kbnCspNotEnforced__ = true;
|
||||
script(src=bootstrapScriptUrl)
|
|
@ -23,6 +23,7 @@ import { schema, TypeOf } from '@kbn/config-schema';
|
|||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
LegacyRenderOptions,
|
||||
Logger,
|
||||
PluginInitializerContext,
|
||||
PluginConfigDescriptor,
|
||||
|
@ -77,6 +78,29 @@ class Plugin {
|
|||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
{
|
||||
path: '/requestcontext/render/{id}',
|
||||
validate: {
|
||||
params: schema.object({
|
||||
id: schema.maybe(schema.string()),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const { id } = req.params;
|
||||
const options: Partial<LegacyRenderOptions> = { app: { getId: () => id! } };
|
||||
const body = await context.core.rendering.render(options);
|
||||
|
||||
return res.ok({
|
||||
body,
|
||||
headers: {
|
||||
'content-securty-policy': core.http.csp.header,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
data$: this.initializerContext.config.create<ConfigType>().pipe(
|
||||
map(configValue => {
|
||||
|
|
|
@ -33,6 +33,11 @@ export default function({ getService }) {
|
|||
200,
|
||||
'SavedObjects client: {"page":1,"per_page":20,"total":0,"saved_objects":[]}'
|
||||
));
|
||||
|
||||
it('provides access to application rendering client', async () => {
|
||||
await supertest.get('/requestcontext/render/core').expect(200, /app:core/);
|
||||
await supertest.get('/requestcontext/render/testbed').expect(200, /app:testbed/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('compression', () => {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
|
@ -53,5 +54,15 @@ export default function({ getService }: PluginFunctionalProviderContext) {
|
|||
statusCode: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders core application explicitly', async () => {
|
||||
await supertest.get('/requestcontext/render/core').expect(200, /app:core/);
|
||||
});
|
||||
|
||||
it('renders legacy application', async () => {
|
||||
await supertest
|
||||
.get('/requestcontext/render/core_plugin_legacy')
|
||||
.expect(200, /app:core_plugin_legacy/);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ export class Plugin {
|
|||
);
|
||||
}
|
||||
|
||||
core.injectUiAppVars('monitoring', core => {
|
||||
core.injectUiAppVars('monitoring', () => {
|
||||
const config = core.config();
|
||||
return {
|
||||
maxBucketSize: config.get('xpack.monitoring.max_bucket_size'),
|
||||
|
|
|
@ -440,8 +440,6 @@
|
|||
"common.ui.flotCharts.thuLabel": "木",
|
||||
"common.ui.flotCharts.tueLabel": "火",
|
||||
"common.ui.flotCharts.wedLabel": "水",
|
||||
"common.ui.legacyBrowserMessage": "この Kibana インストレーションは、現在ご使用のブラウザが満たしていない厳格なセキュリティ要件が有効になっています。",
|
||||
"common.ui.legacyBrowserTitle": "ブラウザをアップグレードしてください",
|
||||
"common.ui.management.breadcrumb": "管理",
|
||||
"management.connectDataDisplayName": "データに接続",
|
||||
"management.displayName": "管理",
|
||||
|
@ -521,8 +519,6 @@
|
|||
"common.ui.vislib.colormaps.redsText": "赤",
|
||||
"common.ui.vislib.colormaps.yellowToRedText": "黄色から赤",
|
||||
"common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "バウンドを取得できませんでした",
|
||||
"common.ui.welcomeErrorMessage": "Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。",
|
||||
"common.ui.welcomeMessage": "Kibana を読み込み中",
|
||||
"common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "地理情報図形",
|
||||
"common.ui.vis.editors.agg.errorsAriaLabel": "集約にエラーがあります",
|
||||
"common.ui.vislib.heatmap.maxBucketsText": "定義された数列が多すぎます ({nr}).構成されている最高値は {max} です。",
|
||||
|
@ -543,6 +539,10 @@
|
|||
"core.ui.chrome.sideGlobalNav.viewRecentItemsFlyoutTitle": "最近のアイテム",
|
||||
"core.ui.chrome.sideGlobalNav.viewRecentItemsLabel": "最近閲覧",
|
||||
"core.ui.recentLinks.linkItem.screenReaderLabel": "{recentlyAccessedItemLinklabel}、タイプ: {pageType}",
|
||||
"core.ui.legacyBrowserMessage": "この Kibana インストレーションは、現在ご使用のブラウザが満たしていない厳格なセキュリティ要件が有効になっています。",
|
||||
"core.ui.legacyBrowserTitle": "ブラウザをアップグレードしてください",
|
||||
"core.ui.welcomeErrorMessage": "Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。",
|
||||
"core.ui.welcomeMessage": "Kibana を読み込み中",
|
||||
"core.chrome.legacyBrowserWarning": "ご使用のブラウザが Kibana のセキュリティ要件を満たしていません。",
|
||||
"core.euiBasicTable.selectAllRows": "すべての行を選択",
|
||||
"core.euiBasicTable.selectThisRow": "この行を選択",
|
||||
|
|
|
@ -440,8 +440,6 @@
|
|||
"common.ui.flotCharts.thuLabel": "周四",
|
||||
"common.ui.flotCharts.tueLabel": "周二",
|
||||
"common.ui.flotCharts.wedLabel": "周三",
|
||||
"common.ui.legacyBrowserMessage": "此 Kibana 安装启用了当前浏览器未满足的严格安全要求。",
|
||||
"common.ui.legacyBrowserTitle": "请升级您的浏览器",
|
||||
"common.ui.management.breadcrumb": "管理",
|
||||
"management.connectDataDisplayName": "连接数据",
|
||||
"management.displayName": "管理",
|
||||
|
@ -522,8 +520,6 @@
|
|||
"common.ui.vislib.colormaps.redsText": "红色",
|
||||
"common.ui.vislib.colormaps.yellowToRedText": "黄到红",
|
||||
"common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "无法获取边界",
|
||||
"common.ui.welcomeErrorMessage": "Kibana 未正确加载。检查服务器输出以了解详情。",
|
||||
"common.ui.welcomeMessage": "正在加载 Kibana",
|
||||
"common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "几何形状字段",
|
||||
"common.ui.vis.editors.agg.errorsAriaLabel": "聚合有错误",
|
||||
"common.ui.vislib.heatmap.maxBucketsText": "定义了过多的序列 ({nr})。配置的最大值为 {max}。",
|
||||
|
@ -544,6 +540,10 @@
|
|||
"core.ui.chrome.sideGlobalNav.viewRecentItemsFlyoutTitle": "最近项",
|
||||
"core.ui.chrome.sideGlobalNav.viewRecentItemsLabel": "最近查看",
|
||||
"core.ui.recentLinks.linkItem.screenReaderLabel": "{recentlyAccessedItemLinklabel},类型:{pageType}",
|
||||
"core.ui.legacyBrowserMessage": "此 Kibana 安装启用了当前浏览器未满足的严格安全要求。",
|
||||
"core.ui.legacyBrowserTitle": "请升级您的浏览器",
|
||||
"core.ui.welcomeErrorMessage": "Kibana 未正确加载。检查服务器输出以了解详情。",
|
||||
"core.ui.welcomeMessage": "正在加载 Kibana",
|
||||
"core.chrome.legacyBrowserWarning": "您的浏览器不满足 Kibana 的安全要求。",
|
||||
"core.euiBasicTable.selectAllRows": "选择所有行",
|
||||
"core.euiBasicTable.selectThisRow": "选择此行",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue