mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[7.x] [new-platform] Introduce ApplicationService scaffolding and capabilities loading (#35545) (#36154)
This commit is contained in:
parent
9e0687a4e0
commit
d6f15af6e5
98 changed files with 1783 additions and 742 deletions
|
@ -0,0 +1,19 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationSetup](./kibana-plugin-public.applicationsetup.md)
|
||||||
|
|
||||||
|
## ApplicationSetup interface
|
||||||
|
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface ApplicationSetup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
| Method | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| [registerApp(app)](./kibana-plugin-public.applicationsetup.registerapp.md) | Register an mountable application to the system. Apps will be mounted based on their <code>rootRoute</code>. |
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) > [registerApp](./kibana-plugin-public.applicationsetup.registerapp.md)
|
||||||
|
|
||||||
|
## ApplicationSetup.registerApp() method
|
||||||
|
|
||||||
|
Register an mountable application to the system. Apps will be mounted based on their `rootRoute`<!-- -->.
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
registerApp(app: App): void;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
| Parameter | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| app | <code>App</code> | |
|
||||||
|
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
`void`
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationStart](./kibana-plugin-public.applicationstart.md) > [availableApps](./kibana-plugin-public.applicationstart.availableapps.md)
|
||||||
|
|
||||||
|
## ApplicationStart.availableApps property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
availableApps: CapabilitiesStart['availableApps'];
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationStart](./kibana-plugin-public.applicationstart.md) > [capabilities](./kibana-plugin-public.applicationstart.capabilities.md)
|
||||||
|
|
||||||
|
## ApplicationStart.capabilities property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
capabilities: CapabilitiesStart['capabilities'];
|
||||||
|
```
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationStart](./kibana-plugin-public.applicationstart.md)
|
||||||
|
|
||||||
|
## ApplicationStart interface
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface ApplicationStart
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [availableApps](./kibana-plugin-public.applicationstart.availableapps.md) | <code>CapabilitiesStart['availableApps']</code> | |
|
||||||
|
| [capabilities](./kibana-plugin-public.applicationstart.capabilities.md) | <code>CapabilitiesStart['capabilities']</code> | |
|
||||||
|
| [mount](./kibana-plugin-public.applicationstart.mount.md) | <code>(mountHandler: Function) => void</code> | |
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [ApplicationStart](./kibana-plugin-public.applicationstart.md) > [mount](./kibana-plugin-public.applicationstart.mount.md)
|
||||||
|
|
||||||
|
## ApplicationStart.mount property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
mount: (mountHandler: Function) => void;
|
||||||
|
```
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [BasePathStart](./kibana-plugin-public.basepathstart.md)
|
||||||
|
|
||||||
|
## BasePathStart type
|
||||||
|
|
||||||
|
Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export declare type BasePathStart = BasePathSetup;
|
||||||
|
```
|
|
@ -1,13 +0,0 @@
|
||||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
|
||||||
|
|
||||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CapabilitiesStart](./kibana-plugin-public.capabilitiesstart.md) > [getCapabilities](./kibana-plugin-public.capabilitiesstart.getcapabilities.md)
|
|
||||||
|
|
||||||
## CapabilitiesStart.getCapabilities property
|
|
||||||
|
|
||||||
Gets the read-only capabilities.
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
getCapabilities: () => Capabilities;
|
|
||||||
```
|
|
|
@ -1,20 +0,0 @@
|
||||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
|
||||||
|
|
||||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CapabilitiesStart](./kibana-plugin-public.capabilitiesstart.md)
|
|
||||||
|
|
||||||
## CapabilitiesStart interface
|
|
||||||
|
|
||||||
Capabilities Setup.
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export interface CapabilitiesStart
|
|
||||||
```
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
| Property | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [getCapabilities](./kibana-plugin-public.capabilitiesstart.getcapabilities.md) | <code>() => Capabilities</code> | Gets the read-only capabilities. |
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreSetup](./kibana-plugin-public.coresetup.md) > [application](./kibana-plugin-public.coresetup.application.md)
|
||||||
|
|
||||||
|
## CoreSetup.application property
|
||||||
|
|
||||||
|
[ApplicationSetup](./kibana-plugin-public.applicationsetup.md)
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
application: ApplicationSetup;
|
||||||
|
```
|
|
@ -16,6 +16,7 @@ export interface CoreSetup
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
| [application](./kibana-plugin-public.coresetup.application.md) | <code>ApplicationSetup</code> | [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) |
|
||||||
| [basePath](./kibana-plugin-public.coresetup.basepath.md) | <code>BasePathSetup</code> | [BasePathSetup](./kibana-plugin-public.basepathsetup.md) |
|
| [basePath](./kibana-plugin-public.coresetup.basepath.md) | <code>BasePathSetup</code> | [BasePathSetup](./kibana-plugin-public.basepathsetup.md) |
|
||||||
| [chrome](./kibana-plugin-public.coresetup.chrome.md) | <code>ChromeSetup</code> | [ChromeSetup](./kibana-plugin-public.chromesetup.md) |
|
| [chrome](./kibana-plugin-public.coresetup.chrome.md) | <code>ChromeSetup</code> | [ChromeSetup](./kibana-plugin-public.chromesetup.md) |
|
||||||
| [fatalErrors](./kibana-plugin-public.coresetup.fatalerrors.md) | <code>FatalErrorsSetup</code> | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) |
|
| [fatalErrors](./kibana-plugin-public.coresetup.fatalerrors.md) | <code>FatalErrorsSetup</code> | [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) |
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [capabilities](./kibana-plugin-public.corestart.capabilities.md)
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [application](./kibana-plugin-public.corestart.application.md)
|
||||||
|
|
||||||
## CoreStart.capabilities property
|
## CoreStart.application property
|
||||||
|
|
||||||
[CapabilitiesStart](./kibana-plugin-public.capabilitiesstart.md)
|
[ApplicationStart](./kibana-plugin-public.applicationstart.md)
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
capabilities: CapabilitiesStart;
|
application: ApplicationStart;
|
||||||
```
|
```
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [basePath](./kibana-plugin-public.corestart.basepath.md)
|
||||||
|
|
||||||
|
## CoreStart.basePath property
|
||||||
|
|
||||||
|
[BasePathStart](./kibana-plugin-public.basepathstart.md)
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
basePath: BasePathStart;
|
||||||
|
```
|
|
@ -14,7 +14,8 @@ export interface CoreStart
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [capabilities](./kibana-plugin-public.corestart.capabilities.md) | <code>CapabilitiesStart</code> | [CapabilitiesStart](./kibana-plugin-public.capabilitiesstart.md) |
|
| [application](./kibana-plugin-public.corestart.application.md) | <code>ApplicationStart</code> | [ApplicationStart](./kibana-plugin-public.applicationstart.md) |
|
||||||
|
| [basePath](./kibana-plugin-public.corestart.basepath.md) | <code>BasePathStart</code> | [BasePathStart](./kibana-plugin-public.basepathstart.md) |
|
||||||
| [i18n](./kibana-plugin-public.corestart.i18n.md) | <code>I18nStart</code> | [I18nStart](./kibana-plugin-public.i18nstart.md) |
|
| [i18n](./kibana-plugin-public.corestart.i18n.md) | <code>I18nStart</code> | [I18nStart](./kibana-plugin-public.i18nstart.md) |
|
||||||
| [injectedMetadata](./kibana-plugin-public.corestart.injectedmetadata.md) | <code>InjectedMetadataStart</code> | [InjectedMetadataStart](./kibana-plugin-public.injectedmetadatastart.md) |
|
| [injectedMetadata](./kibana-plugin-public.corestart.injectedmetadata.md) | <code>InjectedMetadataStart</code> | [InjectedMetadataStart](./kibana-plugin-public.injectedmetadatastart.md) |
|
||||||
| [notifications](./kibana-plugin-public.corestart.notifications.md) | <code>NotificationsStart</code> | [NotificationsStart](./kibana-plugin-public.notificationsstart.md) |
|
| [notifications](./kibana-plugin-public.corestart.notifications.md) | <code>NotificationsStart</code> | [NotificationsStart](./kibana-plugin-public.notificationsstart.md) |
|
||||||
|
|
|
@ -11,7 +11,7 @@ getLegacyMetadata: () => {
|
||||||
app: unknown;
|
app: unknown;
|
||||||
translations: unknown;
|
translations: unknown;
|
||||||
bundleId: string;
|
bundleId: string;
|
||||||
nav: unknown;
|
nav: LegacyNavLink[];
|
||||||
version: string;
|
version: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
buildNum: number;
|
buildNum: number;
|
||||||
|
|
|
@ -21,6 +21,6 @@ export interface InjectedMetadataSetup
|
||||||
| [getInjectedVar](./kibana-plugin-public.injectedmetadatasetup.getinjectedvar.md) | <code>(name: string, defaultValue?: any) => unknown</code> | |
|
| [getInjectedVar](./kibana-plugin-public.injectedmetadatasetup.getinjectedvar.md) | <code>(name: string, defaultValue?: any) => unknown</code> | |
|
||||||
| [getInjectedVars](./kibana-plugin-public.injectedmetadatasetup.getinjectedvars.md) | <code>() => {`<p/>` [key: string]: unknown;`<p/>` }</code> | |
|
| [getInjectedVars](./kibana-plugin-public.injectedmetadatasetup.getinjectedvars.md) | <code>() => {`<p/>` [key: string]: unknown;`<p/>` }</code> | |
|
||||||
| [getKibanaVersion](./kibana-plugin-public.injectedmetadatasetup.getkibanaversion.md) | <code>() => string</code> | |
|
| [getKibanaVersion](./kibana-plugin-public.injectedmetadatasetup.getkibanaversion.md) | <code>() => string</code> | |
|
||||||
| [getLegacyMetadata](./kibana-plugin-public.injectedmetadatasetup.getlegacymetadata.md) | <code>() => {`<p/>` app: unknown;`<p/>` translations: unknown;`<p/>` bundleId: string;`<p/>` nav: unknown;`<p/>` version: string;`<p/>` branch: string;`<p/>` buildNum: number;`<p/>` buildSha: string;`<p/>` basePath: string;`<p/>` serverName: string;`<p/>` devMode: boolean;`<p/>` uiSettings: {`<p/>` defaults: UiSettingsState;`<p/>` user?: UiSettingsState | undefined;`<p/>` };`<p/>` }</code> | |
|
| [getLegacyMetadata](./kibana-plugin-public.injectedmetadatasetup.getlegacymetadata.md) | <code>() => {`<p/>` app: unknown;`<p/>` translations: unknown;`<p/>` bundleId: string;`<p/>` nav: LegacyNavLink[];`<p/>` version: string;`<p/>` branch: string;`<p/>` buildNum: number;`<p/>` buildSha: string;`<p/>` basePath: string;`<p/>` serverName: string;`<p/>` devMode: boolean;`<p/>` uiSettings: {`<p/>` defaults: UiSettingsState;`<p/>` user?: UiSettingsState | undefined;`<p/>` };`<p/>` }</code> | |
|
||||||
| [getPlugins](./kibana-plugin-public.injectedmetadatasetup.getplugins.md) | <code>() => Array<{`<p/>` id: string;`<p/>` plugin: DiscoveredPlugin;`<p/>` }></code> | An array of frontend plugins in topological order. |
|
| [getPlugins](./kibana-plugin-public.injectedmetadatasetup.getplugins.md) | <code>() => Array<{`<p/>` id: string;`<p/>` plugin: DiscoveredPlugin;`<p/>` }></code> | An array of frontend plugins in topological order. |
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [euiIconType](./kibana-plugin-public.legacynavlink.euiicontype.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.euiIconType property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
euiIconType?: string;
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [icon](./kibana-plugin-public.legacynavlink.icon.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.icon property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
icon?: string;
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [id](./kibana-plugin-public.legacynavlink.id.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.id property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
id: string;
|
||||||
|
```
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md)
|
||||||
|
|
||||||
|
## LegacyNavLink interface
|
||||||
|
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export interface LegacyNavLink
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [euiIconType](./kibana-plugin-public.legacynavlink.euiicontype.md) | <code>string</code> | |
|
||||||
|
| [icon](./kibana-plugin-public.legacynavlink.icon.md) | <code>string</code> | |
|
||||||
|
| [id](./kibana-plugin-public.legacynavlink.id.md) | <code>string</code> | |
|
||||||
|
| [order](./kibana-plugin-public.legacynavlink.order.md) | <code>number</code> | |
|
||||||
|
| [title](./kibana-plugin-public.legacynavlink.title.md) | <code>string</code> | |
|
||||||
|
| [url](./kibana-plugin-public.legacynavlink.url.md) | <code>string</code> | |
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [order](./kibana-plugin-public.legacynavlink.order.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.order property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
order: number;
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [title](./kibana-plugin-public.legacynavlink.title.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.title property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
title: string;
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) > [url](./kibana-plugin-public.legacynavlink.url.md)
|
||||||
|
|
||||||
|
## LegacyNavLink.url property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
url: string;
|
||||||
|
```
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
| Interface | Description |
|
| Interface | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
| [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) | |
|
||||||
|
| [ApplicationStart](./kibana-plugin-public.applicationstart.md) | |
|
||||||
| [BasePathSetup](./kibana-plugin-public.basepathsetup.md) | Provides access to the 'server.basePath' configuration option in kibana.yml |
|
| [BasePathSetup](./kibana-plugin-public.basepathsetup.md) | Provides access to the 'server.basePath' configuration option in kibana.yml |
|
||||||
| [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. |
|
| [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. |
|
||||||
| [CapabilitiesStart](./kibana-plugin-public.capabilitiesstart.md) | Capabilities Setup. |
|
|
||||||
| [ChromeBadge](./kibana-plugin-public.chromebadge.md) | |
|
| [ChromeBadge](./kibana-plugin-public.chromebadge.md) | |
|
||||||
| [ChromeBrand](./kibana-plugin-public.chromebrand.md) | |
|
| [ChromeBrand](./kibana-plugin-public.chromebrand.md) | |
|
||||||
| [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | |
|
| [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | |
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
| [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
|
| [FatalErrorsSetup](./kibana-plugin-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
|
||||||
| [I18nSetup](./kibana-plugin-public.i18nsetup.md) | I18nSetup.Context is required by any localizable React component from @<!-- -->kbn/i18n and @<!-- -->elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. |
|
| [I18nSetup](./kibana-plugin-public.i18nsetup.md) | I18nSetup.Context is required by any localizable React component from @<!-- -->kbn/i18n and @<!-- -->elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. |
|
||||||
| [InjectedMetadataSetup](./kibana-plugin-public.injectedmetadatasetup.md) | Provides access to the metadata injected by the server into the page |
|
| [InjectedMetadataSetup](./kibana-plugin-public.injectedmetadatasetup.md) | Provides access to the metadata injected by the server into the page |
|
||||||
|
| [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) | |
|
||||||
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | |
|
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | |
|
||||||
| [OverlayStart](./kibana-plugin-public.overlaystart.md) | |
|
| [OverlayStart](./kibana-plugin-public.overlaystart.md) | |
|
||||||
| [Plugin](./kibana-plugin-public.plugin.md) | The interface that should be returned by a <code>PluginInitializer</code>. |
|
| [Plugin](./kibana-plugin-public.plugin.md) | The interface that should be returned by a <code>PluginInitializer</code>. |
|
||||||
|
@ -38,6 +40,7 @@
|
||||||
|
|
||||||
| Type Alias | Description |
|
| Type Alias | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
| [BasePathStart](./kibana-plugin-public.basepathstart.md) | Provides access to the 'server.basePath' configuration option in kibana.yml |
|
||||||
| [ChromeHelpExtension](./kibana-plugin-public.chromehelpextension.md) | |
|
| [ChromeHelpExtension](./kibana-plugin-public.chromehelpextension.md) | |
|
||||||
| [ChromeSetup](./kibana-plugin-public.chromesetup.md) | |
|
| [ChromeSetup](./kibana-plugin-public.chromesetup.md) | |
|
||||||
| [HttpSetup](./kibana-plugin-public.httpsetup.md) | |
|
| [HttpSetup](./kibana-plugin-public.httpsetup.md) | |
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [PluginSetupContext](./kibana-plugin-public.pluginsetupcontext.md) > [http](./kibana-plugin-public.pluginsetupcontext.http.md)
|
||||||
|
|
||||||
|
## PluginSetupContext.http property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
http: HttpSetup;
|
||||||
|
```
|
|
@ -19,6 +19,7 @@ export interface PluginSetupContext
|
||||||
| [basePath](./kibana-plugin-public.pluginsetupcontext.basepath.md) | <code>BasePathSetup</code> | |
|
| [basePath](./kibana-plugin-public.pluginsetupcontext.basepath.md) | <code>BasePathSetup</code> | |
|
||||||
| [chrome](./kibana-plugin-public.pluginsetupcontext.chrome.md) | <code>ChromeSetup</code> | |
|
| [chrome](./kibana-plugin-public.pluginsetupcontext.chrome.md) | <code>ChromeSetup</code> | |
|
||||||
| [fatalErrors](./kibana-plugin-public.pluginsetupcontext.fatalerrors.md) | <code>FatalErrorsSetup</code> | |
|
| [fatalErrors](./kibana-plugin-public.pluginsetupcontext.fatalerrors.md) | <code>FatalErrorsSetup</code> | |
|
||||||
|
| [http](./kibana-plugin-public.pluginsetupcontext.http.md) | <code>HttpSetup</code> | |
|
||||||
| [i18n](./kibana-plugin-public.pluginsetupcontext.i18n.md) | <code>I18nSetup</code> | |
|
| [i18n](./kibana-plugin-public.pluginsetupcontext.i18n.md) | <code>I18nSetup</code> | |
|
||||||
| [notifications](./kibana-plugin-public.pluginsetupcontext.notifications.md) | <code>NotificationsSetup</code> | |
|
| [notifications](./kibana-plugin-public.pluginsetupcontext.notifications.md) | <code>NotificationsSetup</code> | |
|
||||||
| [uiSettings](./kibana-plugin-public.pluginsetupcontext.uisettings.md) | <code>UiSettingsSetup</code> | |
|
| [uiSettings](./kibana-plugin-public.pluginsetupcontext.uisettings.md) | <code>UiSettingsSetup</code> | |
|
||||||
|
|
45
src/core/public/application/application_service.mock.ts
Normal file
45
src/core/public/application/application_service.mock.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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 { capabilitiesServiceMock } from './capabilities/capabilities_service.mock';
|
||||||
|
import { ApplicationService, ApplicationSetup, ApplicationStart } from './application_service';
|
||||||
|
|
||||||
|
type ApplicationServiceContract = PublicMethodsOf<ApplicationService>;
|
||||||
|
|
||||||
|
const createSetupContractMock = (): jest.Mocked<ApplicationSetup> => ({
|
||||||
|
registerApp: jest.fn(),
|
||||||
|
registerLegacyApp: jest.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const createStartContractMock = (): jest.Mocked<ApplicationStart> => ({
|
||||||
|
mount: jest.fn(),
|
||||||
|
...capabilitiesServiceMock.createStartContract(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const createMock = (): jest.Mocked<ApplicationServiceContract> => ({
|
||||||
|
setup: jest.fn().mockReturnValue(createSetupContractMock()),
|
||||||
|
start: jest.fn().mockReturnValue(createStartContractMock()),
|
||||||
|
stop: jest.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const applicationServiceMock = {
|
||||||
|
create: createMock,
|
||||||
|
createSetupContract: createSetupContractMock,
|
||||||
|
createStartContract: createStartContractMock,
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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 { capabilitiesServiceMock } from './capabilities/capabilities_service.mock';
|
||||||
|
|
||||||
|
export const MockCapabilitiesService = capabilitiesServiceMock.create();
|
||||||
|
export const CapabilitiesServiceConstructor = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => MockCapabilitiesService);
|
||||||
|
jest.doMock('./capabilities', () => ({
|
||||||
|
CapabilitiesService: CapabilitiesServiceConstructor,
|
||||||
|
}));
|
73
src/core/public/application/application_service.test.tsx
Normal file
73
src/core/public/application/application_service.test.tsx
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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 { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||||
|
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||||
|
import { MockCapabilitiesService } from './application_service.test.mocks';
|
||||||
|
import { ApplicationService } from './application_service';
|
||||||
|
|
||||||
|
describe('#start()', () => {
|
||||||
|
it('exposes available apps from capabilities', async () => {
|
||||||
|
const service = new ApplicationService();
|
||||||
|
const setup = service.setup();
|
||||||
|
setup.registerApp({ id: 'app1' } as any);
|
||||||
|
setup.registerLegacyApp({ id: 'app2' } as any);
|
||||||
|
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||||
|
const basePath = basePathServiceMock.createStartContract();
|
||||||
|
expect((await service.start({ basePath, injectedMetadata })).availableApps)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"id": "app1",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"id": "app2",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes registered applications to capabilities', async () => {
|
||||||
|
const service = new ApplicationService();
|
||||||
|
const setup = service.setup();
|
||||||
|
setup.registerApp({ id: 'app1' } as any);
|
||||||
|
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||||
|
const basePath = basePathServiceMock.createStartContract();
|
||||||
|
await service.start({ basePath, injectedMetadata });
|
||||||
|
expect(MockCapabilitiesService.start).toHaveBeenCalledWith({
|
||||||
|
apps: [{ id: 'app1' }],
|
||||||
|
basePath,
|
||||||
|
injectedMetadata,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes registered legacy applications to capabilities', async () => {
|
||||||
|
const service = new ApplicationService();
|
||||||
|
const setup = service.setup();
|
||||||
|
setup.registerLegacyApp({ id: 'legacyApp1' } as any);
|
||||||
|
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
|
||||||
|
const basePath = basePathServiceMock.createStartContract();
|
||||||
|
await service.start({ basePath, injectedMetadata });
|
||||||
|
expect(MockCapabilitiesService.start).toHaveBeenCalledWith({
|
||||||
|
apps: [{ id: 'legacyApp1' }],
|
||||||
|
basePath,
|
||||||
|
injectedMetadata,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
152
src/core/public/application/application_service.tsx
Normal file
152
src/core/public/application/application_service.tsx
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
|
import { CapabilitiesStart, CapabilitiesService, Capabilities } from './capabilities';
|
||||||
|
import { InjectedMetadataStart } from '../injected_metadata';
|
||||||
|
import { BasePathStart } from '../base_path';
|
||||||
|
|
||||||
|
interface BaseApp {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ordinal used to sort nav links relative to one another for display.
|
||||||
|
*/
|
||||||
|
order: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title of the application.
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An observable for a tooltip shown when hovering over app link.
|
||||||
|
*/
|
||||||
|
tooltip$?: Observable<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A EUI iconType that will be used for the app's icon. This icon
|
||||||
|
* takes precendence over the `icon` property.
|
||||||
|
*/
|
||||||
|
euiIconType?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A URL to an image file used as an icon. Used as a fallback
|
||||||
|
* if `euiIconType` is not provided.
|
||||||
|
*/
|
||||||
|
icon?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom capabilities defined by the app.
|
||||||
|
*/
|
||||||
|
capabilities?: Partial<Capabilities>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface App extends BaseApp {
|
||||||
|
/**
|
||||||
|
* The root route to mount this application at.
|
||||||
|
*/
|
||||||
|
rootRoute: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mount function called when the user navigates to this app's `rootRoute`.
|
||||||
|
* @param targetDomElement An HTMLElement to mount the application onto.
|
||||||
|
* @returns An unmounting function that will be called to unmount the application.
|
||||||
|
*/
|
||||||
|
mount(targetDomElement: HTMLElement): () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export interface LegacyApp extends BaseApp {
|
||||||
|
appUrl: string;
|
||||||
|
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export type MixedApp = Partial<App> & Partial<LegacyApp> & BaseApp;
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface ApplicationSetup {
|
||||||
|
/**
|
||||||
|
* Register an mountable application to the system. Apps will be mounted based on their `rootRoute`.
|
||||||
|
* @param app
|
||||||
|
*/
|
||||||
|
registerApp(app: App): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register metadata about legacy applications. Legacy apps will not be mounted when navigated to.
|
||||||
|
* @param app
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
registerLegacyApp(app: LegacyApp): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationStart {
|
||||||
|
mount: (mountHandler: Function) => void;
|
||||||
|
availableApps: CapabilitiesStart['availableApps'];
|
||||||
|
capabilities: CapabilitiesStart['capabilities'];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StartDeps {
|
||||||
|
basePath: BasePathStart;
|
||||||
|
injectedMetadata: InjectedMetadataStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service that is responsible for registering new applications.
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class ApplicationService {
|
||||||
|
private readonly apps$ = new BehaviorSubject<App[]>([]);
|
||||||
|
private readonly legacyApps$ = new BehaviorSubject<LegacyApp[]>([]);
|
||||||
|
private readonly capabilities = new CapabilitiesService();
|
||||||
|
|
||||||
|
public setup(): ApplicationSetup {
|
||||||
|
return {
|
||||||
|
registerApp: (app: App) => {
|
||||||
|
this.apps$.next([...this.apps$.value, app]);
|
||||||
|
},
|
||||||
|
registerLegacyApp: (app: LegacyApp) => {
|
||||||
|
this.legacyApps$.next([...this.legacyApps$.value, app]);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start({ basePath, injectedMetadata }: StartDeps): Promise<ApplicationStart> {
|
||||||
|
this.apps$.complete();
|
||||||
|
this.legacyApps$.complete();
|
||||||
|
|
||||||
|
const apps = [...this.apps$.value, ...this.legacyApps$.value];
|
||||||
|
const { capabilities, availableApps } = await this.capabilities.start({
|
||||||
|
apps,
|
||||||
|
basePath,
|
||||||
|
injectedMetadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mount() {},
|
||||||
|
capabilities,
|
||||||
|
availableApps,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop() {}
|
||||||
|
}
|
|
@ -16,28 +16,25 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { Capabilities, CapabilitiesService, CapabilitiesStart } from './capabilities_service';
|
import { CapabilitiesService, CapabilitiesStart } from './capabilities_service';
|
||||||
|
import { deepFreeze } from '../../utils/deep_freeze';
|
||||||
|
import { MixedApp } from '../application_service';
|
||||||
|
|
||||||
const createStartContractMock = () => {
|
const createStartContractMock = (
|
||||||
const startContract: jest.Mocked<CapabilitiesStart> = {
|
apps: ReadonlyArray<MixedApp> = []
|
||||||
getCapabilities: jest.fn(),
|
): jest.Mocked<CapabilitiesStart> => ({
|
||||||
};
|
availableApps: apps,
|
||||||
startContract.getCapabilities.mockReturnValue({
|
capabilities: deepFreeze({
|
||||||
catalogue: {},
|
catalogue: {},
|
||||||
management: {},
|
management: {},
|
||||||
navLinks: {},
|
navLinks: {},
|
||||||
} as Capabilities);
|
}),
|
||||||
return startContract;
|
});
|
||||||
};
|
|
||||||
|
|
||||||
type CapabilitiesServiceContract = PublicMethodsOf<CapabilitiesService>;
|
type CapabilitiesServiceContract = PublicMethodsOf<CapabilitiesService>;
|
||||||
const createMock = () => {
|
const createMock = (): jest.Mocked<CapabilitiesServiceContract> => ({
|
||||||
const mocked: jest.Mocked<CapabilitiesServiceContract> = {
|
start: jest.fn().mockImplementation(({ apps }) => createStartContractMock(apps)),
|
||||||
start: jest.fn(),
|
});
|
||||||
};
|
|
||||||
mocked.start.mockReturnValue(createStartContractMock());
|
|
||||||
return mocked;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const capabilitiesServiceMock = {
|
export const capabilitiesServiceMock = {
|
||||||
create: createMock,
|
create: createMock,
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import fetchMock from 'fetch-mock/es5/client';
|
||||||
|
|
||||||
|
import { InjectedMetadataService } from '../../injected_metadata';
|
||||||
|
import { CapabilitiesService } from './capabilities_service';
|
||||||
|
import { basePathServiceMock } from '../../base_path/base_path_service.mock';
|
||||||
|
|
||||||
|
describe('#start', () => {
|
||||||
|
const basePath = basePathServiceMock.createStartContract();
|
||||||
|
basePath.addToPath.mockImplementation(str => str);
|
||||||
|
const injectedMetadata = new InjectedMetadataService({
|
||||||
|
injectedMetadata: {
|
||||||
|
vars: {
|
||||||
|
uiCapabilities: {
|
||||||
|
foo: { feature: true },
|
||||||
|
bar: { feature: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
}).start();
|
||||||
|
const apps = [{ id: 'app1' }, { id: 'app2', capabilities: { app2: { feature: true } } }] as any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fetchMock.post('/api/capabilities', (url: string, options: any) => ({
|
||||||
|
body: options.body,
|
||||||
|
status: 200,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fetchMock.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls backend API with merged capabilities', async () => {
|
||||||
|
const service = new CapabilitiesService();
|
||||||
|
await service.start({ apps, basePath, injectedMetadata });
|
||||||
|
expect(fetchMock.calls()).toMatchInlineSnapshot(`
|
||||||
|
Array [
|
||||||
|
Array [
|
||||||
|
"/api/capabilities",
|
||||||
|
Object {
|
||||||
|
"body": "{\\"capabilities\\":{\\"navLinks\\":{\\"app2\\":true,\\"app1\\":true},\\"management\\":{},\\"catalogue\\":{},\\"app2\\":{\\"feature\\":true}}}",
|
||||||
|
"credentials": "same-origin",
|
||||||
|
"headers": Object {
|
||||||
|
"kbn-xsrf": "xxx",
|
||||||
|
},
|
||||||
|
"method": "POST",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns capabilities from backend', async () => {
|
||||||
|
const service = new CapabilitiesService();
|
||||||
|
expect((await service.start({ apps, basePath, injectedMetadata })).capabilities)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"app2": Object {
|
||||||
|
"feature": true,
|
||||||
|
},
|
||||||
|
"catalogue": Object {},
|
||||||
|
"management": Object {},
|
||||||
|
"navLinks": Object {
|
||||||
|
"app1": true,
|
||||||
|
"app2": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters available apps based on returned navLinks', async () => {
|
||||||
|
fetchMock.post(
|
||||||
|
'/api/capabilities',
|
||||||
|
(url: string, options: any) => ({
|
||||||
|
body: JSON.stringify({ capabilities: { navLinks: { app1: true, app2: false } } }),
|
||||||
|
status: 200,
|
||||||
|
}),
|
||||||
|
{ overwriteRoutes: true }
|
||||||
|
);
|
||||||
|
const service = new CapabilitiesService();
|
||||||
|
expect((await service.start({ apps, basePath, injectedMetadata })).availableApps).toEqual([
|
||||||
|
{ id: 'app1' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not allow Capabilities to be modified', async () => {
|
||||||
|
const service = new CapabilitiesService();
|
||||||
|
const { capabilities } = await service.start({
|
||||||
|
apps,
|
||||||
|
basePath,
|
||||||
|
injectedMetadata,
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-ignore TypeScript knows this shouldn't be possible
|
||||||
|
expect(() => (capabilities.foo = 'foo')).toThrowError();
|
||||||
|
});
|
||||||
|
});
|
|
@ -16,10 +16,16 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { InjectedMetadataStart } from '../injected_metadata';
|
|
||||||
import { deepFreeze } from '../utils/deep_freeze';
|
import { deepFreeze, RecursiveReadonly } from '../../utils/deep_freeze';
|
||||||
|
import { MixedApp } from '../application_service';
|
||||||
|
import { mergeCapabilities } from './merge_capabilities';
|
||||||
|
import { InjectedMetadataStart } from '../../injected_metadata';
|
||||||
|
import { BasePathStart } from '../../base_path';
|
||||||
|
|
||||||
interface StartDeps {
|
interface StartDeps {
|
||||||
|
apps: ReadonlyArray<MixedApp>;
|
||||||
|
basePath: BasePathStart;
|
||||||
injectedMetadata: InjectedMetadataStart;
|
injectedMetadata: InjectedMetadataStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +60,13 @@ export interface CapabilitiesStart {
|
||||||
/**
|
/**
|
||||||
* Gets the read-only capabilities.
|
* Gets the read-only capabilities.
|
||||||
*/
|
*/
|
||||||
getCapabilities: () => Capabilities;
|
capabilities: RecursiveReadonly<Capabilities>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apps available based on the current capabilities. Should be used
|
||||||
|
* to show navigation links and make routing decisions.
|
||||||
|
*/
|
||||||
|
availableApps: ReadonlyArray<MixedApp>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -63,10 +75,44 @@ export interface CapabilitiesStart {
|
||||||
* Service that is responsible for UI Capabilities.
|
* Service that is responsible for UI Capabilities.
|
||||||
*/
|
*/
|
||||||
export class CapabilitiesService {
|
export class CapabilitiesService {
|
||||||
public start({ injectedMetadata }: StartDeps): CapabilitiesStart {
|
public async start({ apps, basePath, injectedMetadata }: StartDeps): Promise<CapabilitiesStart> {
|
||||||
|
const mergedCapabilities = mergeCapabilities(
|
||||||
|
// Custom capabilites for new platform apps
|
||||||
|
...apps.filter(app => app.capabilities).map(app => app.capabilities!),
|
||||||
|
// Generate navLink capabilities for all apps
|
||||||
|
...apps.map(app => ({ navLinks: { [app.id]: true } }))
|
||||||
|
);
|
||||||
|
|
||||||
|
// NOTE: should replace `fetch` with browser HTTP service once it exists
|
||||||
|
const res = await fetch(basePath.addToPath('/api/capabilities'), {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ capabilities: mergedCapabilities }),
|
||||||
|
headers: {
|
||||||
|
'kbn-xsrf': 'xxx',
|
||||||
|
},
|
||||||
|
credentials: 'same-origin',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 401) {
|
||||||
|
return {
|
||||||
|
availableApps: [],
|
||||||
|
capabilities: deepFreeze({
|
||||||
|
navLinks: {},
|
||||||
|
management: {},
|
||||||
|
catalogue: {},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
} else if (res.status !== 200) {
|
||||||
|
throw new Error(`Capabilities check failed.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await res.json();
|
||||||
|
const capabilities = deepFreeze(body.capabilities as Capabilities);
|
||||||
|
const availableApps = apps.filter(app => capabilities.navLinks[app.id]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getCapabilities: () =>
|
availableApps,
|
||||||
deepFreeze(injectedMetadata.getInjectedVar('uiCapabilities') as Capabilities),
|
capabilities,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 { Capabilities } from './capabilities_service';
|
||||||
|
|
||||||
|
export const mergeCapabilities = (...sources: Array<Partial<Capabilities>>) =>
|
||||||
|
sources.reduce(
|
||||||
|
(capabilities, source) => {
|
||||||
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
|
capabilities[key] = {
|
||||||
|
...value,
|
||||||
|
...capabilities[key],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return capabilities;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
navLinks: {},
|
||||||
|
management: {},
|
||||||
|
catalogue: {},
|
||||||
|
}
|
||||||
|
);
|
21
src/core/public/application/index.ts
Normal file
21
src/core/public/application/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 { ApplicationService, ApplicationSetup, ApplicationStart } from './application_service';
|
||||||
|
export { Capabilities } from './capabilities';
|
|
@ -30,16 +30,21 @@ const createSetupContractMock = () => {
|
||||||
return setupContract;
|
return setupContract;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createStartContractMock = createSetupContractMock;
|
||||||
|
|
||||||
type BasePathServiceContract = PublicMethodsOf<BasePathService>;
|
type BasePathServiceContract = PublicMethodsOf<BasePathService>;
|
||||||
const createMock = () => {
|
const createMock = () => {
|
||||||
const mocked: jest.Mocked<BasePathServiceContract> = {
|
const mocked: jest.Mocked<BasePathServiceContract> = {
|
||||||
setup: jest.fn(),
|
setup: jest.fn(),
|
||||||
|
start: jest.fn(),
|
||||||
};
|
};
|
||||||
mocked.setup.mockReturnValue(createSetupContractMock());
|
mocked.setup.mockReturnValue(createSetupContractMock());
|
||||||
|
mocked.start.mockReturnValue(createStartContractMock());
|
||||||
return mocked;
|
return mocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const basePathServiceMock = {
|
export const basePathServiceMock = {
|
||||||
create: createMock,
|
create: createMock,
|
||||||
createSetupContract: createSetupContractMock,
|
createSetupContract: createSetupContractMock,
|
||||||
|
createStartContract: createStartContractMock,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
/* eslint-disable max-classes-per-file */
|
/* eslint-disable max-classes-per-file */
|
||||||
|
|
||||||
import { InjectedMetadataSetup } from '../injected_metadata';
|
import { InjectedMetadataSetup, InjectedMetadataStart } from '../injected_metadata';
|
||||||
import { modifyUrl } from '../utils';
|
import { modifyUrl } from '../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,13 +49,24 @@ export interface BasePathSetup {
|
||||||
removeFromPath(path: string): string;
|
removeFromPath(path: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BasePathDeps {
|
/**
|
||||||
|
* Provides access to the 'server.basePath' configuration option in kibana.yml
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export type BasePathStart = BasePathSetup;
|
||||||
|
|
||||||
|
interface SetupDeps {
|
||||||
injectedMetadata: InjectedMetadataSetup;
|
injectedMetadata: InjectedMetadataSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StartDeps {
|
||||||
|
injectedMetadata: InjectedMetadataStart;
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export class BasePathService {
|
export class BasePathService {
|
||||||
public setup({ injectedMetadata }: BasePathDeps) {
|
public setup({ injectedMetadata }: SetupDeps) {
|
||||||
const basePath = injectedMetadata.getBasePath() || '';
|
const basePath = injectedMetadata.getBasePath() || '';
|
||||||
|
|
||||||
const basePathSetup: BasePathSetup = {
|
const basePathSetup: BasePathSetup = {
|
||||||
|
@ -86,4 +97,8 @@ export class BasePathService {
|
||||||
|
|
||||||
return basePathSetup;
|
return basePathSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public start({ injectedMetadata }: StartDeps) {
|
||||||
|
return this.setup({ injectedMetadata });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,4 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { BasePathService, BasePathSetup } from './base_path_service';
|
export { BasePathService, BasePathSetup, BasePathStart } from './base_path_service';
|
||||||
|
|
|
@ -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.
|
|
||||||
*/
|
|
||||||
import { InjectedMetadataService } from '../injected_metadata';
|
|
||||||
import { CapabilitiesService } from './capabilities_service';
|
|
||||||
|
|
||||||
describe('#start', () => {
|
|
||||||
it('returns a service with getCapabilities', () => {
|
|
||||||
const injectedMetadata = new InjectedMetadataService({
|
|
||||||
injectedMetadata: {
|
|
||||||
vars: {
|
|
||||||
uiCapabilities: {
|
|
||||||
foo: 'bar',
|
|
||||||
bar: 'baz',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as any,
|
|
||||||
});
|
|
||||||
const service = new CapabilitiesService();
|
|
||||||
const startContract = service.start({ injectedMetadata: injectedMetadata.start() });
|
|
||||||
expect(startContract.getCapabilities()).toEqual({
|
|
||||||
foo: 'bar',
|
|
||||||
bar: 'baz',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`does not allow Capabilities to be modified`, () => {
|
|
||||||
const injectedMetadata = new InjectedMetadataService({
|
|
||||||
injectedMetadata: {
|
|
||||||
vars: {
|
|
||||||
uiCapabilities: {
|
|
||||||
foo: 'bar',
|
|
||||||
bar: 'baz',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as any,
|
|
||||||
});
|
|
||||||
const service = new CapabilitiesService();
|
|
||||||
const startContract = service.start({ injectedMetadata: injectedMetadata.start() });
|
|
||||||
const capabilities = startContract.getCapabilities();
|
|
||||||
|
|
||||||
// @ts-ignore TypeScript knows this shouldn't be possible
|
|
||||||
expect(() => (capabilities.foo = 'foo')).toThrowError();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { basePathServiceMock } from './base_path/base_path_service.mock';
|
import { basePathServiceMock } from './base_path/base_path_service.mock';
|
||||||
import { capabilitiesServiceMock } from './capabilities/capabilities_service.mock';
|
import { applicationServiceMock } from './application/application_service.mock';
|
||||||
import { chromeServiceMock } from './chrome/chrome_service.mock';
|
import { chromeServiceMock } from './chrome/chrome_service.mock';
|
||||||
import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
|
import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock';
|
||||||
import { httpServiceMock } from './http/http_service.mock';
|
import { httpServiceMock } from './http/http_service.mock';
|
||||||
|
@ -106,10 +106,10 @@ jest.doMock('./plugins', () => ({
|
||||||
PluginsService: PluginsServiceConstructor,
|
PluginsService: PluginsServiceConstructor,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const MockCapabilitiesService = capabilitiesServiceMock.create();
|
export const MockApplicationService = applicationServiceMock.create();
|
||||||
export const CapabilitiesServiceConstructor = jest
|
export const ApplicationServiceConstructor = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(() => MockCapabilitiesService);
|
.mockImplementation(() => MockApplicationService);
|
||||||
jest.doMock('./capabilities', () => ({
|
jest.doMock('./application', () => ({
|
||||||
CapabilitiesService: CapabilitiesServiceConstructor,
|
ApplicationService: ApplicationServiceConstructor,
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -39,7 +39,7 @@ import {
|
||||||
NotificationServiceConstructor,
|
NotificationServiceConstructor,
|
||||||
OverlayServiceConstructor,
|
OverlayServiceConstructor,
|
||||||
UiSettingsServiceConstructor,
|
UiSettingsServiceConstructor,
|
||||||
MockCapabilitiesService,
|
MockApplicationService,
|
||||||
} from './core_system.test.mocks';
|
} from './core_system.test.mocks';
|
||||||
|
|
||||||
import { CoreSystem } from './core_system';
|
import { CoreSystem } from './core_system';
|
||||||
|
@ -155,6 +155,11 @@ describe('#setup()', () => {
|
||||||
return core.setup();
|
return core.setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it('calls application#setup()', async () => {
|
||||||
|
await setupCore();
|
||||||
|
expect(MockApplicationService.setup).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('calls injectedMetadata#setup()', async () => {
|
it('calls injectedMetadata#setup()', async () => {
|
||||||
await setupCore();
|
await setupCore();
|
||||||
expect(MockInjectedMetadataService.setup).toHaveBeenCalledTimes(1);
|
expect(MockInjectedMetadataService.setup).toHaveBeenCalledTimes(1);
|
||||||
|
@ -219,9 +224,9 @@ describe('#start()', () => {
|
||||||
expect(root.innerHTML).toBe('<div></div><div></div><div></div>');
|
expect(root.innerHTML).toBe('<div></div><div></div><div></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls capabilities#start()', async () => {
|
it('calls application#start()', async () => {
|
||||||
await startCore();
|
await startCore();
|
||||||
expect(MockCapabilitiesService.start).toHaveBeenCalledTimes(1);
|
expect(MockApplicationService.start).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls i18n#start()', async () => {
|
it('calls i18n#start()', async () => {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import './core.css';
|
||||||
|
|
||||||
import { CoreSetup, CoreStart } from '.';
|
import { CoreSetup, CoreStart } from '.';
|
||||||
import { BasePathService } from './base_path';
|
import { BasePathService } from './base_path';
|
||||||
import { CapabilitiesService } from './capabilities';
|
|
||||||
import { ChromeService } from './chrome';
|
import { ChromeService } from './chrome';
|
||||||
import { FatalErrorsService } from './fatal_errors';
|
import { FatalErrorsService } from './fatal_errors';
|
||||||
import { HttpService } from './http';
|
import { HttpService } from './http';
|
||||||
|
@ -32,6 +31,7 @@ import { NotificationsService } from './notifications';
|
||||||
import { OverlayService } from './overlays';
|
import { OverlayService } from './overlays';
|
||||||
import { PluginsService } from './plugins';
|
import { PluginsService } from './plugins';
|
||||||
import { UiSettingsService } from './ui_settings';
|
import { UiSettingsService } from './ui_settings';
|
||||||
|
import { ApplicationService } from './application';
|
||||||
|
|
||||||
interface Params {
|
interface Params {
|
||||||
rootDomElement: HTMLElement;
|
rootDomElement: HTMLElement;
|
||||||
|
@ -63,9 +63,9 @@ export class CoreSystem {
|
||||||
private readonly basePath: BasePathService;
|
private readonly basePath: BasePathService;
|
||||||
private readonly chrome: ChromeService;
|
private readonly chrome: ChromeService;
|
||||||
private readonly i18n: I18nService;
|
private readonly i18n: I18nService;
|
||||||
private readonly capabilities: CapabilitiesService;
|
|
||||||
private readonly overlay: OverlayService;
|
private readonly overlay: OverlayService;
|
||||||
private readonly plugins: PluginsService;
|
private readonly plugins: PluginsService;
|
||||||
|
private readonly application: ApplicationService;
|
||||||
|
|
||||||
private readonly rootDomElement: HTMLElement;
|
private readonly rootDomElement: HTMLElement;
|
||||||
private readonly overlayTargetDomElement: HTMLDivElement;
|
private readonly overlayTargetDomElement: HTMLDivElement;
|
||||||
|
@ -83,8 +83,6 @@ export class CoreSystem {
|
||||||
|
|
||||||
this.i18n = new I18nService();
|
this.i18n = new I18nService();
|
||||||
|
|
||||||
this.capabilities = new CapabilitiesService();
|
|
||||||
|
|
||||||
this.injectedMetadata = new InjectedMetadataService({
|
this.injectedMetadata = new InjectedMetadataService({
|
||||||
injectedMetadata,
|
injectedMetadata,
|
||||||
});
|
});
|
||||||
|
@ -103,6 +101,7 @@ export class CoreSystem {
|
||||||
this.uiSettings = new UiSettingsService();
|
this.uiSettings = new UiSettingsService();
|
||||||
this.overlayTargetDomElement = document.createElement('div');
|
this.overlayTargetDomElement = document.createElement('div');
|
||||||
this.overlay = new OverlayService(this.overlayTargetDomElement);
|
this.overlay = new OverlayService(this.overlayTargetDomElement);
|
||||||
|
this.application = new ApplicationService();
|
||||||
this.chrome = new ChromeService({ browserSupportsCsp });
|
this.chrome = new ChromeService({ browserSupportsCsp });
|
||||||
|
|
||||||
const core: CoreContext = {};
|
const core: CoreContext = {};
|
||||||
|
@ -127,12 +126,14 @@ export class CoreSystem {
|
||||||
basePath,
|
basePath,
|
||||||
});
|
});
|
||||||
const notifications = this.notifications.setup({ uiSettings });
|
const notifications = this.notifications.setup({ uiSettings });
|
||||||
|
const application = this.application.setup();
|
||||||
const chrome = this.chrome.setup({
|
const chrome = this.chrome.setup({
|
||||||
injectedMetadata,
|
injectedMetadata,
|
||||||
notifications,
|
notifications,
|
||||||
});
|
});
|
||||||
|
|
||||||
const core: CoreSetup = {
|
const core: CoreSetup = {
|
||||||
|
application,
|
||||||
basePath,
|
basePath,
|
||||||
chrome,
|
chrome,
|
||||||
fatalErrors,
|
fatalErrors,
|
||||||
|
@ -155,27 +156,30 @@ export class CoreSystem {
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
try {
|
try {
|
||||||
// ensure the rootDomElement is empty
|
const injectedMetadata = await this.injectedMetadata.start();
|
||||||
this.rootDomElement.textContent = '';
|
const basePath = await this.basePath.start({ injectedMetadata });
|
||||||
this.rootDomElement.classList.add('coreSystemRootDomElement');
|
const i18n = await this.i18n.start();
|
||||||
|
const application = await this.application.start({ basePath, injectedMetadata });
|
||||||
|
|
||||||
const notificationsTargetDomElement = document.createElement('div');
|
const notificationsTargetDomElement = document.createElement('div');
|
||||||
const legacyPlatformTargetDomElement = document.createElement('div');
|
const legacyPlatformTargetDomElement = document.createElement('div');
|
||||||
|
|
||||||
|
// ensure the rootDomElement is empty
|
||||||
|
this.rootDomElement.textContent = '';
|
||||||
|
this.rootDomElement.classList.add('coreSystemRootDomElement');
|
||||||
this.rootDomElement.appendChild(notificationsTargetDomElement);
|
this.rootDomElement.appendChild(notificationsTargetDomElement);
|
||||||
this.rootDomElement.appendChild(legacyPlatformTargetDomElement);
|
this.rootDomElement.appendChild(legacyPlatformTargetDomElement);
|
||||||
this.rootDomElement.appendChild(this.overlayTargetDomElement);
|
this.rootDomElement.appendChild(this.overlayTargetDomElement);
|
||||||
|
|
||||||
const injectedMetadata = this.injectedMetadata.start();
|
const notifications = await this.notifications.start({
|
||||||
const i18n = this.i18n.start();
|
|
||||||
const capabilities = this.capabilities.start({ injectedMetadata });
|
|
||||||
const notifications = this.notifications.start({
|
|
||||||
i18n,
|
i18n,
|
||||||
targetDomElement: notificationsTargetDomElement,
|
targetDomElement: notificationsTargetDomElement,
|
||||||
});
|
});
|
||||||
const overlays = this.overlay.start({ i18n });
|
const overlays = await this.overlay.start({ i18n });
|
||||||
|
|
||||||
const core: CoreStart = {
|
const core: CoreStart = {
|
||||||
capabilities,
|
application,
|
||||||
|
basePath,
|
||||||
i18n,
|
i18n,
|
||||||
injectedMetadata,
|
injectedMetadata,
|
||||||
notifications,
|
notifications,
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BasePathSetup } from './base_path';
|
import { BasePathSetup, BasePathStart } from './base_path';
|
||||||
import { Capabilities, CapabilitiesStart } from './capabilities';
|
|
||||||
import {
|
import {
|
||||||
ChromeBadge,
|
ChromeBadge,
|
||||||
ChromeBrand,
|
ChromeBrand,
|
||||||
|
@ -33,6 +32,7 @@ import {
|
||||||
InjectedMetadataParams,
|
InjectedMetadataParams,
|
||||||
InjectedMetadataSetup,
|
InjectedMetadataSetup,
|
||||||
InjectedMetadataStart,
|
InjectedMetadataStart,
|
||||||
|
LegacyNavLink,
|
||||||
} from './injected_metadata';
|
} from './injected_metadata';
|
||||||
import {
|
import {
|
||||||
NotificationsSetup,
|
NotificationsSetup,
|
||||||
|
@ -44,6 +44,7 @@ import {
|
||||||
import { FlyoutRef, OverlayStart } from './overlays';
|
import { FlyoutRef, OverlayStart } from './overlays';
|
||||||
import { Plugin, PluginInitializer, PluginInitializerContext, PluginSetupContext } from './plugins';
|
import { Plugin, PluginInitializer, PluginInitializerContext, PluginSetupContext } from './plugins';
|
||||||
import { UiSettingsClient, UiSettingsSetup, UiSettingsState } from './ui_settings';
|
import { UiSettingsClient, UiSettingsSetup, UiSettingsState } from './ui_settings';
|
||||||
|
import { ApplicationSetup, Capabilities, ApplicationStart } from './application';
|
||||||
|
|
||||||
/** @interal */
|
/** @interal */
|
||||||
export { CoreContext, CoreSystem } from './core_system';
|
export { CoreContext, CoreSystem } from './core_system';
|
||||||
|
@ -58,6 +59,8 @@ export { CoreContext, CoreSystem } from './core_system';
|
||||||
* https://github.com/Microsoft/web-build-tools/issues/1237
|
* https://github.com/Microsoft/web-build-tools/issues/1237
|
||||||
*/
|
*/
|
||||||
export interface CoreSetup {
|
export interface CoreSetup {
|
||||||
|
/** {@link ApplicationSetup} */
|
||||||
|
application: ApplicationSetup;
|
||||||
/** {@link I18nSetup} */
|
/** {@link I18nSetup} */
|
||||||
i18n: I18nSetup;
|
i18n: I18nSetup;
|
||||||
/** {@link InjectedMetadataSetup} */
|
/** {@link InjectedMetadataSetup} */
|
||||||
|
@ -77,8 +80,10 @@ export interface CoreSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreStart {
|
export interface CoreStart {
|
||||||
/** {@link CapabilitiesStart} */
|
/** {@link ApplicationStart} */
|
||||||
capabilities: CapabilitiesStart;
|
application: ApplicationStart;
|
||||||
|
/** {@link BasePathStart} */
|
||||||
|
basePath: BasePathStart;
|
||||||
/** {@link I18nStart} */
|
/** {@link I18nStart} */
|
||||||
i18n: I18nStart;
|
i18n: I18nStart;
|
||||||
/** {@link InjectedMetadataStart} */
|
/** {@link InjectedMetadataStart} */
|
||||||
|
@ -90,11 +95,13 @@ export interface CoreStart {
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
ApplicationSetup,
|
||||||
|
ApplicationStart,
|
||||||
BasePathSetup,
|
BasePathSetup,
|
||||||
|
BasePathStart,
|
||||||
HttpSetup,
|
HttpSetup,
|
||||||
FatalErrorsSetup,
|
FatalErrorsSetup,
|
||||||
Capabilities,
|
Capabilities,
|
||||||
CapabilitiesStart,
|
|
||||||
ChromeSetup,
|
ChromeSetup,
|
||||||
ChromeBadge,
|
ChromeBadge,
|
||||||
ChromeBreadcrumb,
|
ChromeBreadcrumb,
|
||||||
|
@ -105,6 +112,7 @@ export {
|
||||||
InjectedMetadataSetup,
|
InjectedMetadataSetup,
|
||||||
InjectedMetadataStart,
|
InjectedMetadataStart,
|
||||||
InjectedMetadataParams,
|
InjectedMetadataParams,
|
||||||
|
LegacyNavLink,
|
||||||
Plugin,
|
Plugin,
|
||||||
PluginInitializer,
|
PluginInitializer,
|
||||||
PluginInitializerContext,
|
PluginInitializerContext,
|
||||||
|
|
|
@ -22,4 +22,5 @@ export {
|
||||||
InjectedMetadataParams,
|
InjectedMetadataParams,
|
||||||
InjectedMetadataSetup,
|
InjectedMetadataSetup,
|
||||||
InjectedMetadataStart,
|
InjectedMetadataStart,
|
||||||
|
LegacyNavLink,
|
||||||
} from './injected_metadata_service';
|
} from './injected_metadata_service';
|
||||||
|
|
|
@ -31,6 +31,7 @@ const createSetupContractMock = () => {
|
||||||
setupContract.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true });
|
setupContract.getCspConfig.mockReturnValue({ warnLegacyBrowsers: true });
|
||||||
setupContract.getKibanaVersion.mockReturnValue('kibanaVersion');
|
setupContract.getKibanaVersion.mockReturnValue('kibanaVersion');
|
||||||
setupContract.getLegacyMetadata.mockReturnValue({
|
setupContract.getLegacyMetadata.mockReturnValue({
|
||||||
|
nav: [],
|
||||||
uiSettings: {
|
uiSettings: {
|
||||||
defaults: { legacyInjectedUiSettingDefaults: true },
|
defaults: { legacyInjectedUiSettingDefaults: true },
|
||||||
user: { legacyInjectedUiSettingUserValues: true },
|
user: { legacyInjectedUiSettingUserValues: true },
|
||||||
|
|
|
@ -22,6 +22,16 @@ import { DiscoveredPlugin, PluginName } from '../../server';
|
||||||
import { UiSettingsState } from '../ui_settings';
|
import { UiSettingsState } from '../ui_settings';
|
||||||
import { deepFreeze } from '../utils/deep_freeze';
|
import { deepFreeze } from '../utils/deep_freeze';
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface LegacyNavLink {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
order: number;
|
||||||
|
url: string;
|
||||||
|
icon?: string;
|
||||||
|
euiIconType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export interface InjectedMetadataParams {
|
export interface InjectedMetadataParams {
|
||||||
injectedMetadata: {
|
injectedMetadata: {
|
||||||
|
@ -42,7 +52,7 @@ export interface InjectedMetadataParams {
|
||||||
app: unknown;
|
app: unknown;
|
||||||
translations: unknown;
|
translations: unknown;
|
||||||
bundleId: string;
|
bundleId: string;
|
||||||
nav: unknown;
|
nav: LegacyNavLink[];
|
||||||
version: string;
|
version: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
buildNum: number;
|
buildNum: number;
|
||||||
|
@ -140,7 +150,7 @@ export interface InjectedMetadataSetup {
|
||||||
app: unknown;
|
app: unknown;
|
||||||
translations: unknown;
|
translations: unknown;
|
||||||
bundleId: string;
|
bundleId: string;
|
||||||
nav: unknown;
|
nav: LegacyNavLink[];
|
||||||
version: string;
|
version: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
buildNum: number;
|
buildNum: number;
|
||||||
|
|
|
@ -150,7 +150,6 @@ jest.mock('ui/chrome/services/global_nav_state', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||||
import { capabilitiesServiceMock } from '../capabilities/capabilities_service.mock';
|
|
||||||
import { chromeServiceMock } from '../chrome/chrome_service.mock';
|
import { chromeServiceMock } from '../chrome/chrome_service.mock';
|
||||||
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock';
|
||||||
import { httpServiceMock } from '../http/http_service.mock';
|
import { httpServiceMock } from '../http/http_service.mock';
|
||||||
|
@ -160,7 +159,9 @@ import { notificationServiceMock } from '../notifications/notifications_service.
|
||||||
import { overlayServiceMock } from '../overlays/overlay_service.mock';
|
import { overlayServiceMock } from '../overlays/overlay_service.mock';
|
||||||
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
||||||
import { LegacyPlatformService } from './legacy_service';
|
import { LegacyPlatformService } from './legacy_service';
|
||||||
|
import { applicationServiceMock } from '../application/application_service.mock';
|
||||||
|
|
||||||
|
const applicationSetup = applicationServiceMock.createSetupContract();
|
||||||
const basePathSetup = basePathServiceMock.createSetupContract();
|
const basePathSetup = basePathServiceMock.createSetupContract();
|
||||||
const chromeSetup = chromeServiceMock.createSetupContract();
|
const chromeSetup = chromeServiceMock.createSetupContract();
|
||||||
const fatalErrorsSetup = fatalErrorsServiceMock.createSetupContract();
|
const fatalErrorsSetup = fatalErrorsServiceMock.createSetupContract();
|
||||||
|
@ -178,6 +179,7 @@ const defaultParams = {
|
||||||
|
|
||||||
const defaultSetupDeps = {
|
const defaultSetupDeps = {
|
||||||
core: {
|
core: {
|
||||||
|
application: applicationSetup,
|
||||||
i18n: i18nSetup,
|
i18n: i18nSetup,
|
||||||
fatalErrors: fatalErrorsSetup,
|
fatalErrors: fatalErrorsSetup,
|
||||||
injectedMetadata: injectedMetadataSetup,
|
injectedMetadata: injectedMetadataSetup,
|
||||||
|
@ -189,7 +191,8 @@ const defaultSetupDeps = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const capabilitiesStart = capabilitiesServiceMock.createStartContract();
|
const applicationStart = applicationServiceMock.createStartContract();
|
||||||
|
const basePathStart = basePathServiceMock.createStartContract();
|
||||||
const i18nStart = i18nServiceMock.createStartContract();
|
const i18nStart = i18nServiceMock.createStartContract();
|
||||||
const injectedMetadataStart = injectedMetadataServiceMock.createStartContract();
|
const injectedMetadataStart = injectedMetadataServiceMock.createStartContract();
|
||||||
const notificationsStart = notificationServiceMock.createStartContract();
|
const notificationsStart = notificationServiceMock.createStartContract();
|
||||||
|
@ -197,7 +200,8 @@ const overlayStart = overlayServiceMock.createStartContract();
|
||||||
|
|
||||||
const defaultStartDeps = {
|
const defaultStartDeps = {
|
||||||
core: {
|
core: {
|
||||||
capabilities: capabilitiesStart,
|
application: applicationStart,
|
||||||
|
basePath: basePathStart,
|
||||||
i18n: i18nStart,
|
i18n: i18nStart,
|
||||||
injectedMetadata: injectedMetadataStart,
|
injectedMetadata: injectedMetadataStart,
|
||||||
notifications: notificationsStart,
|
notifications: notificationsStart,
|
||||||
|
@ -208,7 +212,6 @@ const defaultStartDeps = {
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
injectedMetadataSetup.getLegacyMetadata.mockReset();
|
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
mockLoadOrder.length = 0;
|
mockLoadOrder.length = 0;
|
||||||
});
|
});
|
||||||
|
@ -216,8 +219,8 @@ afterEach(() => {
|
||||||
describe('#setup()', () => {
|
describe('#setup()', () => {
|
||||||
describe('default', () => {
|
describe('default', () => {
|
||||||
it('passes legacy metadata from injectedVars to ui/metadata', () => {
|
it('passes legacy metadata from injectedVars to ui/metadata', () => {
|
||||||
const legacyMetadata = { isLegacyMetadata: true };
|
const legacyMetadata = { nav: [], isLegacyMetadata: true };
|
||||||
injectedMetadataSetup.getLegacyMetadata.mockReturnValue(legacyMetadata as any);
|
injectedMetadataSetup.getLegacyMetadata.mockReturnValueOnce(legacyMetadata as any);
|
||||||
|
|
||||||
const legacyPlatform = new LegacyPlatformService({
|
const legacyPlatform = new LegacyPlatformService({
|
||||||
...defaultParams,
|
...defaultParams,
|
||||||
|
@ -404,7 +407,7 @@ describe('#start()', () => {
|
||||||
legacyPlatform.start(defaultStartDeps);
|
legacyPlatform.start(defaultStartDeps);
|
||||||
|
|
||||||
expect(mockUICapabilitiesInit).toHaveBeenCalledTimes(1);
|
expect(mockUICapabilitiesInit).toHaveBeenCalledTimes(1);
|
||||||
expect(mockUICapabilitiesInit).toHaveBeenCalledWith(capabilitiesStart);
|
expect(mockUICapabilitiesInit).toHaveBeenCalledWith(applicationStart.capabilities);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('useLegacyTestHarness = false', () => {
|
describe('useLegacyTestHarness = false', () => {
|
||||||
|
|
|
@ -52,8 +52,9 @@ export class LegacyPlatformService {
|
||||||
|
|
||||||
constructor(private readonly params: LegacyPlatformParams) {}
|
constructor(private readonly params: LegacyPlatformParams) {}
|
||||||
|
|
||||||
public async setup({ core }: SetupDeps) {
|
public setup({ core }: SetupDeps) {
|
||||||
const {
|
const {
|
||||||
|
application,
|
||||||
i18n,
|
i18n,
|
||||||
injectedMetadata,
|
injectedMetadata,
|
||||||
fatalErrors,
|
fatalErrors,
|
||||||
|
@ -81,6 +82,17 @@ export class LegacyPlatformService {
|
||||||
require('ui/chrome/api/breadcrumbs').__newPlatformSetup__(chrome);
|
require('ui/chrome/api/breadcrumbs').__newPlatformSetup__(chrome);
|
||||||
require('ui/chrome/services/global_nav_state').__newPlatformSetup__(chrome);
|
require('ui/chrome/services/global_nav_state').__newPlatformSetup__(chrome);
|
||||||
|
|
||||||
|
injectedMetadata.getLegacyMetadata().nav.forEach((navLink: any) =>
|
||||||
|
application.registerLegacyApp({
|
||||||
|
id: navLink.id,
|
||||||
|
order: navLink.order,
|
||||||
|
title: navLink.title,
|
||||||
|
euiIconType: navLink.euiIconType,
|
||||||
|
icon: navLink.icon,
|
||||||
|
appUrl: navLink.url,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Load the bootstrap module before loading the legacy platform files so that
|
// Load the bootstrap module before loading the legacy platform files so that
|
||||||
// the bootstrap module can modify the environment a bit first
|
// the bootstrap module can modify the environment a bit first
|
||||||
this.bootstrapModule = this.loadBootstrapModule();
|
this.bootstrapModule = this.loadBootstrapModule();
|
||||||
|
@ -97,7 +109,7 @@ export class LegacyPlatformService {
|
||||||
this.targetDomElement = targetDomElement;
|
this.targetDomElement = targetDomElement;
|
||||||
|
|
||||||
require('ui/new_platform').__newPlatformStart__(core);
|
require('ui/new_platform').__newPlatformStart__(core);
|
||||||
require('ui/capabilities').__newPlatformStart__(core.capabilities);
|
require('ui/capabilities').__newPlatformStart__(core.application.capabilities);
|
||||||
|
|
||||||
this.bootstrapModule.bootstrap(this.targetDomElement);
|
this.bootstrapModule.bootstrap(this.targetDomElement);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DiscoveredPlugin } from '../../server';
|
import { DiscoveredPlugin } from '../../server';
|
||||||
import { BasePathSetup } from '../base_path';
|
import { BasePathSetup, BasePathStart } from '../base_path';
|
||||||
import { ChromeSetup } from '../chrome';
|
import { ChromeSetup } from '../chrome';
|
||||||
import { CoreContext } from '../core_system';
|
import { CoreContext } from '../core_system';
|
||||||
import { FatalErrorsSetup } from '../fatal_errors';
|
import { FatalErrorsSetup } from '../fatal_errors';
|
||||||
|
@ -27,8 +27,9 @@ import { NotificationsSetup, NotificationsStart } from '../notifications';
|
||||||
import { UiSettingsSetup } from '../ui_settings';
|
import { UiSettingsSetup } from '../ui_settings';
|
||||||
import { PluginWrapper } from './plugin';
|
import { PluginWrapper } from './plugin';
|
||||||
import { PluginsServiceSetupDeps, PluginsServiceStartDeps } from './plugins_service';
|
import { PluginsServiceSetupDeps, PluginsServiceStartDeps } from './plugins_service';
|
||||||
import { CapabilitiesStart } from '../capabilities';
|
|
||||||
import { OverlayStart } from '../overlays';
|
import { OverlayStart } from '../overlays';
|
||||||
|
import { ApplicationStart } from '../application';
|
||||||
|
import { HttpSetup } from '../http';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The available core services passed to a `PluginInitializer`
|
* The available core services passed to a `PluginInitializer`
|
||||||
|
@ -47,6 +48,7 @@ export interface PluginSetupContext {
|
||||||
basePath: BasePathSetup;
|
basePath: BasePathSetup;
|
||||||
chrome: ChromeSetup;
|
chrome: ChromeSetup;
|
||||||
fatalErrors: FatalErrorsSetup;
|
fatalErrors: FatalErrorsSetup;
|
||||||
|
http: HttpSetup;
|
||||||
i18n: I18nSetup;
|
i18n: I18nSetup;
|
||||||
notifications: NotificationsSetup;
|
notifications: NotificationsSetup;
|
||||||
uiSettings: UiSettingsSetup;
|
uiSettings: UiSettingsSetup;
|
||||||
|
@ -58,7 +60,8 @@ export interface PluginSetupContext {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface PluginStartContext {
|
export interface PluginStartContext {
|
||||||
capabilities: CapabilitiesStart;
|
application: Pick<ApplicationStart, 'capabilities'>;
|
||||||
|
basePath: BasePathStart;
|
||||||
i18n: I18nStart;
|
i18n: I18nStart;
|
||||||
notifications: NotificationsStart;
|
notifications: NotificationsStart;
|
||||||
overlays: OverlayStart;
|
overlays: OverlayStart;
|
||||||
|
@ -95,6 +98,7 @@ export function createPluginSetupContext<TSetup, TStart, TPluginsSetup, TPlugins
|
||||||
plugin: PluginWrapper<TSetup, TStart, TPluginsSetup, TPluginsStart>
|
plugin: PluginWrapper<TSetup, TStart, TPluginsSetup, TPluginsStart>
|
||||||
): PluginSetupContext {
|
): PluginSetupContext {
|
||||||
return {
|
return {
|
||||||
|
http: deps.http,
|
||||||
basePath: deps.basePath,
|
basePath: deps.basePath,
|
||||||
chrome: deps.chrome,
|
chrome: deps.chrome,
|
||||||
fatalErrors: deps.fatalErrors,
|
fatalErrors: deps.fatalErrors,
|
||||||
|
@ -120,7 +124,10 @@ export function createPluginStartContext<TSetup, TStart, TPluginsSetup, TPlugins
|
||||||
plugin: PluginWrapper<TSetup, TStart, TPluginsSetup, TPluginsStart>
|
plugin: PluginWrapper<TSetup, TStart, TPluginsSetup, TPluginsStart>
|
||||||
): PluginStartContext {
|
): PluginStartContext {
|
||||||
return {
|
return {
|
||||||
capabilities: deps.capabilities,
|
application: {
|
||||||
|
capabilities: deps.application.capabilities,
|
||||||
|
},
|
||||||
|
basePath: deps.basePath,
|
||||||
i18n: deps.i18n,
|
i18n: deps.i18n,
|
||||||
notifications: deps.notifications,
|
notifications: deps.notifications,
|
||||||
overlays: deps.overlays,
|
overlays: deps.overlays,
|
||||||
|
|
|
@ -33,7 +33,7 @@ import {
|
||||||
PluginsServiceSetupDeps,
|
PluginsServiceSetupDeps,
|
||||||
} from './plugins_service';
|
} from './plugins_service';
|
||||||
import { notificationServiceMock } from '../notifications/notifications_service.mock';
|
import { notificationServiceMock } from '../notifications/notifications_service.mock';
|
||||||
import { capabilitiesServiceMock } from '../capabilities/capabilities_service.mock';
|
import { applicationServiceMock } from '../application/application_service.mock';
|
||||||
import { i18nServiceMock } from '../i18n/i18n_service.mock';
|
import { i18nServiceMock } from '../i18n/i18n_service.mock';
|
||||||
import { overlayServiceMock } from '../overlays/overlay_service.mock';
|
import { overlayServiceMock } from '../overlays/overlay_service.mock';
|
||||||
import { PluginStartContext, PluginSetupContext } from './plugin_context';
|
import { PluginStartContext, PluginSetupContext } from './plugin_context';
|
||||||
|
@ -42,6 +42,8 @@ import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.moc
|
||||||
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
import { uiSettingsServiceMock } from '../ui_settings/ui_settings_service.mock';
|
||||||
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
import { basePathServiceMock } from '../base_path/base_path_service.mock';
|
||||||
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
|
||||||
|
import { UiSettingsClient } from '../ui_settings';
|
||||||
|
import { httpServiceMock } from '../http/http_service.mock';
|
||||||
|
|
||||||
export let mockPluginInitializers: Map<PluginName, MockedPluginInitializer>;
|
export let mockPluginInitializers: Map<PluginName, MockedPluginInitializer>;
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@ let mockStartContext: DeeplyMocked<PluginStartContext>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockSetupDeps = {
|
mockSetupDeps = {
|
||||||
|
application: applicationServiceMock.createSetupContract(),
|
||||||
injectedMetadata: (function() {
|
injectedMetadata: (function() {
|
||||||
const metadata = injectedMetadataServiceMock.createSetupContract();
|
const metadata = injectedMetadataServiceMock.createSetupContract();
|
||||||
metadata.getPlugins.mockReturnValue([
|
metadata.getPlugins.mockReturnValue([
|
||||||
|
@ -78,19 +81,26 @@ beforeEach(() => {
|
||||||
})(),
|
})(),
|
||||||
chrome: chromeServiceMock.createSetupContract(),
|
chrome: chromeServiceMock.createSetupContract(),
|
||||||
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
|
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
|
||||||
|
http: httpServiceMock.createSetupContract(),
|
||||||
i18n: i18nServiceMock.createSetupContract(),
|
i18n: i18nServiceMock.createSetupContract(),
|
||||||
notifications: notificationServiceMock.createSetupContract(),
|
notifications: notificationServiceMock.createSetupContract(),
|
||||||
uiSettings: uiSettingsServiceMock.createSetupContract(),
|
uiSettings: uiSettingsServiceMock.createSetupContract() as jest.Mocked<UiSettingsClient>,
|
||||||
} as any;
|
};
|
||||||
mockSetupContext = omit(mockSetupDeps, 'injectedMetadata');
|
mockSetupContext = omit(mockSetupDeps, 'application', 'injectedMetadata');
|
||||||
mockStartDeps = {
|
mockStartDeps = {
|
||||||
capabilities: capabilitiesServiceMock.createStartContract(),
|
application: applicationServiceMock.createStartContract(),
|
||||||
|
basePath: basePathServiceMock.createStartContract(),
|
||||||
i18n: i18nServiceMock.createStartContract(),
|
i18n: i18nServiceMock.createStartContract(),
|
||||||
injectedMetadata: injectedMetadataServiceMock.createStartContract(),
|
injectedMetadata: injectedMetadataServiceMock.createStartContract(),
|
||||||
notifications: notificationServiceMock.createStartContract(),
|
notifications: notificationServiceMock.createStartContract(),
|
||||||
overlays: overlayServiceMock.createStartContract(),
|
overlays: overlayServiceMock.createStartContract(),
|
||||||
};
|
};
|
||||||
mockStartContext = omit(mockStartDeps, 'injectedMetadata');
|
mockStartContext = {
|
||||||
|
...omit(mockStartDeps, 'injectedMetadata'),
|
||||||
|
application: {
|
||||||
|
capabilities: mockStartDeps.application.capabilities,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Reset these for each test.
|
// Reset these for each test.
|
||||||
mockPluginInitializers = new Map<PluginName, MockedPluginInitializer>(([
|
mockPluginInitializers = new Map<PluginName, MockedPluginInitializer>(([
|
||||||
|
|
|
@ -7,10 +7,35 @@
|
||||||
import * as CSS from 'csstype';
|
import * as CSS from 'csstype';
|
||||||
import { default } from 'react';
|
import { default } from 'react';
|
||||||
import { IconType } from '@elastic/eui';
|
import { IconType } from '@elastic/eui';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
import * as Rx from 'rxjs';
|
import * as Rx from 'rxjs';
|
||||||
import { Toast } from '@elastic/eui';
|
import { Toast } from '@elastic/eui';
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface ApplicationSetup {
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "App" needs to be exported by the entry point index.d.ts
|
||||||
|
registerApp(app: App): void;
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "LegacyApp" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
|
// @internal
|
||||||
|
registerLegacyApp(app: LegacyApp): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning: (ae-missing-release-tag) "ApplicationStart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
|
//
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface ApplicationStart {
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "CapabilitiesStart" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
|
// (undocumented)
|
||||||
|
availableApps: CapabilitiesStart['availableApps'];
|
||||||
|
// (undocumented)
|
||||||
|
capabilities: CapabilitiesStart['capabilities'];
|
||||||
|
// (undocumented)
|
||||||
|
mount: (mountHandler: Function) => void;
|
||||||
|
}
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export interface BasePathSetup {
|
export interface BasePathSetup {
|
||||||
addToPath(path: string): string;
|
addToPath(path: string): string;
|
||||||
|
@ -18,6 +43,9 @@ export interface BasePathSetup {
|
||||||
removeFromPath(path: string): string;
|
removeFromPath(path: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @public
|
||||||
|
export type BasePathStart = BasePathSetup;
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export interface Capabilities {
|
export interface Capabilities {
|
||||||
[key: string]: Record<string, boolean | Record<string, boolean>>;
|
[key: string]: Record<string, boolean | Record<string, boolean>>;
|
||||||
|
@ -28,11 +56,6 @@ export interface Capabilities {
|
||||||
navLinks: Record<string, boolean>;
|
navLinks: Record<string, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public
|
|
||||||
export interface CapabilitiesStart {
|
|
||||||
getCapabilities: () => Capabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface ChromeBadge {
|
export interface ChromeBadge {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -75,6 +98,8 @@ export interface CoreContext {
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export interface CoreSetup {
|
export interface CoreSetup {
|
||||||
|
// (undocumented)
|
||||||
|
application: ApplicationSetup;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
basePath: BasePathSetup;
|
basePath: BasePathSetup;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -98,7 +123,9 @@ export interface CoreSetup {
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface CoreStart {
|
export interface CoreStart {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
capabilities: CapabilitiesStart;
|
application: ApplicationStart;
|
||||||
|
// (undocumented)
|
||||||
|
basePath: BasePathStart;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
i18n: I18nStart;
|
i18n: I18nStart;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -175,7 +202,7 @@ export interface InjectedMetadataParams {
|
||||||
app: unknown;
|
app: unknown;
|
||||||
translations: unknown;
|
translations: unknown;
|
||||||
bundleId: string;
|
bundleId: string;
|
||||||
nav: unknown;
|
nav: LegacyNavLink[];
|
||||||
version: string;
|
version: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
buildNum: number;
|
buildNum: number;
|
||||||
|
@ -212,7 +239,7 @@ export interface InjectedMetadataSetup {
|
||||||
app: unknown;
|
app: unknown;
|
||||||
translations: unknown;
|
translations: unknown;
|
||||||
bundleId: string;
|
bundleId: string;
|
||||||
nav: unknown;
|
nav: LegacyNavLink[];
|
||||||
version: string;
|
version: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
buildNum: number;
|
buildNum: number;
|
||||||
|
@ -234,6 +261,22 @@ export interface InjectedMetadataSetup {
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type InjectedMetadataStart = InjectedMetadataSetup;
|
export type InjectedMetadataStart = InjectedMetadataSetup;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface LegacyNavLink {
|
||||||
|
// (undocumented)
|
||||||
|
euiIconType?: string;
|
||||||
|
// (undocumented)
|
||||||
|
icon?: string;
|
||||||
|
// (undocumented)
|
||||||
|
id: string;
|
||||||
|
// (undocumented)
|
||||||
|
order: number;
|
||||||
|
// (undocumented)
|
||||||
|
title: string;
|
||||||
|
// (undocumented)
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface NotificationsSetup {
|
export interface NotificationsSetup {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -282,6 +325,8 @@ export interface PluginSetupContext {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
fatalErrors: FatalErrorsSetup;
|
fatalErrors: FatalErrorsSetup;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
http: HttpSetup;
|
||||||
|
// (undocumented)
|
||||||
i18n: I18nSetup;
|
i18n: I18nSetup;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
notifications: NotificationsSetup;
|
notifications: NotificationsSetup;
|
||||||
|
@ -356,8 +401,8 @@ export interface UiSettingsState {
|
||||||
|
|
||||||
// Warnings were encountered during analysis:
|
// Warnings were encountered during analysis:
|
||||||
//
|
//
|
||||||
// src/core/public/injected_metadata/injected_metadata_service.ts:38:7 - (ae-forgotten-export) The symbol "PluginName" needs to be exported by the entry point index.d.ts
|
// src/core/public/injected_metadata/injected_metadata_service.ts:48:7 - (ae-forgotten-export) The symbol "PluginName" needs to be exported by the entry point index.d.ts
|
||||||
// src/core/public/injected_metadata/injected_metadata_service.ts:39:7 - (ae-forgotten-export) The symbol "DiscoveredPlugin" needs to be exported by the entry point index.d.ts
|
// src/core/public/injected_metadata/injected_metadata_service.ts:49:7 - (ae-forgotten-export) The symbol "DiscoveredPlugin" needs to be exported by the entry point index.d.ts
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ type Freezable = { [k: string]: any } | any[];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
interface RecursiveReadonlyArray<T> extends Array<RecursiveReadonly<T>> {}
|
interface RecursiveReadonlyArray<T> extends Array<RecursiveReadonly<T>> {}
|
||||||
|
|
||||||
type RecursiveReadonly<T> = T extends any[]
|
export type RecursiveReadonly<T> = T extends any[]
|
||||||
? RecursiveReadonlyArray<T[number]>
|
? RecursiveReadonlyArray<T[number]>
|
||||||
: T extends object
|
: T extends object
|
||||||
? Readonly<{ [K in keyof T]: RecursiveReadonly<T[K]> }>
|
? Readonly<{ [K in keyof T]: RecursiveReadonly<T[K]> }>
|
||||||
|
|
|
@ -96,6 +96,15 @@ export default function (kibana) {
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uiCapabilities() {
|
||||||
|
return {
|
||||||
|
dev_tools: {
|
||||||
|
show: true,
|
||||||
|
save: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
async init(server, options) {
|
async init(server, options) {
|
||||||
server.expose('addExtensionSpecFilePath', addExtensionSpecFilePath);
|
server.expose('addExtensionSpecFilePath', addExtensionSpecFilePath);
|
||||||
if (options.ssl && options.ssl.verify) {
|
if (options.ssl && options.ssl.verify) {
|
||||||
|
@ -111,12 +120,6 @@ export default function (kibana) {
|
||||||
elasticsearchUrl: url.format(
|
elasticsearchUrl: url.format(
|
||||||
Object.assign(url.parse(head(legacyEsConfig.hosts)), { auth: false })
|
Object.assign(url.parse(head(legacyEsConfig.hosts)), { auth: false })
|
||||||
),
|
),
|
||||||
uiCapabilities: {
|
|
||||||
dev_tools: {
|
|
||||||
show: true,
|
|
||||||
save: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
server.route(createProxyRoute({
|
server.route(createProxyRoute({
|
||||||
|
|
|
@ -228,62 +228,9 @@ export default function (kibana) {
|
||||||
},
|
},
|
||||||
|
|
||||||
injectDefaultVars(server, options) {
|
injectDefaultVars(server, options) {
|
||||||
const { savedObjects } = server;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kbnIndex: options.index,
|
kbnIndex: options.index,
|
||||||
kbnBaseUrl,
|
kbnBaseUrl,
|
||||||
uiCapabilities: {
|
|
||||||
discover: {
|
|
||||||
show: true,
|
|
||||||
createShortUrl: true,
|
|
||||||
save: true,
|
|
||||||
},
|
|
||||||
visualize: {
|
|
||||||
show: true,
|
|
||||||
createShortUrl: true,
|
|
||||||
delete: true,
|
|
||||||
save: true,
|
|
||||||
},
|
|
||||||
dashboard: {
|
|
||||||
createNew: true,
|
|
||||||
show: true,
|
|
||||||
showWriteControls: true,
|
|
||||||
},
|
|
||||||
catalogue: {
|
|
||||||
discover: true,
|
|
||||||
dashboard: true,
|
|
||||||
visualize: true,
|
|
||||||
console: true,
|
|
||||||
advanced_settings: true,
|
|
||||||
index_patterns: true,
|
|
||||||
},
|
|
||||||
advancedSettings: {
|
|
||||||
show: true,
|
|
||||||
save: true
|
|
||||||
},
|
|
||||||
indexPatterns: {
|
|
||||||
save: true,
|
|
||||||
},
|
|
||||||
savedObjectsManagement: savedObjects.types.reduce((acc, type) => ({
|
|
||||||
...acc,
|
|
||||||
[type]: {
|
|
||||||
delete: true,
|
|
||||||
edit: true,
|
|
||||||
read: true,
|
|
||||||
}
|
|
||||||
}), {}),
|
|
||||||
management: {
|
|
||||||
/*
|
|
||||||
* Management settings correspond to management section/link ids, and should not be changed
|
|
||||||
* without also updating those definitions.
|
|
||||||
*/
|
|
||||||
kibana: {
|
|
||||||
settings: true,
|
|
||||||
index_patterns: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -293,6 +240,62 @@ export default function (kibana) {
|
||||||
migrations,
|
migrations,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uiCapabilities: async function (server) {
|
||||||
|
const { savedObjects } = server;
|
||||||
|
|
||||||
|
return {
|
||||||
|
discover: {
|
||||||
|
show: true,
|
||||||
|
createShortUrl: true,
|
||||||
|
save: true,
|
||||||
|
},
|
||||||
|
visualize: {
|
||||||
|
show: true,
|
||||||
|
createShortUrl: true,
|
||||||
|
delete: true,
|
||||||
|
save: true,
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
createNew: true,
|
||||||
|
show: true,
|
||||||
|
showWriteControls: true,
|
||||||
|
},
|
||||||
|
catalogue: {
|
||||||
|
discover: true,
|
||||||
|
dashboard: true,
|
||||||
|
visualize: true,
|
||||||
|
console: true,
|
||||||
|
advanced_settings: true,
|
||||||
|
index_patterns: true,
|
||||||
|
},
|
||||||
|
advancedSettings: {
|
||||||
|
show: true,
|
||||||
|
save: true
|
||||||
|
},
|
||||||
|
indexPatterns: {
|
||||||
|
save: true,
|
||||||
|
},
|
||||||
|
savedObjectsManagement: savedObjects.types.reduce((acc, type) => ({
|
||||||
|
...acc,
|
||||||
|
[type]: {
|
||||||
|
delete: true,
|
||||||
|
edit: true,
|
||||||
|
read: true,
|
||||||
|
}
|
||||||
|
}), {}),
|
||||||
|
management: {
|
||||||
|
/*
|
||||||
|
* Management settings correspond to management section/link ids, and should not be changed
|
||||||
|
* without also updating those definitions.
|
||||||
|
*/
|
||||||
|
kibana: {
|
||||||
|
settings: true,
|
||||||
|
index_patterns: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
preInit: async function (server) {
|
preInit: async function (server) {
|
||||||
try {
|
try {
|
||||||
// Create the data directory (recursively, if the a parent dir doesn't exist).
|
// Create the data directory (recursively, if the a parent dir doesn't exist).
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
|
||||||
import { ObjectsTable } from './components/objects_table';
|
import { ObjectsTable } from './components/objects_table';
|
||||||
import { I18nContext } from 'ui/i18n';
|
import { I18nContext } from 'ui/i18n';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
|
import { getNewPlatform } from 'ui/new_platform';
|
||||||
|
|
||||||
import { getIndexBreadcrumbs } from './breadcrumbs';
|
import { getIndexBreadcrumbs } from './breadcrumbs';
|
||||||
|
|
||||||
|
@ -39,10 +40,10 @@ function updateObjectsTable($scope, $injector) {
|
||||||
const $http = $injector.get('$http');
|
const $http = $injector.get('$http');
|
||||||
const kbnUrl = $injector.get('kbnUrl');
|
const kbnUrl = $injector.get('kbnUrl');
|
||||||
const config = $injector.get('config');
|
const config = $injector.get('config');
|
||||||
const uiCapabilites = chrome.getInjected('uiCapabilities');
|
|
||||||
|
|
||||||
const savedObjectsClient = Private(SavedObjectsClientProvider);
|
const savedObjectsClient = Private(SavedObjectsClientProvider);
|
||||||
const services = savedObjectManagementRegistry.all().map(obj => $injector.get(obj.service));
|
const services = savedObjectManagementRegistry.all().map(obj => $injector.get(obj.service));
|
||||||
|
const uiCapabilites = getNewPlatform().start.core.application.capabilities;
|
||||||
|
|
||||||
$scope.$$postDigest(() => {
|
$scope.$$postDigest(() => {
|
||||||
const node = document.getElementById(REACT_OBJECTS_TABLE_DOM_ELEMENT_ID);
|
const node = document.getElementById(REACT_OBJECTS_TABLE_DOM_ELEMENT_ID);
|
||||||
|
|
|
@ -35,8 +35,47 @@ import 'custom-event-polyfill';
|
||||||
import 'whatwg-fetch';
|
import 'whatwg-fetch';
|
||||||
import 'abortcontroller-polyfill';
|
import 'abortcontroller-polyfill';
|
||||||
import 'childnode-remove-polyfill';
|
import 'childnode-remove-polyfill';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
import { CoreSystem } from '__kibanaCore__'
|
import { CoreSystem } from '__kibanaCore__';
|
||||||
|
|
||||||
|
// Fake uiCapabilities returned to Core in browser tests
|
||||||
|
const uiCapabilities = {
|
||||||
|
navLinks: {
|
||||||
|
myLink: true,
|
||||||
|
notMyLink: true,
|
||||||
|
},
|
||||||
|
discover: {
|
||||||
|
showWriteControls: true
|
||||||
|
},
|
||||||
|
visualize: {
|
||||||
|
save: true
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
showWriteControls: true
|
||||||
|
},
|
||||||
|
timelion: {
|
||||||
|
save: true
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stub fetch for CoreSystem calls.
|
||||||
|
const fetchStub = sinon.stub(window, 'fetch');
|
||||||
|
fetchStub.callsFake((url, options) => {
|
||||||
|
if (url !== '/api/capabilities') {
|
||||||
|
console.warn('Stubbed window.fetch does not support this request.');
|
||||||
|
return Promise.resolve(new window.Response('Resource not found', { status: 404 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(
|
||||||
|
new window.Response(
|
||||||
|
JSON.stringify({ capabilities: uiCapabilities })),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// render the core system in a child of the body as the default children of the body
|
// render the core system in a child of the body as the default children of the body
|
||||||
// in the browser tests are needed for mocha and other test components to work
|
// in the browser tests are needed for mocha and other test components to work
|
||||||
|
@ -48,6 +87,7 @@ const coreSystem = new CoreSystem({
|
||||||
version: '1.2.3',
|
version: '1.2.3',
|
||||||
buildNumber: 1234,
|
buildNumber: 1234,
|
||||||
legacyMetadata: {
|
legacyMetadata: {
|
||||||
|
nav: [],
|
||||||
version: '1.2.3',
|
version: '1.2.3',
|
||||||
buildNum: 1234,
|
buildNum: 1234,
|
||||||
devMode: true,
|
devMode: true,
|
||||||
|
@ -85,24 +125,6 @@ const coreSystem = new CoreSystem({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
enableExternalUrls: true
|
enableExternalUrls: true
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
navLinks: {
|
|
||||||
myLink: true,
|
|
||||||
notMyLink: true,
|
|
||||||
},
|
|
||||||
discover: {
|
|
||||||
showWriteControls: true
|
|
||||||
},
|
|
||||||
visualize: {
|
|
||||||
save: true
|
|
||||||
},
|
|
||||||
dashboard: {
|
|
||||||
showWriteControls: true
|
|
||||||
},
|
|
||||||
timelion: {
|
|
||||||
save: true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
interpreterConfig: {
|
interpreterConfig: {
|
||||||
enableInVisualize: true
|
enableInVisualize: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,14 @@ export default function (kibana) {
|
||||||
}).default();
|
}).default();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uiCapabilities() {
|
||||||
|
return {
|
||||||
|
timelion: {
|
||||||
|
save: true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
uiExports: {
|
uiExports: {
|
||||||
app: {
|
app: {
|
||||||
title: 'Timelion',
|
title: 'Timelion',
|
||||||
|
@ -54,11 +62,6 @@ export default function (kibana) {
|
||||||
injectDefaultVars(server) {
|
injectDefaultVars(server) {
|
||||||
return {
|
return {
|
||||||
timelionUiEnabled: server.config().get('timelion.ui.enabled'),
|
timelionUiEnabled: server.config().get('timelion.ui.enabled'),
|
||||||
uiCapabilities: {
|
|
||||||
timelion: {
|
|
||||||
save: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
visTypes: [
|
visTypes: [
|
||||||
|
|
|
@ -56,6 +56,7 @@ export class PluginSpec {
|
||||||
version,
|
version,
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
uiExports,
|
uiExports,
|
||||||
|
uiCapabilities,
|
||||||
publicDir,
|
publicDir,
|
||||||
configPrefix,
|
configPrefix,
|
||||||
config,
|
config,
|
||||||
|
@ -74,6 +75,7 @@ export class PluginSpec {
|
||||||
|
|
||||||
this._publicDir = publicDir;
|
this._publicDir = publicDir;
|
||||||
this._uiExports = uiExports;
|
this._uiExports = uiExports;
|
||||||
|
this._uiCapabilities = uiCapabilities;
|
||||||
|
|
||||||
this._configPrefix = configPrefix;
|
this._configPrefix = configPrefix;
|
||||||
this._configSchemaProvider = config;
|
this._configSchemaProvider = config;
|
||||||
|
@ -170,6 +172,10 @@ export class PluginSpec {
|
||||||
return this._uiExports;
|
return this._uiExports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUiCapabilitiesProvider() {
|
||||||
|
return this._uiCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
getPreInitHandler() {
|
getPreInitHandler() {
|
||||||
return this._preInit;
|
return this._preInit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { Server } from '../../server/kbn_server';
|
import { Server } from '../../server/kbn_server';
|
||||||
|
import { Capabilities } from '../../../core/public';
|
||||||
|
|
||||||
export type InitPluginFunction = (server: Server) => void;
|
export type InitPluginFunction = (server: Server) => void;
|
||||||
export interface UiExports {
|
export interface UiExports {
|
||||||
|
@ -29,6 +30,7 @@ export interface PluginSpecOptions {
|
||||||
require: string[];
|
require: string[];
|
||||||
publicDir: string;
|
publicDir: string;
|
||||||
uiExports?: UiExports;
|
uiExports?: UiExports;
|
||||||
|
uiCapabilities?: Capabilities;
|
||||||
init: InitPluginFunction;
|
init: InitPluginFunction;
|
||||||
config: any;
|
config: any;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 const mockRegisterCapabilitiesRoute = jest.fn();
|
||||||
|
jest.mock('./capabilities_route', () => ({
|
||||||
|
registerCapabilitiesRoute: mockRegisterCapabilitiesRoute,
|
||||||
|
}));
|
88
src/legacy/server/capabilities/capabilities_mixin.test.ts
Normal file
88
src/legacy/server/capabilities/capabilities_mixin.test.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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 KbnServer from '../kbn_server';
|
||||||
|
import { mockRegisterCapabilitiesRoute } from './capabilities_mixin.test.mocks';
|
||||||
|
|
||||||
|
import { capabilitiesMixin } from './capabilities_mixin';
|
||||||
|
|
||||||
|
describe('capabilitiesMixin', () => {
|
||||||
|
const getKbnServer = (pluginSpecs: any[] = []) => {
|
||||||
|
return {
|
||||||
|
afterPluginsInit: (callback: () => void) => callback(),
|
||||||
|
pluginSpecs,
|
||||||
|
} as KbnServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
let server: Server;
|
||||||
|
beforeEach(() => {
|
||||||
|
server = new Server();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mockRegisterCapabilitiesRoute.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls registerCapabilitiesRoute with merged uiCapabilitiesProviers', async () => {
|
||||||
|
const kbnServer = getKbnServer([
|
||||||
|
{
|
||||||
|
getUiCapabilitiesProvider: () => () => ({
|
||||||
|
app1: { read: true },
|
||||||
|
management: { section1: { feature1: true } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getUiCapabilitiesProvider: () => () => ({
|
||||||
|
app2: { write: true },
|
||||||
|
catalogue: { feature3: true },
|
||||||
|
management: { section2: { feature2: true } },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await capabilitiesMixin(kbnServer, server);
|
||||||
|
|
||||||
|
expect(mockRegisterCapabilitiesRoute).toHaveBeenCalledWith(
|
||||||
|
server,
|
||||||
|
{
|
||||||
|
app1: { read: true },
|
||||||
|
app2: { write: true },
|
||||||
|
catalogue: { feature3: true },
|
||||||
|
management: {
|
||||||
|
section1: { feature1: true },
|
||||||
|
section2: { feature2: true },
|
||||||
|
},
|
||||||
|
navLinks: {},
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exposes server#registerCapabilitiesModifier for providing modifiers to the route', async () => {
|
||||||
|
const kbnServer = getKbnServer();
|
||||||
|
await capabilitiesMixin(kbnServer, server);
|
||||||
|
const mockModifier1 = jest.fn();
|
||||||
|
const mockModifier2 = jest.fn();
|
||||||
|
server.registerCapabilitiesModifier(mockModifier1);
|
||||||
|
server.registerCapabilitiesModifier(mockModifier2);
|
||||||
|
|
||||||
|
expect(mockRegisterCapabilitiesRoute.mock.calls[0][2]).toEqual([mockModifier1, mockModifier2]);
|
||||||
|
});
|
||||||
|
});
|
53
src/legacy/server/capabilities/capabilities_mixin.ts
Normal file
53
src/legacy/server/capabilities/capabilities_mixin.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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, Request } from 'hapi';
|
||||||
|
|
||||||
|
import { Capabilities } from '../../../core/public';
|
||||||
|
import KbnServer from '../kbn_server';
|
||||||
|
import { registerCapabilitiesRoute } from './capabilities_route';
|
||||||
|
import { mergeCapabilities } from './merge_capabilities';
|
||||||
|
|
||||||
|
export type CapabilitiesModifier = (
|
||||||
|
request: Request,
|
||||||
|
uiCapabilities: Capabilities
|
||||||
|
) => Capabilities | Promise<Capabilities>;
|
||||||
|
|
||||||
|
export async function capabilitiesMixin(kbnServer: KbnServer, server: Server) {
|
||||||
|
const modifiers: CapabilitiesModifier[] = [];
|
||||||
|
|
||||||
|
server.decorate('server', 'registerCapabilitiesModifier', (provider: CapabilitiesModifier) => {
|
||||||
|
modifiers.push(provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Some plugin capabilities are derived from data provided by other plugins,
|
||||||
|
// so we need to wait until after all plugins have been init'd to fetch uiCapabilities.
|
||||||
|
kbnServer.afterPluginsInit(async () => {
|
||||||
|
const defaultCapabilities = mergeCapabilities(
|
||||||
|
...(await Promise.all(
|
||||||
|
kbnServer.pluginSpecs
|
||||||
|
.map(spec => spec.getUiCapabilitiesProvider())
|
||||||
|
.filter(provider => !!provider)
|
||||||
|
.map(provider => provider(server))
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, modifiers);
|
||||||
|
});
|
||||||
|
}
|
137
src/legacy/server/capabilities/capabilities_route.test.ts
Normal file
137
src/legacy/server/capabilities/capabilities_route.test.ts
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* 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 { registerCapabilitiesRoute } from './capabilities_route';
|
||||||
|
import { Capabilities } from '../../../core/public';
|
||||||
|
|
||||||
|
describe('capabilities api', () => {
|
||||||
|
const defaultCapabilities = {
|
||||||
|
catalogue: {
|
||||||
|
feature1: true,
|
||||||
|
feature2: true,
|
||||||
|
},
|
||||||
|
management: {
|
||||||
|
section1: {
|
||||||
|
read: true,
|
||||||
|
},
|
||||||
|
section2: {
|
||||||
|
write: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
navLinks: {
|
||||||
|
app1: true,
|
||||||
|
app2: true,
|
||||||
|
},
|
||||||
|
myApp: {
|
||||||
|
read: true,
|
||||||
|
write: true,
|
||||||
|
kioskMode: true,
|
||||||
|
},
|
||||||
|
} as Capabilities;
|
||||||
|
|
||||||
|
let server: Server;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
server = new Server();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns unmodified uiCapabilities if no modifiers are available', async () => {
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, []);
|
||||||
|
const resp = await server.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/capabilities',
|
||||||
|
payload: { capabilities: {} },
|
||||||
|
});
|
||||||
|
expect(JSON.parse(resp.payload)).toEqual({
|
||||||
|
capabilities: defaultCapabilities,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges payload capabilities with defaultCapabilities', async () => {
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, []);
|
||||||
|
const resp = await server.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/capabilities',
|
||||||
|
payload: { capabilities: { navLinks: { app3: true } } },
|
||||||
|
});
|
||||||
|
expect(JSON.parse(resp.payload)).toEqual({
|
||||||
|
capabilities: {
|
||||||
|
...defaultCapabilities,
|
||||||
|
navLinks: {
|
||||||
|
...defaultCapabilities.navLinks,
|
||||||
|
app3: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows a single provider to modify uiCapabilities', async () => {
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, [
|
||||||
|
(req, caps) => {
|
||||||
|
caps.management.section2.write = false;
|
||||||
|
caps.myApp.write = false;
|
||||||
|
return caps;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const resp = await server.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/capabilities',
|
||||||
|
payload: { capabilities: {} },
|
||||||
|
});
|
||||||
|
const results = JSON.parse(resp.payload);
|
||||||
|
expect(results.capabilities.management.section2.write).toBe(false);
|
||||||
|
expect(results.capabilities.myApp.write).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows multiple providers to modify uiCapabilities', async () => {
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, [
|
||||||
|
(req, caps) => {
|
||||||
|
caps.management.section2.write = false;
|
||||||
|
return caps;
|
||||||
|
},
|
||||||
|
(req, caps) => {
|
||||||
|
caps.myApp.write = false;
|
||||||
|
return caps;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const resp = await server.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/capabilities',
|
||||||
|
payload: { capabilities: {} },
|
||||||
|
});
|
||||||
|
const results = JSON.parse(resp.payload);
|
||||||
|
expect(results.capabilities.management.section2.write).toBe(false);
|
||||||
|
expect(results.capabilities.myApp.write).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an error if any providers fail', async () => {
|
||||||
|
registerCapabilitiesRoute(server, defaultCapabilities, [
|
||||||
|
(req, caps) => {
|
||||||
|
throw new Error(`Couldn't fetch license`);
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const resp = await server.inject({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/api/capabilities',
|
||||||
|
payload: { capabilities: {} },
|
||||||
|
});
|
||||||
|
expect(resp.statusCode).toBe(500);
|
||||||
|
});
|
||||||
|
});
|
55
src/legacy/server/capabilities/capabilities_route.ts
Normal file
55
src/legacy/server/capabilities/capabilities_route.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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 Joi from 'joi';
|
||||||
|
import { Server } from 'hapi';
|
||||||
|
|
||||||
|
import { CapabilitiesModifier } from '.';
|
||||||
|
import { Capabilities } from '../../../core/public';
|
||||||
|
import { mergeCapabilities } from './merge_capabilities';
|
||||||
|
|
||||||
|
export const registerCapabilitiesRoute = (
|
||||||
|
server: Server,
|
||||||
|
defaultCapabilities: Capabilities,
|
||||||
|
modifiers: CapabilitiesModifier[]
|
||||||
|
) => {
|
||||||
|
server.route({
|
||||||
|
path: '/api/capabilities',
|
||||||
|
method: 'POST',
|
||||||
|
options: {
|
||||||
|
validate: {
|
||||||
|
payload: Joi.object({
|
||||||
|
capabilities: Joi.object().required(),
|
||||||
|
}).required(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async handler(request) {
|
||||||
|
let { capabilities } = request.payload as { capabilities: Capabilities };
|
||||||
|
capabilities = mergeCapabilities({ ...defaultCapabilities }, capabilities);
|
||||||
|
|
||||||
|
for (const provider of modifiers) {
|
||||||
|
capabilities = await provider(request, capabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
capabilities,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
20
src/legacy/server/capabilities/index.ts
Normal file
20
src/legacy/server/capabilities/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 { CapabilitiesModifier, capabilitiesMixin } from './capabilities_mixin';
|
39
src/legacy/server/capabilities/merge_capabilities.ts
Normal file
39
src/legacy/server/capabilities/merge_capabilities.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 { Capabilities } from '../../../core/public';
|
||||||
|
|
||||||
|
export const mergeCapabilities = (...sources: Capabilities[]): Capabilities =>
|
||||||
|
sources.reduce(
|
||||||
|
(capabilities, source) => {
|
||||||
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
|
capabilities[key] = {
|
||||||
|
...value,
|
||||||
|
...capabilities[key],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return capabilities;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
navLinks: {},
|
||||||
|
management: {},
|
||||||
|
catalogue: {},
|
||||||
|
} as Capabilities
|
||||||
|
);
|
8
src/legacy/server/kbn_server.d.ts
vendored
8
src/legacy/server/kbn_server.d.ts
vendored
|
@ -30,6 +30,7 @@ import {
|
||||||
import { ApmOssPlugin } from '../core_plugins/apm_oss';
|
import { ApmOssPlugin } from '../core_plugins/apm_oss';
|
||||||
import { CallClusterWithRequest, ElasticsearchPlugin } from '../core_plugins/elasticsearch';
|
import { CallClusterWithRequest, ElasticsearchPlugin } from '../core_plugins/elasticsearch';
|
||||||
|
|
||||||
|
import { CapabilitiesModifier } from './capabilities';
|
||||||
import { IndexPatternsServiceFactory } from './index_patterns';
|
import { IndexPatternsServiceFactory } from './index_patterns';
|
||||||
import {
|
import {
|
||||||
SavedObjectsClient,
|
SavedObjectsClient,
|
||||||
|
@ -61,8 +62,13 @@ declare module 'hapi' {
|
||||||
config: () => KibanaConfig;
|
config: () => KibanaConfig;
|
||||||
indexPatternsServiceFactory: IndexPatternsServiceFactory;
|
indexPatternsServiceFactory: IndexPatternsServiceFactory;
|
||||||
savedObjects: SavedObjectsService;
|
savedObjects: SavedObjectsService;
|
||||||
|
usage: { collectorSet: any };
|
||||||
injectUiAppVars: (pluginName: string, getAppVars: () => { [key: string]: any }) => void;
|
injectUiAppVars: (pluginName: string, getAppVars: () => { [key: string]: any }) => void;
|
||||||
getHiddenUiAppById(appId: string): UiApp;
|
getHiddenUiAppById(appId: string): UiApp;
|
||||||
|
registerCapabilitiesModifier: (provider: CapabilitiesModifier) => void;
|
||||||
|
addScopedTutorialContextFactory: (
|
||||||
|
scopedTutorialContextFactory: (...args: any[]) => any
|
||||||
|
) => void;
|
||||||
savedObjectsManagement(): SavedObjectsManagement;
|
savedObjectsManagement(): SavedObjectsManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +109,7 @@ export default class KbnServer {
|
||||||
};
|
};
|
||||||
public server: Server;
|
public server: Server;
|
||||||
public inject: Server['inject'];
|
public inject: Server['inject'];
|
||||||
|
public pluginSpecs: any[];
|
||||||
|
|
||||||
constructor(settings: any, core: any);
|
constructor(settings: any, core: any);
|
||||||
|
|
||||||
|
@ -110,6 +117,7 @@ export default class KbnServer {
|
||||||
public mixin(...fns: KbnMixinFunc[]): Promise<void>;
|
public mixin(...fns: KbnMixinFunc[]): Promise<void>;
|
||||||
public listen(): Promise<Server>;
|
public listen(): Promise<Server>;
|
||||||
public close(): Promise<void>;
|
public close(): Promise<void>;
|
||||||
|
public afterPluginsInit(callback: () => void): void;
|
||||||
public applyLoggingConfiguration(settings: any): void;
|
public applyLoggingConfiguration(settings: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import * as Plugins from './plugins';
|
||||||
import { indexPatternsMixin } from './index_patterns';
|
import { indexPatternsMixin } from './index_patterns';
|
||||||
import { savedObjectsMixin } from './saved_objects';
|
import { savedObjectsMixin } from './saved_objects';
|
||||||
import { sampleDataMixin } from './sample_data';
|
import { sampleDataMixin } from './sample_data';
|
||||||
|
import { capabilitiesMixin } from './capabilities';
|
||||||
import { urlShorteningMixin } from './url_shortening';
|
import { urlShorteningMixin } from './url_shortening';
|
||||||
import { serverExtensionsMixin } from './server_extensions';
|
import { serverExtensionsMixin } from './server_extensions';
|
||||||
import { uiMixin } from '../ui';
|
import { uiMixin } from '../ui';
|
||||||
|
@ -114,6 +115,9 @@ export default class KbnServer {
|
||||||
// setup saved object routes
|
// setup saved object routes
|
||||||
savedObjectsMixin,
|
savedObjectsMixin,
|
||||||
|
|
||||||
|
// setup capabilities routes
|
||||||
|
capabilitiesMixin,
|
||||||
|
|
||||||
// setup routes for installing/uninstalling sample data sets
|
// setup routes for installing/uninstalling sample data sets
|
||||||
sampleDataMixin,
|
sampleDataMixin,
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,17 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Capabilities as UICapabilities, CapabilitiesStart } from '../../../../core/public';
|
import { Capabilities as UICapabilities } from '../../../../core/public';
|
||||||
|
|
||||||
export { UICapabilities };
|
export { UICapabilities };
|
||||||
|
let uiCapabilities: UICapabilities;
|
||||||
|
|
||||||
let uiCapabilities: UICapabilities = null!;
|
export function __newPlatformStart__(capabilities: UICapabilities) {
|
||||||
|
|
||||||
export function __newPlatformStart__(capabililitiesService: CapabilitiesStart) {
|
|
||||||
if (uiCapabilities) {
|
if (uiCapabilities) {
|
||||||
throw new Error('ui/capabilities already initialized with new platform apis');
|
throw new Error('ui/capabilities already initialized with new platform apis');
|
||||||
}
|
}
|
||||||
|
|
||||||
uiCapabilities = capabililitiesService.getCapabilities();
|
uiCapabilities = capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const capabilities = {
|
export const capabilities = {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import { CoreSetup } from 'kibana/public';
|
import { CoreSetup } from 'kibana/public';
|
||||||
|
|
||||||
import { fatalError } from 'ui/notify';
|
import { fatalError } from 'ui/notify';
|
||||||
|
import { capabilities } from 'ui/capabilities';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { modifyUrl } from 'ui/url';
|
import { modifyUrl } from 'ui/url';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -65,6 +66,7 @@ export const configureAppAngularModule = (angularModule: IModule) => {
|
||||||
.value('serverName', legacyMetadata.serverName)
|
.value('serverName', legacyMetadata.serverName)
|
||||||
.value('sessionId', Date.now())
|
.value('sessionId', Date.now())
|
||||||
.value('esUrl', getEsUrl(newPlatform))
|
.value('esUrl', getEsUrl(newPlatform))
|
||||||
|
.value('uiCapabilities', capabilities.get())
|
||||||
.config(setupCompileProvider(newPlatform))
|
.config(setupCompileProvider(newPlatform))
|
||||||
.config(setupLocationProvider(newPlatform))
|
.config(setupLocationProvider(newPlatform))
|
||||||
.config($setupXsrfRequestInterceptor(newPlatform))
|
.config($setupXsrfRequestInterceptor(newPlatform))
|
||||||
|
|
|
@ -39,19 +39,6 @@ export function uiRenderMixin(kbnServer, server, config) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInitialDefaultInjectedVars() {
|
|
||||||
const navLinkSpecs = server.getUiNavLinks();
|
|
||||||
|
|
||||||
return {
|
|
||||||
uiCapabilities: {
|
|
||||||
navLinks: navLinkSpecs.reduce((acc, navLinkSpec) => ({
|
|
||||||
...acc,
|
|
||||||
[navLinkSpec._id]: true
|
|
||||||
}), {})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultInjectedVars = {};
|
let defaultInjectedVars = {};
|
||||||
kbnServer.afterPluginsInit(() => {
|
kbnServer.afterPluginsInit(() => {
|
||||||
const { defaultInjectedVarProviders = [] } = kbnServer.uiExports;
|
const { defaultInjectedVarProviders = [] } = kbnServer.uiExports;
|
||||||
|
@ -61,7 +48,7 @@ export function uiRenderMixin(kbnServer, server, config) {
|
||||||
allDefaults,
|
allDefaults,
|
||||||
fn(kbnServer.server, pluginSpec.readConfigValue(kbnServer.config, []))
|
fn(kbnServer.server, pluginSpec.readConfigValue(kbnServer.config, []))
|
||||||
)
|
)
|
||||||
), getInitialDefaultInjectedVars());
|
), {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// render all views from ./views
|
// render all views from ./views
|
||||||
|
|
|
@ -109,28 +109,6 @@ export const security = (kibana) => new kibana.Plugin({
|
||||||
sessionTimeout: config.get('xpack.security.sessionTimeout'),
|
sessionTimeout: config.get('xpack.security.sessionTimeout'),
|
||||||
enableSpaceAwarePrivileges: config.get('xpack.spaces.enabled'),
|
enableSpaceAwarePrivileges: config.get('xpack.spaces.enabled'),
|
||||||
};
|
};
|
||||||
},
|
|
||||||
replaceInjectedVars: async function (originalInjectedVars, request, server) {
|
|
||||||
// if we have a license which doesn't enable security, or we're a legacy user
|
|
||||||
// we shouldn't disable any ui capabilities
|
|
||||||
const { authorization } = server.plugins.security;
|
|
||||||
if (!authorization.mode.useRbacForRequest(request)) {
|
|
||||||
return originalInjectedVars;
|
|
||||||
}
|
|
||||||
|
|
||||||
const disableUICapabilites = disableUICapabilitesFactory(server, request);
|
|
||||||
// if we're an anonymous route, we disable all ui capabilities
|
|
||||||
if (request.route.settings.auth === false) {
|
|
||||||
return {
|
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: disableUICapabilites.all(originalInjectedVars.uiCapabilities)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: await disableUICapabilites.usingPrivileges(originalInjectedVars.uiCapabilities)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -242,5 +220,22 @@ export const security = (kibana) => new kibana.Plugin({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.registerCapabilitiesModifier((request, uiCapabilities) => {
|
||||||
|
// if we have a license which doesn't enable security, or we're a legacy user
|
||||||
|
// we shouldn't disable any ui capabilities
|
||||||
|
const { authorization } = server.plugins.security;
|
||||||
|
if (!authorization.mode.useRbacForRequest(request)) {
|
||||||
|
return uiCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disableUICapabilites = disableUICapabilitesFactory(server, request);
|
||||||
|
// if we're an anonymous route, we disable all ui capabilities
|
||||||
|
if (request.route.settings.auth === false) {
|
||||||
|
return disableUICapabilites.all(uiCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
return disableUICapabilites.usingPrivileges(uiCapabilities);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,7 +51,7 @@ export function disableUICapabilitesFactory(
|
||||||
|
|
||||||
throw new Error(`Expected value type of boolean or object, but found ${value}`);
|
throw new Error(`Expected value type of boolean or object, but found ${value}`);
|
||||||
})
|
})
|
||||||
);
|
) as UICapabilities;
|
||||||
};
|
};
|
||||||
|
|
||||||
const usingPrivileges = async (uiCapabilities: UICapabilities) => {
|
const usingPrivileges = async (uiCapabilities: UICapabilities) => {
|
||||||
|
@ -143,7 +143,7 @@ export function disableUICapabilitesFactory(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
}) as UICapabilities;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
import JoiNamespace from 'joi';
|
import JoiNamespace from 'joi';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
import { Server } from 'hapi';
|
||||||
|
|
||||||
import { getConfigSchema, initServerWithKibana, KbnServer } from './server/kibana.index';
|
import { getConfigSchema, initServerWithKibana } from './server/kibana.index';
|
||||||
|
|
||||||
const APP_ID = 'siem';
|
const APP_ID = 'siem';
|
||||||
export const APP_NAME = 'SIEM';
|
export const APP_NAME = 'SIEM';
|
||||||
|
@ -43,7 +44,7 @@ export function siem(kibana: any) {
|
||||||
config(Joi: typeof JoiNamespace) {
|
config(Joi: typeof JoiNamespace) {
|
||||||
return getConfigSchema(Joi);
|
return getConfigSchema(Joi);
|
||||||
},
|
},
|
||||||
init(server: KbnServer) {
|
init(server: Server) {
|
||||||
initServerWithKibana(server);
|
initServerWithKibana(server);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,13 +14,9 @@ import { createLogger } from './utils/logger';
|
||||||
|
|
||||||
const APP_ID = 'siem';
|
const APP_ID = 'siem';
|
||||||
|
|
||||||
export interface KbnServer extends Server {
|
|
||||||
usage: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const amMocking = (): boolean => process.env.INGEST_MOCKS === 'true';
|
export const amMocking = (): boolean => process.env.INGEST_MOCKS === 'true';
|
||||||
|
|
||||||
export const initServerWithKibana = (kbnServer: KbnServer) => {
|
export const initServerWithKibana = (kbnServer: Server) => {
|
||||||
// bind is so "this" binds correctly to the logger since hapi server does not auto-bind its methods
|
// bind is so "this" binds correctly to the logger since hapi server does not auto-bind its methods
|
||||||
const logger = createLogger(kbnServer.log.bind(kbnServer));
|
const logger = createLogger(kbnServer.log.bind(kbnServer));
|
||||||
logger.info('Plugin initializing');
|
logger.info('Plugin initializing');
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
|
||||||
import { SavedObjectsService } from 'src/legacy/server/saved_objects';
|
import { SavedObjectsService } from 'src/legacy/server/saved_objects';
|
||||||
|
import { Request, Server } from 'hapi';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { AuditLogger } from '../../server/lib/audit_logger';
|
import { AuditLogger } from '../../server/lib/audit_logger';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -43,6 +44,14 @@ export const spaces = (kibana: Record<string, any>) =>
|
||||||
}).default();
|
}).default();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uiCapabilities() {
|
||||||
|
return {
|
||||||
|
spaces: {
|
||||||
|
manage: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
uiExports: {
|
uiExports: {
|
||||||
chromeNavControls: ['plugins/spaces/views/nav_control'],
|
chromeNavControls: ['plugins/spaces/views/nav_control'],
|
||||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||||
|
@ -74,11 +83,6 @@ export const spaces = (kibana: Record<string, any>) =>
|
||||||
spaces: [],
|
spaces: [],
|
||||||
activeSpace: null,
|
activeSpace: null,
|
||||||
spaceSelectorURL: getSpaceSelectorUrl(server.config()),
|
spaceSelectorURL: getSpaceSelectorUrl(server.config()),
|
||||||
uiCapabilities: {
|
|
||||||
spaces: {
|
|
||||||
manage: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async replaceInjectedVars(
|
async replaceInjectedVars(
|
||||||
|
@ -103,20 +107,11 @@ export const spaces = (kibana: Record<string, any>) =>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vars.activeSpace.space) {
|
|
||||||
const features = server.plugins.xpack_main.getFeatures();
|
|
||||||
vars.uiCapabilities = toggleUICapabilities(
|
|
||||||
features,
|
|
||||||
vars.uiCapabilities,
|
|
||||||
vars.activeSpace.space
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vars;
|
return vars;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async init(server: any) {
|
async init(server: Server) {
|
||||||
const thisPlugin = this;
|
const thisPlugin = this;
|
||||||
const xpackMainPlugin = server.plugins.xpack_main;
|
const xpackMainPlugin = server.plugins.xpack_main;
|
||||||
|
|
||||||
|
@ -140,10 +135,10 @@ export const spaces = (kibana: Record<string, any>) =>
|
||||||
);
|
);
|
||||||
|
|
||||||
server.expose('spacesClient', {
|
server.expose('spacesClient', {
|
||||||
getScopedClient: (request: Record<string, any>) => {
|
getScopedClient: (request: Request) => {
|
||||||
const adminCluster = server.plugins.elasticsearch.getCluster('admin');
|
const adminCluster = server.plugins.elasticsearch.getCluster('admin');
|
||||||
const { callWithRequest, callWithInternalUser } = adminCluster;
|
const { callWithRequest, callWithInternalUser } = adminCluster;
|
||||||
const callCluster = (...args: any[]) => callWithRequest(request, ...args);
|
const callCluster = callWithRequest.bind(adminCluster, request);
|
||||||
const { savedObjects } = server;
|
const { savedObjects } = server;
|
||||||
const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser);
|
const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser);
|
||||||
const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster);
|
const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster);
|
||||||
|
@ -182,5 +177,21 @@ export const spaces = (kibana: Record<string, any>) =>
|
||||||
|
|
||||||
// Register a function with server to manage the collection of usage stats
|
// Register a function with server to manage the collection of usage stats
|
||||||
server.usage.collectorSet.register(getSpacesUsageCollector(server));
|
server.usage.collectorSet.register(getSpacesUsageCollector(server));
|
||||||
|
|
||||||
|
server.registerCapabilitiesModifier(async (request, uiCapabilities) => {
|
||||||
|
const spacesClient = server.plugins.spaces.spacesClient.getScopedClient(request);
|
||||||
|
try {
|
||||||
|
const activeSpace = await getActiveSpace(
|
||||||
|
spacesClient,
|
||||||
|
request.getBasePath(),
|
||||||
|
server.config().get('server.basePath')
|
||||||
|
);
|
||||||
|
|
||||||
|
const features = server.plugins.xpack_main.getFeatures();
|
||||||
|
return toggleUICapabilities(features, uiCapabilities, activeSpace);
|
||||||
|
} catch (e) {
|
||||||
|
return uiCapabilities;
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
|
||||||
import { replaceInjectedVars } from './server/lib/replace_injected_vars';
|
import { replaceInjectedVars } from './server/lib/replace_injected_vars';
|
||||||
import { setupXPackMain } from './server/lib/setup_xpack_main';
|
import { setupXPackMain } from './server/lib/setup_xpack_main';
|
||||||
import { getLocalizationUsageCollector } from './server/lib/get_localization_usage_collector';
|
import { getLocalizationUsageCollector } from './server/lib/get_localization_usage_collector';
|
||||||
|
import { uiCapabilitiesForFeatures } from './server/lib/ui_capabilities_for_features';
|
||||||
import {
|
import {
|
||||||
xpackInfoRoute,
|
xpackInfoRoute,
|
||||||
telemetryRoute,
|
telemetryRoute,
|
||||||
|
@ -61,6 +62,10 @@ export const xpackMain = (kibana) => {
|
||||||
}).default();
|
}).default();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uiCapabilities(server) {
|
||||||
|
return uiCapabilitiesForFeatures(server.plugins.xpack_main);
|
||||||
|
},
|
||||||
|
|
||||||
uiExports: {
|
uiExports: {
|
||||||
managementSections: ['plugins/xpack_main/views/management'],
|
managementSections: ['plugins/xpack_main/views/management'],
|
||||||
uiSettingDefaults: {
|
uiSettingDefaults: {
|
||||||
|
@ -92,6 +97,7 @@ export const xpackMain = (kibana) => {
|
||||||
},
|
},
|
||||||
injectDefaultVars(server) {
|
injectDefaultVars(server) {
|
||||||
const config = server.config();
|
const config = server.config();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
telemetryUrl: config.get('xpack.xpack_main.telemetry.url'),
|
telemetryUrl: config.get('xpack.xpack_main.telemetry.url'),
|
||||||
telemetryEnabled: isTelemetryEnabled(config),
|
telemetryEnabled: isTelemetryEnabled(config),
|
||||||
|
|
|
@ -47,12 +47,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sinon.assert.calledOnce(server.plugins.security.isAuthenticated);
|
sinon.assert.calledOnce(server.plugins.security.isAuthenticated);
|
||||||
|
@ -72,12 +66,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,12 +82,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,12 +98,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -138,12 +114,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,49 +130,27 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
xpackInitialInfo: {
|
xpackInitialInfo: {
|
||||||
b: 1
|
b: 1
|
||||||
},
|
},
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends the originalInjectedVars augmented with UI Capabilities if not authenticated', async () => {
|
it('sends the originalInjectedVars if not authenticated', async () => {
|
||||||
const originalInjectedVars = { a: 1 };
|
const originalInjectedVars = { a: 1 };
|
||||||
const request = buildRequest();
|
const request = buildRequest();
|
||||||
const server = mockServer();
|
const server = mockServer();
|
||||||
server.plugins.security.isAuthenticated.returns(false);
|
server.plugins.security.isAuthenticated.returns(false);
|
||||||
|
|
||||||
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
||||||
expect(newVars).to.eql({
|
expect(newVars).to.eql(originalInjectedVars);
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends the originalInjectedVars augmented with UI Capabilities if xpack info is unavailable', async () => {
|
it('sends the originalInjectedVars if xpack info is unavailable', async () => {
|
||||||
const originalInjectedVars = { a: 1 };
|
const originalInjectedVars = { a: 1 };
|
||||||
const request = buildRequest();
|
const request = buildRequest();
|
||||||
const server = mockServer();
|
const server = mockServer();
|
||||||
server.plugins.xpack_main.info.isAvailable.returns(false);
|
server.plugins.xpack_main.info.isAvailable.returns(false);
|
||||||
|
|
||||||
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
||||||
expect(newVars).to.eql({
|
expect(newVars).to.eql(originalInjectedVars);
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends the originalInjectedVars (with xpackInitialInfo = undefined) if security is disabled, xpack info is unavailable', async () => {
|
it('sends the originalInjectedVars (with xpackInitialInfo = undefined) if security is disabled, xpack info is unavailable', async () => {
|
||||||
|
@ -220,9 +168,6 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
uiCapabilities: {
|
uiCapabilities: {
|
||||||
navLinks: { foo: true },
|
navLinks: { foo: true },
|
||||||
bar: { baz: true },
|
bar: { baz: true },
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {
|
catalogue: {
|
||||||
cfoo: true,
|
cfoo: true,
|
||||||
}
|
}
|
||||||
|
@ -230,22 +175,14 @@ describe('replaceInjectedVars uiExport', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends the originalInjectedVars augmented with UI Capabilities if the license check result is not available', async () => {
|
it('sends the originalInjectedVars if the license check result is not available', async () => {
|
||||||
const originalInjectedVars = { a: 1 };
|
const originalInjectedVars = { a: 1 };
|
||||||
const request = buildRequest();
|
const request = buildRequest();
|
||||||
const server = mockServer();
|
const server = mockServer();
|
||||||
server.plugins.xpack_main.info.feature().getLicenseCheckResults.returns(undefined);
|
server.plugins.xpack_main.info.feature().getLicenseCheckResults.returns(undefined);
|
||||||
|
|
||||||
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
const newVars = await replaceInjectedVars(originalInjectedVars, request, server);
|
||||||
expect(newVars).to.eql({
|
expect(newVars).to.eql(originalInjectedVars);
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: {
|
|
||||||
mockFeature: {
|
|
||||||
mockFeatureCapability: true,
|
|
||||||
},
|
|
||||||
catalogue: {}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -5,20 +5,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getTelemetryOptIn } from './get_telemetry_opt_in';
|
import { getTelemetryOptIn } from './get_telemetry_opt_in';
|
||||||
import { populateUICapabilities } from './populate_ui_capabilities';
|
|
||||||
|
|
||||||
export async function replaceInjectedVars(originalInjectedVars, request, server) {
|
export async function replaceInjectedVars(originalInjectedVars, request, server) {
|
||||||
const xpackInfo = server.plugins.xpack_main.info;
|
const xpackInfo = server.plugins.xpack_main.info;
|
||||||
|
|
||||||
const originalInjectedVarsWithUICapabilities = {
|
|
||||||
...originalInjectedVars,
|
|
||||||
uiCapabilities: {
|
|
||||||
...populateUICapabilities(server.plugins.xpack_main, originalInjectedVars.uiCapabilities),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const withXpackInfo = async () => ({
|
const withXpackInfo = async () => ({
|
||||||
...originalInjectedVarsWithUICapabilities,
|
...originalInjectedVars,
|
||||||
telemetryOptedIn: await getTelemetryOptIn(request),
|
telemetryOptedIn: await getTelemetryOptIn(request),
|
||||||
xpackInitialInfo: xpackInfo.isAvailable() ? xpackInfo.toJSON() : undefined,
|
xpackInitialInfo: xpackInfo.isAvailable() ? xpackInfo.toJSON() : undefined,
|
||||||
});
|
});
|
||||||
|
@ -30,12 +22,12 @@ export async function replaceInjectedVars(originalInjectedVars, request, server)
|
||||||
|
|
||||||
// not enough license info to make decision one way or another
|
// not enough license info to make decision one way or another
|
||||||
if (!xpackInfo.isAvailable() || !xpackInfo.feature('security').getLicenseCheckResults()) {
|
if (!xpackInfo.isAvailable() || !xpackInfo.feature('security').getLicenseCheckResults()) {
|
||||||
return originalInjectedVarsWithUICapabilities;
|
return originalInjectedVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
// request is not authenticated
|
// request is not authenticated
|
||||||
if (!await server.plugins.security.isAuthenticated(request)) {
|
if (!await server.plugins.security.isAuthenticated(request)) {
|
||||||
return originalInjectedVarsWithUICapabilities;
|
return originalInjectedVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
// plugin enabled, license is appropriate, request is authenticated
|
// plugin enabled, license is appropriate, request is authenticated
|
||||||
|
|
|
@ -4,9 +4,8 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { UICapabilities } from 'ui/capabilities';
|
|
||||||
import { Feature } from './feature_registry';
|
import { Feature } from './feature_registry';
|
||||||
import { populateUICapabilities } from './populate_ui_capabilities';
|
import { uiCapabilitiesForFeatures } from './ui_capabilities_for_features';
|
||||||
|
|
||||||
function getMockXpackMainPlugin(features: Feature[]) {
|
function getMockXpackMainPlugin(features: Feature[]) {
|
||||||
return {
|
return {
|
||||||
|
@ -14,26 +13,6 @@ function getMockXpackMainPlugin(features: Feature[]) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMockOriginalInjectedVars() {
|
|
||||||
return {
|
|
||||||
uiCapabilities: {
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
feature: {
|
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
otherFeature: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFeaturePrivilege(key: string, capabilities: string[] = []) {
|
function createFeaturePrivilege(key: string, capabilities: string[] = []) {
|
||||||
return {
|
return {
|
||||||
[key]: {
|
[key]: {
|
||||||
|
@ -51,28 +30,7 @@ describe('populateUICapabilities', () => {
|
||||||
it('handles no original uiCapabilites and no registered features gracefully', () => {
|
it('handles no original uiCapabilites and no registered features gracefully', () => {
|
||||||
const xpackMainPlugin = getMockXpackMainPlugin([]);
|
const xpackMainPlugin = getMockXpackMainPlugin([]);
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, {} as UICapabilities)).toEqual({});
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({});
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the original uiCapabilities untouched when no features are registered', () => {
|
|
||||||
const xpackMainPlugin = getMockXpackMainPlugin([]);
|
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
|
||||||
feature: {
|
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
otherFeature: {},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles features with no registered capabilities', () => {
|
it('handles features with no registered capabilities', () => {
|
||||||
|
@ -86,23 +44,10 @@ describe('populateUICapabilities', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({
|
||||||
feature: {
|
catalogue: {},
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
newFeature: {},
|
newFeature: {},
|
||||||
otherFeature: {},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -118,26 +63,13 @@ describe('populateUICapabilities', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({
|
||||||
feature: {
|
catalogue: {},
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
newFeature: {
|
newFeature: {
|
||||||
capability1: true,
|
capability1: true,
|
||||||
capability2: true,
|
capability2: true,
|
||||||
},
|
},
|
||||||
otherFeature: {},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -156,21 +88,10 @@ describe('populateUICapabilities', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({
|
||||||
feature: {
|
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
catalogue: {
|
||||||
fooEntry: true,
|
|
||||||
anotherFooEntry: true,
|
anotherFooEntry: true,
|
||||||
barEntry: true,
|
|
||||||
anotherBarEntry: true,
|
anotherBarEntry: true,
|
||||||
},
|
},
|
||||||
newFeature: {
|
newFeature: {
|
||||||
|
@ -179,7 +100,6 @@ describe('populateUICapabilities', () => {
|
||||||
capability3: true,
|
capability3: true,
|
||||||
capability4: true,
|
capability4: true,
|
||||||
},
|
},
|
||||||
otherFeature: {},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -197,21 +117,9 @@ describe('populateUICapabilities', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({
|
||||||
feature: {
|
catalogue: {},
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
newFeature: {
|
newFeature: {
|
||||||
capability1: true,
|
capability1: true,
|
||||||
capability2: true,
|
capability2: true,
|
||||||
|
@ -219,7 +127,6 @@ describe('populateUICapabilities', () => {
|
||||||
capability4: true,
|
capability4: true,
|
||||||
capability5: true,
|
capability5: true,
|
||||||
},
|
},
|
||||||
otherFeature: {},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -261,27 +168,15 @@ describe('populateUICapabilities', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const originalInjectedVars = getMockOriginalInjectedVars();
|
|
||||||
|
|
||||||
expect(populateUICapabilities(xpackMainPlugin, originalInjectedVars.uiCapabilities)).toEqual({
|
expect(uiCapabilitiesForFeatures(xpackMainPlugin)).toEqual({
|
||||||
anotherNewFeature: {
|
anotherNewFeature: {
|
||||||
capability1: true,
|
capability1: true,
|
||||||
capability2: true,
|
capability2: true,
|
||||||
capability3: true,
|
capability3: true,
|
||||||
capability4: true,
|
capability4: true,
|
||||||
},
|
},
|
||||||
feature: {
|
catalogue: {},
|
||||||
someCapability: true,
|
|
||||||
},
|
|
||||||
navLinks: {
|
|
||||||
foo: true,
|
|
||||||
bar: true,
|
|
||||||
},
|
|
||||||
management: {},
|
|
||||||
catalogue: {
|
|
||||||
fooEntry: true,
|
|
||||||
barEntry: true,
|
|
||||||
},
|
|
||||||
newFeature: {
|
newFeature: {
|
||||||
capability1: true,
|
capability1: true,
|
||||||
capability2: true,
|
capability2: true,
|
||||||
|
@ -289,7 +184,6 @@ describe('populateUICapabilities', () => {
|
||||||
capability4: true,
|
capability4: true,
|
||||||
capability5: true,
|
capability5: true,
|
||||||
},
|
},
|
||||||
otherFeature: {},
|
|
||||||
yetAnotherNewFeature: {
|
yetAnotherNewFeature: {
|
||||||
capability1: true,
|
capability1: true,
|
||||||
capability2: true,
|
capability2: true,
|
|
@ -14,15 +14,12 @@ interface FeatureCapabilities {
|
||||||
[featureId: string]: Record<string, boolean>;
|
[featureId: string]: Record<string, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function populateUICapabilities(
|
export function uiCapabilitiesForFeatures(xpackMainPlugin: Record<string, any>): UICapabilities {
|
||||||
xpackMainPlugin: Record<string, any>,
|
|
||||||
uiCapabilities: UICapabilities
|
|
||||||
): UICapabilities {
|
|
||||||
const features: Feature[] = xpackMainPlugin.getFeatures();
|
const features: Feature[] = xpackMainPlugin.getFeatures();
|
||||||
|
|
||||||
const featureCapabilities: FeatureCapabilities[] = features.map(getCapabilitiesFromFeature);
|
const featureCapabilities: FeatureCapabilities[] = features.map(getCapabilitiesFromFeature);
|
||||||
|
|
||||||
return mergeCapabilities(uiCapabilities || {}, ...featureCapabilities);
|
return buildCapabilities(...featureCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCapabilitiesFromFeature(feature: Feature): FeatureCapabilities {
|
function getCapabilitiesFromFeature(feature: Feature): FeatureCapabilities {
|
||||||
|
@ -60,25 +57,28 @@ function getCapabilitiesFromFeature(feature: Feature): FeatureCapabilities {
|
||||||
return UIFeatureCapabilities;
|
return UIFeatureCapabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeCapabilities(
|
function buildCapabilities(...allFeatureCapabilities: FeatureCapabilities[]): UICapabilities {
|
||||||
originalCapabilities: UICapabilities,
|
return allFeatureCapabilities.reduce<UICapabilities>(
|
||||||
...allFeatureCapabilities: FeatureCapabilities[]
|
(acc, capabilities) => {
|
||||||
): UICapabilities {
|
const mergableCapabilities: UICapabilities = _.omit(
|
||||||
return allFeatureCapabilities.reduce<UICapabilities>((acc, capabilities) => {
|
capabilities,
|
||||||
const mergableCapabilities: UICapabilities = _.omit(capabilities, ...ELIGIBLE_FLAT_MERGE_KEYS);
|
...ELIGIBLE_FLAT_MERGE_KEYS
|
||||||
|
);
|
||||||
|
|
||||||
const mergedFeatureCapabilities = {
|
const mergedFeatureCapabilities = {
|
||||||
...mergableCapabilities,
|
...mergableCapabilities,
|
||||||
...acc,
|
...acc,
|
||||||
};
|
|
||||||
|
|
||||||
ELIGIBLE_FLAT_MERGE_KEYS.forEach(key => {
|
|
||||||
mergedFeatureCapabilities[key] = {
|
|
||||||
...mergedFeatureCapabilities[key],
|
|
||||||
...capabilities[key],
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
|
||||||
return mergedFeatureCapabilities;
|
ELIGIBLE_FLAT_MERGE_KEYS.forEach(key => {
|
||||||
}, originalCapabilities);
|
mergedFeatureCapabilities[key] = {
|
||||||
|
...mergedFeatureCapabilities[key],
|
||||||
|
...capabilities[key],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return mergedFeatureCapabilities;
|
||||||
|
},
|
||||||
|
{} as UICapabilities
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -50,6 +50,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
||||||
...xPackFunctionalTestsConfig.get('kbnTestServer.serverArgs'),
|
...xPackFunctionalTestsConfig.get('kbnTestServer.serverArgs'),
|
||||||
...disabledPlugins.map(key => `--xpack.${key}.enabled=false`),
|
...disabledPlugins.map(key => `--xpack.${key}.enabled=false`),
|
||||||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'foo_plugin')}`,
|
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'foo_plugin')}`,
|
||||||
|
'--optimize.enabled=false',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface NestedBooleanObject {
|
||||||
|
[key: string]: boolean | NestedBooleanObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const assertDeeplyFalse = (obj: NestedBooleanObject, path: string[] = []) => {
|
||||||
|
Object.keys(obj).forEach(key => {
|
||||||
|
const value = obj[key];
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
assertDeeplyFalse(value, [...path, key]);
|
||||||
|
} else if (typeof value === 'boolean') {
|
||||||
|
if (value) {
|
||||||
|
throw new Error(`${[...path, key].join('.')} is not false: ${value}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`Expected nest object with boolean keys. '${key}' is not boolean: ${value}.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
|
@ -4,7 +4,6 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
import axios, { AxiosInstance } from 'axios';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
import cheerio from 'cheerio';
|
|
||||||
import { UICapabilities } from 'ui/capabilities';
|
import { UICapabilities } from 'ui/capabilities';
|
||||||
import { format as formatUrl } from 'url';
|
import { format as formatUrl } from 'url';
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
|
@ -41,22 +40,23 @@ export class UICapabilitiesService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get(
|
public async get({
|
||||||
credentials: BasicCredentials | null,
|
credentials,
|
||||||
spaceId?: string
|
navLinks,
|
||||||
): Promise<GetUICapabilitiesResult> {
|
spaceId,
|
||||||
|
}: {
|
||||||
|
credentials?: BasicCredentials;
|
||||||
|
navLinks?: Record<string, boolean>;
|
||||||
|
spaceId?: string;
|
||||||
|
}): Promise<GetUICapabilitiesResult> {
|
||||||
const spaceUrlPrefix = spaceId ? `/s/${spaceId}` : '';
|
const spaceUrlPrefix = spaceId ? `/s/${spaceId}` : '';
|
||||||
this.log.debug(`requesting ${spaceUrlPrefix}/app/kibana to parse the uiCapabilities`);
|
this.log.debug(`requesting ${spaceUrlPrefix}/api/capabilities to get the uiCapabilities`);
|
||||||
const requestHeaders = credentials
|
const requestOptions = credentials ? { auth: credentials } : {};
|
||||||
? {
|
const response = await this.axios.post(
|
||||||
Authorization: `Basic ${Buffer.from(
|
`${spaceUrlPrefix}/api/capabilities`,
|
||||||
`${credentials.username}:${credentials.password}`
|
{ capabilities: { navLinks } },
|
||||||
).toString('base64')}`,
|
requestOptions
|
||||||
}
|
);
|
||||||
: {};
|
|
||||||
const response = await this.axios.get(`${spaceUrlPrefix}/app/kibana`, {
|
|
||||||
headers: requestHeaders,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status === 302 && response.headers.location === '/') {
|
if (response.status === 302 && response.headers.location === '/') {
|
||||||
return {
|
return {
|
||||||
|
@ -65,13 +65,6 @@ export class UICapabilitiesService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.status === 404) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
failureReason: GetUICapabilitiesFailureReason.NotFound,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Expected status code of 200, received ${response.status} ${
|
`Expected status code of 200, received ${response.status} ${
|
||||||
|
@ -80,25 +73,10 @@ export class UICapabilitiesService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dom = cheerio.load(response.data.toString());
|
return {
|
||||||
const element = dom('kbn-injected-metadata');
|
success: true,
|
||||||
if (!element) {
|
value: response.data.capabilities,
|
||||||
throw new Error('Unable to find "kbn-injected-metadata" element ');
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const dataAttrJson = element.attr('data');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dataAttr = JSON.parse(dataAttrJson);
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
value: dataAttr.vars.uiCapabilities as UICapabilities,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(
|
|
||||||
`Unable to parse JSON from the kbn-injected-metadata data attribute: ${dataAttrJson}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,9 @@
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { mapValues } from 'lodash';
|
import { mapValues } from 'lodash';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserAtSpaceScenarios } from '../scenarios';
|
import { UserAtSpaceScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function catalogueTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
export default function catalogueTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
||||||
|
@ -22,14 +20,16 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
it(`${scenario.id}`, async () => {
|
it(`${scenario.id}`, async () => {
|
||||||
const { user, space } = scenario;
|
const { user, space } = scenario;
|
||||||
|
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
{ username: user.username, password: user.password },
|
credentials: { username: user.username, password: user.password },
|
||||||
space.id
|
spaceId: space.id,
|
||||||
);
|
});
|
||||||
|
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('catalogue');
|
||||||
|
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'superuser at everything_space': {
|
case 'superuser at everything_space': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// everything is enabled
|
// everything is enabled
|
||||||
const expected = mapValues(uiCapabilities.value!.catalogue, () => true);
|
const expected = mapValues(uiCapabilities.value!.catalogue, () => true);
|
||||||
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
||||||
|
@ -41,8 +41,6 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
case 'global_read at everything_space':
|
case 'global_read at everything_space':
|
||||||
case 'dual_privileges_read at everything_space':
|
case 'dual_privileges_read at everything_space':
|
||||||
case 'everything_space_read at everything_space': {
|
case 'everything_space_read at everything_space': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// everything except ml and monitoring is enabled
|
// everything except ml and monitoring is enabled
|
||||||
const expected = mapValues(
|
const expected = mapValues(
|
||||||
uiCapabilities.value!.catalogue,
|
uiCapabilities.value!.catalogue,
|
||||||
|
@ -60,16 +58,13 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
case 'dual_privileges_read at nothing_space':
|
case 'dual_privileges_read at nothing_space':
|
||||||
case 'nothing_space_all at nothing_space':
|
case 'nothing_space_all at nothing_space':
|
||||||
case 'nothing_space_read at nothing_space': {
|
case 'nothing_space_read at nothing_space': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// everything is disabled
|
// everything is disabled
|
||||||
const expected = mapValues(uiCapabilities.value!.catalogue, () => false);
|
const expected = mapValues(uiCapabilities.value!.catalogue, () => false);
|
||||||
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// if we don't have access at the space itself, we're
|
// if we don't have access at the space itself, all ui
|
||||||
// redirected to the space selector and the ui capabilities
|
// capabilities should be false
|
||||||
// are lagely irrelevant because they won't be consumed
|
|
||||||
case 'no_kibana_privileges at everything_space':
|
case 'no_kibana_privileges at everything_space':
|
||||||
case 'no_kibana_privileges at nothing_space':
|
case 'no_kibana_privileges at nothing_space':
|
||||||
case 'legacy_all at everything_space':
|
case 'legacy_all at everything_space':
|
||||||
|
@ -78,10 +73,7 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
case 'everything_space_read at nothing_space':
|
case 'everything_space_read at nothing_space':
|
||||||
case 'nothing_space_all at everything_space':
|
case 'nothing_space_all at everything_space':
|
||||||
case 'nothing_space_read at everything_space':
|
case 'nothing_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
assertDeeplyFalse(uiCapabilities.value!.catalogue);
|
||||||
expect(uiCapabilities.failureReason).to.be(
|
|
||||||
GetUICapabilitiesFailureReason.RedirectedToRoot
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -6,11 +6,9 @@
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserAtSpaceScenarios } from '../scenarios';
|
import { UserAtSpaceScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function fooTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
export default function fooTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
||||||
|
@ -21,18 +19,18 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
it(`${scenario.id}`, async () => {
|
it(`${scenario.id}`, async () => {
|
||||||
const { user, space } = scenario;
|
const { user, space } = scenario;
|
||||||
|
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
{ username: user.username, password: user.password },
|
credentials: { username: user.username, password: user.password },
|
||||||
space.id
|
spaceId: space.id,
|
||||||
);
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('foo');
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
// these users have a read/write view
|
// these users have a read/write view
|
||||||
case 'superuser at everything_space':
|
case 'superuser at everything_space':
|
||||||
case 'global_all at everything_space':
|
case 'global_all at everything_space':
|
||||||
case 'dual_privileges_all at everything_space':
|
case 'dual_privileges_all at everything_space':
|
||||||
case 'everything_space_all at everything_space':
|
case 'everything_space_all at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('foo');
|
|
||||||
expect(uiCapabilities.value!.foo).to.eql({
|
expect(uiCapabilities.value!.foo).to.eql({
|
||||||
create: true,
|
create: true,
|
||||||
edit: true,
|
edit: true,
|
||||||
|
@ -44,8 +42,6 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
case 'global_read at everything_space':
|
case 'global_read at everything_space':
|
||||||
case 'dual_privileges_read at everything_space':
|
case 'dual_privileges_read at everything_space':
|
||||||
case 'everything_space_read at everything_space':
|
case 'everything_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('foo');
|
|
||||||
expect(uiCapabilities.value!.foo).to.eql({
|
expect(uiCapabilities.value!.foo).to.eql({
|
||||||
create: false,
|
create: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
|
@ -62,8 +58,6 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
case 'dual_privileges_read at nothing_space':
|
case 'dual_privileges_read at nothing_space':
|
||||||
case 'nothing_space_all at nothing_space':
|
case 'nothing_space_all at nothing_space':
|
||||||
case 'nothing_space_read at nothing_space':
|
case 'nothing_space_read at nothing_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('foo');
|
|
||||||
expect(uiCapabilities.value!.foo).to.eql({
|
expect(uiCapabilities.value!.foo).to.eql({
|
||||||
create: false,
|
create: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
|
@ -71,9 +65,8 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
show: false,
|
show: false,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// if we don't have access at the space itself, we're
|
// if we don't have access at the space itself, all ui
|
||||||
// redirected to the space selector and the ui capabilities
|
// capabilities should be false
|
||||||
// are largely irrelevant because they won't be consumed
|
|
||||||
case 'no_kibana_privileges at everything_space':
|
case 'no_kibana_privileges at everything_space':
|
||||||
case 'no_kibana_privileges at nothing_space':
|
case 'no_kibana_privileges at nothing_space':
|
||||||
case 'legacy_all at everything_space':
|
case 'legacy_all at everything_space':
|
||||||
|
@ -82,10 +75,7 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
case 'everything_space_read at nothing_space':
|
case 'everything_space_read at nothing_space':
|
||||||
case 'nothing_space_all at everything_space':
|
case 'nothing_space_all at everything_space':
|
||||||
case 'nothing_space_read at everything_space':
|
case 'nothing_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
assertDeeplyFalse(uiCapabilities.value!.foo);
|
||||||
expect(uiCapabilities.failureReason).to.be(
|
|
||||||
GetUICapabilitiesFailureReason.RedirectedToRoot
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -8,10 +8,7 @@ import expect from '@kbn/expect';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import { NavLinksBuilder } from '../../common/nav_links_builder';
|
import { NavLinksBuilder } from '../../common/nav_links_builder';
|
||||||
import { FeaturesService } from '../../common/services';
|
import { FeaturesService } from '../../common/services';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserAtSpaceScenarios } from '../scenarios';
|
import { UserAtSpaceScenarios } from '../scenarios';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
@ -30,14 +27,15 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
it(`${scenario.id}`, async () => {
|
it(`${scenario.id}`, async () => {
|
||||||
const { user, space } = scenario;
|
const { user, space } = scenario;
|
||||||
|
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
{ username: user.username, password: user.password },
|
credentials: { username: user.username, password: user.password },
|
||||||
space.id
|
navLinks: navLinksBuilder.all(),
|
||||||
);
|
spaceId: space.id,
|
||||||
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('navLinks');
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'superuser at everything_space':
|
case 'superuser at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.all());
|
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.all());
|
||||||
break;
|
break;
|
||||||
case 'global_all at everything_space':
|
case 'global_all at everything_space':
|
||||||
|
@ -46,8 +44,6 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
case 'global_read at everything_space':
|
case 'global_read at everything_space':
|
||||||
case 'everything_space_all at everything_space':
|
case 'everything_space_all at everything_space':
|
||||||
case 'everything_space_read at everything_space':
|
case 'everything_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(
|
expect(uiCapabilities.value!.navLinks).to.eql(
|
||||||
navLinksBuilder.except('ml', 'monitoring')
|
navLinksBuilder.except('ml', 'monitoring')
|
||||||
);
|
);
|
||||||
|
@ -59,10 +55,10 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
case 'global_read at nothing_space':
|
case 'global_read at nothing_space':
|
||||||
case 'nothing_space_all at nothing_space':
|
case 'nothing_space_all at nothing_space':
|
||||||
case 'nothing_space_read at nothing_space':
|
case 'nothing_space_read at nothing_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.only('management'));
|
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.only('management'));
|
||||||
break;
|
break;
|
||||||
|
// these users have no access to any navLinks except management
|
||||||
|
// which is not a navLink that ever gets disabled.
|
||||||
case 'no_kibana_privileges at everything_space':
|
case 'no_kibana_privileges at everything_space':
|
||||||
case 'no_kibana_privileges at nothing_space':
|
case 'no_kibana_privileges at nothing_space':
|
||||||
case 'legacy_all at everything_space':
|
case 'legacy_all at everything_space':
|
||||||
|
@ -71,10 +67,7 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
case 'everything_space_read at nothing_space':
|
case 'everything_space_read at nothing_space':
|
||||||
case 'nothing_space_all at everything_space':
|
case 'nothing_space_all at everything_space':
|
||||||
case 'nothing_space_read at everything_space':
|
case 'nothing_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.only('management'));
|
||||||
expect(uiCapabilities.failureReason).to.be(
|
|
||||||
GetUICapabilitiesFailureReason.RedirectedToRoot
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -7,11 +7,9 @@ import expect from '@kbn/expect';
|
||||||
import { mapValues } from 'lodash';
|
import { mapValues } from 'lodash';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import { SavedObjectsManagementBuilder } from '../../common/saved_objects_management_builder';
|
import { SavedObjectsManagementBuilder } from '../../common/saved_objects_management_builder';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserAtSpaceScenarios } from '../scenarios';
|
import { UserAtSpaceScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
const savedObjectsManagementBuilder = new SavedObjectsManagementBuilder(true);
|
const savedObjectsManagementBuilder = new SavedObjectsManagementBuilder(true);
|
||||||
|
|
||||||
|
@ -26,15 +24,15 @@ export default function savedObjectsManagementTests({
|
||||||
it(`${scenario.id}`, async () => {
|
it(`${scenario.id}`, async () => {
|
||||||
const { user, space } = scenario;
|
const { user, space } = scenario;
|
||||||
|
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
{ username: user.username, password: user.password },
|
credentials: { username: user.username, password: user.password },
|
||||||
space.id
|
spaceId: space.id,
|
||||||
);
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'superuser at everything_space':
|
case 'superuser at everything_space':
|
||||||
case 'superuser at nothing_space':
|
case 'superuser at nothing_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
||||||
savedObjectsManagementBuilder.uiCapabilities('all')
|
savedObjectsManagementBuilder.uiCapabilities('all')
|
||||||
);
|
);
|
||||||
|
@ -46,8 +44,6 @@ export default function savedObjectsManagementTests({
|
||||||
case 'global_all at nothing_space':
|
case 'global_all at nothing_space':
|
||||||
case 'dual_privileges_all at nothing_space':
|
case 'dual_privileges_all at nothing_space':
|
||||||
case 'nothing_space_all at nothing_space':
|
case 'nothing_space_all at nothing_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
all: [
|
all: [
|
||||||
|
@ -74,8 +70,6 @@ export default function savedObjectsManagementTests({
|
||||||
case 'dual_privileges_read at nothing_space':
|
case 'dual_privileges_read at nothing_space':
|
||||||
case 'global_read at nothing_space':
|
case 'global_read at nothing_space':
|
||||||
case 'nothing_space_read at nothing_space':
|
case 'nothing_space_read at nothing_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
read: [
|
read: [
|
||||||
|
@ -95,6 +89,8 @@ export default function savedObjectsManagementTests({
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
// if we don't have access at the space itself, all ui
|
||||||
|
// capabilities should be false
|
||||||
case 'no_kibana_privileges at everything_space':
|
case 'no_kibana_privileges at everything_space':
|
||||||
case 'no_kibana_privileges at nothing_space':
|
case 'no_kibana_privileges at nothing_space':
|
||||||
case 'legacy_all at everything_space':
|
case 'legacy_all at everything_space':
|
||||||
|
@ -103,10 +99,7 @@ export default function savedObjectsManagementTests({
|
||||||
case 'everything_space_read at nothing_space':
|
case 'everything_space_read at nothing_space':
|
||||||
case 'nothing_space_all at everything_space':
|
case 'nothing_space_all at everything_space':
|
||||||
case 'nothing_space_read at everything_space':
|
case 'nothing_space_read at everything_space':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
assertDeeplyFalse(uiCapabilities.value!.savedObjectsManagement);
|
||||||
expect(uiCapabilities.failureReason).to.be(
|
|
||||||
GetUICapabilitiesFailureReason.RedirectedToRoot
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -7,11 +7,9 @@
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { mapValues } from 'lodash';
|
import { mapValues } from 'lodash';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserScenarios } from '../scenarios';
|
import { UserScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function catalogueTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
export default function catalogueTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
||||||
|
@ -21,13 +19,15 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
UserScenarios.forEach(scenario => {
|
UserScenarios.forEach(scenario => {
|
||||||
it(`${scenario.fullName}`, async () => {
|
it(`${scenario.fullName}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get({
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
username: scenario.username,
|
credentials: {
|
||||||
password: scenario.password,
|
username: scenario.username,
|
||||||
|
password: scenario.password,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('catalogue');
|
||||||
switch (scenario.username) {
|
switch (scenario.username) {
|
||||||
case 'superuser': {
|
case 'superuser': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// everything is enabled
|
// everything is enabled
|
||||||
const expected = mapValues(uiCapabilities.value!.catalogue, () => true);
|
const expected = mapValues(uiCapabilities.value!.catalogue, () => true);
|
||||||
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
||||||
|
@ -37,8 +37,6 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
case 'read':
|
case 'read':
|
||||||
case 'dual_privileges_all':
|
case 'dual_privileges_all':
|
||||||
case 'dual_privileges_read': {
|
case 'dual_privileges_read': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// everything except ml and monitoring is enabled
|
// everything except ml and monitoring is enabled
|
||||||
const expected = mapValues(
|
const expected = mapValues(
|
||||||
uiCapabilities.value!.catalogue,
|
uiCapabilities.value!.catalogue,
|
||||||
|
@ -49,8 +47,6 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
}
|
}
|
||||||
case 'foo_all':
|
case 'foo_all':
|
||||||
case 'foo_read': {
|
case 'foo_read': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('catalogue');
|
|
||||||
// only foo is enabled
|
// only foo is enabled
|
||||||
const expected = mapValues(
|
const expected = mapValues(
|
||||||
uiCapabilities.value!.catalogue,
|
uiCapabilities.value!.catalogue,
|
||||||
|
@ -59,11 +55,10 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
expect(uiCapabilities.value!.catalogue).to.eql(expected);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// these users have no access to even get the ui capabilities
|
// these users have no access to any ui capabilities
|
||||||
case 'legacy_all':
|
case 'legacy_all':
|
||||||
case 'no_kibana_privileges':
|
case 'no_kibana_privileges':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
assertDeeplyFalse(uiCapabilities.value!.catalogue);
|
||||||
expect(uiCapabilities.failureReason).to.be(GetUICapabilitiesFailureReason.NotFound);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -6,11 +6,9 @@
|
||||||
|
|
||||||
import expect from '@kbn/expect';
|
import expect from '@kbn/expect';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserScenarios } from '../scenarios';
|
import { UserScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function fooTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
export default function fooTests({ getService }: KibanaFunctionalTestDefaultProviders) {
|
||||||
|
@ -20,17 +18,21 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
UserScenarios.forEach(scenario => {
|
UserScenarios.forEach(scenario => {
|
||||||
it(`${scenario.fullName}`, async () => {
|
it(`${scenario.fullName}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get({
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
username: scenario.username,
|
credentials: {
|
||||||
password: scenario.password,
|
username: scenario.username,
|
||||||
|
password: scenario.password,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('foo');
|
||||||
|
|
||||||
switch (scenario.username) {
|
switch (scenario.username) {
|
||||||
// these users have a read/write view of Foo
|
// these users have a read/write view of Foo
|
||||||
case 'superuser':
|
case 'superuser':
|
||||||
case 'all':
|
case 'all':
|
||||||
case 'dual_privileges_all':
|
case 'dual_privileges_all':
|
||||||
case 'foo_all':
|
case 'foo_all':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('foo');
|
|
||||||
expect(uiCapabilities.value!.foo).to.eql({
|
expect(uiCapabilities.value!.foo).to.eql({
|
||||||
create: true,
|
create: true,
|
||||||
edit: true,
|
edit: true,
|
||||||
|
@ -42,8 +44,6 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
case 'read':
|
case 'read':
|
||||||
case 'dual_privileges_read':
|
case 'dual_privileges_read':
|
||||||
case 'foo_read':
|
case 'foo_read':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('foo');
|
|
||||||
expect(uiCapabilities.value!.foo).to.eql({
|
expect(uiCapabilities.value!.foo).to.eql({
|
||||||
create: false,
|
create: false,
|
||||||
edit: false,
|
edit: false,
|
||||||
|
@ -51,11 +51,10 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
show: true,
|
show: true,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// these users have no access to even get the ui capabilities
|
// these users have no access to any ui capabilities
|
||||||
case 'legacy_all':
|
case 'legacy_all':
|
||||||
case 'no_kibana_privileges':
|
case 'no_kibana_privileges':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
assertDeeplyFalse(uiCapabilities.value!.foo);
|
||||||
expect(uiCapabilities.failureReason).to.be(GetUICapabilitiesFailureReason.NotFound);
|
|
||||||
break;
|
break;
|
||||||
// all other users can't do anything with Foo
|
// all other users can't do anything with Foo
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -8,10 +8,7 @@ import expect from '@kbn/expect';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import { NavLinksBuilder } from '../../common/nav_links_builder';
|
import { NavLinksBuilder } from '../../common/nav_links_builder';
|
||||||
import { FeaturesService } from '../../common/services';
|
import { FeaturesService } from '../../common/services';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserScenarios } from '../scenarios';
|
import { UserScenarios } from '../scenarios';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
@ -29,37 +26,38 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
UserScenarios.forEach(scenario => {
|
UserScenarios.forEach(scenario => {
|
||||||
it(`${scenario.fullName}`, async () => {
|
it(`${scenario.fullName}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get({
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
username: scenario.username,
|
credentials: {
|
||||||
password: scenario.password,
|
username: scenario.username,
|
||||||
|
password: scenario.password,
|
||||||
|
},
|
||||||
|
navLinks: navLinksBuilder.all(),
|
||||||
});
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('navLinks');
|
||||||
|
|
||||||
switch (scenario.username) {
|
switch (scenario.username) {
|
||||||
case 'superuser':
|
case 'superuser':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.all());
|
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.all());
|
||||||
break;
|
break;
|
||||||
case 'all':
|
case 'all':
|
||||||
case 'read':
|
case 'read':
|
||||||
case 'dual_privileges_all':
|
case 'dual_privileges_all':
|
||||||
case 'dual_privileges_read':
|
case 'dual_privileges_read':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(
|
expect(uiCapabilities.value!.navLinks).to.eql(
|
||||||
navLinksBuilder.except('ml', 'monitoring')
|
navLinksBuilder.except('ml', 'monitoring')
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'foo_all':
|
case 'foo_all':
|
||||||
case 'foo_read':
|
case 'foo_read':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('navLinks');
|
|
||||||
expect(uiCapabilities.value!.navLinks).to.eql(
|
expect(uiCapabilities.value!.navLinks).to.eql(
|
||||||
navLinksBuilder.only('management', 'foo')
|
navLinksBuilder.only('management', 'foo')
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
// these users have no access to any navLinks except management
|
||||||
|
// which is not a navLink that ever gets disabled.
|
||||||
case 'legacy_all':
|
case 'legacy_all':
|
||||||
case 'no_kibana_privileges':
|
case 'no_kibana_privileges':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
expect(uiCapabilities.value!.navLinks).to.eql(navLinksBuilder.only('management'));
|
||||||
expect(uiCapabilities.failureReason).to.be(GetUICapabilitiesFailureReason.NotFound);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -8,11 +8,9 @@ import expect from '@kbn/expect';
|
||||||
import { mapValues } from 'lodash';
|
import { mapValues } from 'lodash';
|
||||||
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
import { KibanaFunctionalTestDefaultProviders } from '../../../types/providers';
|
||||||
import { SavedObjectsManagementBuilder } from '../../common/saved_objects_management_builder';
|
import { SavedObjectsManagementBuilder } from '../../common/saved_objects_management_builder';
|
||||||
import {
|
import { UICapabilitiesService } from '../../common/services/ui_capabilities';
|
||||||
GetUICapabilitiesFailureReason,
|
|
||||||
UICapabilitiesService,
|
|
||||||
} from '../../common/services/ui_capabilities';
|
|
||||||
import { UserScenarios } from '../scenarios';
|
import { UserScenarios } from '../scenarios';
|
||||||
|
import { assertDeeplyFalse } from '../../common/lib/assert_deeply_false';
|
||||||
|
|
||||||
const savedObjectsManagementBuilder = new SavedObjectsManagementBuilder(false);
|
const savedObjectsManagementBuilder = new SavedObjectsManagementBuilder(false);
|
||||||
|
|
||||||
|
@ -26,13 +24,15 @@ export default function savedObjectsManagementTests({
|
||||||
UserScenarios.forEach(scenario => {
|
UserScenarios.forEach(scenario => {
|
||||||
it(`${scenario.fullName}`, async () => {
|
it(`${scenario.fullName}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get({
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
username: scenario.username,
|
credentials: {
|
||||||
password: scenario.password,
|
username: scenario.username,
|
||||||
|
password: scenario.password,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
||||||
switch (scenario.username) {
|
switch (scenario.username) {
|
||||||
case 'superuser':
|
case 'superuser':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
||||||
savedObjectsManagementBuilder.uiCapabilities('all')
|
savedObjectsManagementBuilder.uiCapabilities('all')
|
||||||
);
|
);
|
||||||
|
@ -40,8 +40,6 @@ export default function savedObjectsManagementTests({
|
||||||
break;
|
break;
|
||||||
case 'all':
|
case 'all':
|
||||||
case 'dual_privileges_all':
|
case 'dual_privileges_all':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
all: [
|
all: [
|
||||||
|
@ -64,8 +62,6 @@ export default function savedObjectsManagementTests({
|
||||||
break;
|
break;
|
||||||
case 'read':
|
case 'read':
|
||||||
case 'dual_privileges_read':
|
case 'dual_privileges_read':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
read: [
|
read: [
|
||||||
|
@ -86,8 +82,6 @@ export default function savedObjectsManagementTests({
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'foo_all':
|
case 'foo_all':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
all: ['foo', 'telemetry'],
|
all: ['foo', 'telemetry'],
|
||||||
|
@ -96,8 +90,6 @@ export default function savedObjectsManagementTests({
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'foo_read':
|
case 'foo_read':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
|
||||||
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
expect(uiCapabilities.value!.savedObjectsManagement).to.eql(
|
||||||
savedObjectsManagementBuilder.build({
|
savedObjectsManagementBuilder.build({
|
||||||
read: ['foo', 'index-pattern', 'config'],
|
read: ['foo', 'index-pattern', 'config'],
|
||||||
|
@ -105,9 +97,10 @@ export default function savedObjectsManagementTests({
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'no_kibana_privileges':
|
case 'no_kibana_privileges':
|
||||||
|
// these users have no access to any ui capabilities
|
||||||
case 'legacy_all':
|
case 'legacy_all':
|
||||||
expect(uiCapabilities.success).to.be(false);
|
case 'no_kibana_privileges':
|
||||||
expect(uiCapabilities.failureReason).to.be(GetUICapabilitiesFailureReason.NotFound);
|
assertDeeplyFalse(uiCapabilities.value!.savedObjectsManagement);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new UnreachableError(scenario);
|
throw new UnreachableError(scenario);
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default function catalogueTests({ getService }: KibanaFunctionalTestDefau
|
||||||
describe('catalogue', () => {
|
describe('catalogue', () => {
|
||||||
SpaceScenarios.forEach(scenario => {
|
SpaceScenarios.forEach(scenario => {
|
||||||
it(`${scenario.name}`, async () => {
|
it(`${scenario.name}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(null, scenario.id);
|
const uiCapabilities = await uiCapabilitiesService.get({ spaceId: scenario.id });
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'everything_space': {
|
case 'everything_space': {
|
||||||
expect(uiCapabilities.success).to.be(true);
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function fooTests({ getService }: KibanaFunctionalTestDefaultProv
|
||||||
describe('foo', () => {
|
describe('foo', () => {
|
||||||
SpaceScenarios.forEach(scenario => {
|
SpaceScenarios.forEach(scenario => {
|
||||||
it(`${scenario.name}`, async () => {
|
it(`${scenario.name}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(null, scenario.id);
|
const uiCapabilities = await uiCapabilitiesService.get({ spaceId: scenario.id });
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'everything_space':
|
case 'everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
|
|
@ -25,7 +25,10 @@ export default function navLinksTests({ getService }: KibanaFunctionalTestDefaul
|
||||||
|
|
||||||
SpaceScenarios.forEach(scenario => {
|
SpaceScenarios.forEach(scenario => {
|
||||||
it(`${scenario.name}`, async () => {
|
it(`${scenario.name}`, async () => {
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(null, scenario.id);
|
const uiCapabilities = await uiCapabilitiesService.get({
|
||||||
|
navLinks: navLinksBuilder.all(),
|
||||||
|
spaceId: scenario.id,
|
||||||
|
});
|
||||||
switch (scenario.id) {
|
switch (scenario.id) {
|
||||||
case 'everything_space':
|
case 'everything_space':
|
||||||
expect(uiCapabilities.success).to.be(true);
|
expect(uiCapabilities.success).to.be(true);
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default function savedObjectsManagementTests({
|
||||||
SpaceScenarios.forEach(scenario => {
|
SpaceScenarios.forEach(scenario => {
|
||||||
it(`${scenario.name}`, async () => {
|
it(`${scenario.name}`, async () => {
|
||||||
// spaces don't affect saved objects management, so we assert the same thing for every scenario
|
// spaces don't affect saved objects management, so we assert the same thing for every scenario
|
||||||
const uiCapabilities = await uiCapabilitiesService.get(null, scenario.id);
|
const uiCapabilities = await uiCapabilitiesService.get({ spaceId: scenario.id });
|
||||||
expect(uiCapabilities.success).to.be(true);
|
expect(uiCapabilities.success).to.be(true);
|
||||||
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
expect(uiCapabilities.value).to.have.property('savedObjectsManagement');
|
||||||
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
const expected = mapValues(uiCapabilities.value!.savedObjectsManagement, () =>
|
||||||
|
|
2
x-pack/typings/hapi.d.ts
vendored
2
x-pack/typings/hapi.d.ts
vendored
|
@ -8,8 +8,8 @@ import 'hapi';
|
||||||
|
|
||||||
import { CloudPlugin } from '../plugins/cloud';
|
import { CloudPlugin } from '../plugins/cloud';
|
||||||
import { EncryptedSavedObjectsPlugin } from '../plugins/encrypted_saved_objects';
|
import { EncryptedSavedObjectsPlugin } from '../plugins/encrypted_saved_objects';
|
||||||
import { SecurityPlugin } from '../plugins/security';
|
|
||||||
import { XPackMainPlugin } from '../plugins/xpack_main/xpack_main';
|
import { XPackMainPlugin } from '../plugins/xpack_main/xpack_main';
|
||||||
|
import { SecurityPlugin } from '../plugins/security';
|
||||||
|
|
||||||
declare module 'hapi' {
|
declare module 'hapi' {
|
||||||
interface PluginProperties {
|
interface PluginProperties {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue