mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Merge remote-tracking branch 'origin/master' into feature/merge-code
This commit is contained in:
commit
4357686db5
231 changed files with 5193 additions and 3260 deletions
|
@ -132,11 +132,13 @@ module.exports = {
|
|||
],
|
||||
from: [
|
||||
'src/core/public/**/*',
|
||||
'!src/core/public/index*',
|
||||
'!src/core/public/index.ts',
|
||||
'!src/core/public/mocks.ts',
|
||||
'!src/core/public/utils/**/*',
|
||||
|
||||
'src/core/server/**/*',
|
||||
'!src/core/server/index*',
|
||||
'!src/core/server/index.ts',
|
||||
'!src/core/server/mocks.ts',
|
||||
|
||||
'src/plugins/**/public/**/*',
|
||||
'!src/plugins/**/public/index*',
|
||||
|
|
|
@ -7,13 +7,13 @@ The interface that should be returned by a `PluginInitializer`<!-- -->.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface Plugin<TSetup, TDependencies extends Record<string, unknown> =
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<string, unknown> =
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [setup](./kibana-plugin-public.plugin.setup.md) | <code>(core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise<TSetup></code> | |
|
||||
| [setup](./kibana-plugin-public.plugin.setup.md) | <code>(core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup></code> | |
|
||||
| [stop](./kibana-plugin-public.plugin.stop.md) | <code>() => void</code> | |
|
||||
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise<TSetup>;
|
||||
setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
```
|
||||
|
|
|
@ -7,5 +7,5 @@ The `plugin` export at the root of a plugin's `public` directory should conform
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type PluginInitializer<TSetup, TDependencies extends Record<string, unknown> = {}> = (core: PluginInitializerContext) => Plugin<TSetup, TDependencies>;
|
||||
export declare type PluginInitializer<TSetup, TPluginsSetup extends Record<string, unknown> = {}> = (core: PluginInitializerContext) => Plugin<TSetup, TPluginsSetup>;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [atPath](./kibana-plugin-server.configservice.atpath.md)
|
||||
|
||||
## ConfigService.atPath() method
|
||||
|
||||
Reads the subset of the config at the specified `path` and validates it against the static `schema` on the given `ConfigClass`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
atPath<TSchema extends Type<any>, TConfig>(path: ConfigPath, ConfigClass: ConfigWithSchema<TSchema, TConfig>): Observable<TConfig>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>ConfigPath</code> | The path to the desired subset of the config. |
|
||||
| ConfigClass | <code>ConfigWithSchema<TSchema, TConfig></code> | A class (not an instance of a class) that contains a static <code>schema</code> that we validate the config at the given <code>path</code> against. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Observable<TConfig>`
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [getConfig$](./kibana-plugin-server.configservice.getconfig$.md)
|
||||
|
||||
## ConfigService.getConfig$() method
|
||||
|
||||
Returns the full config object observable. This is not intended for "normal use", but for features that \_need\_ access to the full object.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getConfig$(): Observable<Config>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Observable<Config>`
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [getUnusedPaths](./kibana-plugin-server.configservice.getunusedpaths.md)
|
||||
|
||||
## ConfigService.getUnusedPaths() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getUnusedPaths(): Promise<string[]>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<string[]>`
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [getUsedPaths](./kibana-plugin-server.configservice.getusedpaths.md)
|
||||
|
||||
## ConfigService.getUsedPaths() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getUsedPaths(): Promise<string[]>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<string[]>`
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [isEnabledAtPath](./kibana-plugin-server.configservice.isenabledatpath.md)
|
||||
|
||||
## ConfigService.isEnabledAtPath() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isEnabledAtPath(path: ConfigPath): Promise<boolean>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>ConfigPath</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<boolean>`
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md)
|
||||
|
||||
## ConfigService class
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare class ConfigService
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [atPath(path, ConfigClass)](./kibana-plugin-server.configservice.atpath.md) | | Reads the subset of the config at the specified <code>path</code> and validates it against the static <code>schema</code> on the given <code>ConfigClass</code>. |
|
||||
| [getConfig$()](./kibana-plugin-server.configservice.getconfig$.md) | | Returns the full config object observable. This is not intended for "normal use", but for features that \_need\_ access to the full object. |
|
||||
| [getUnusedPaths()](./kibana-plugin-server.configservice.getunusedpaths.md) | | |
|
||||
| [getUsedPaths()](./kibana-plugin-server.configservice.getusedpaths.md) | | |
|
||||
| [isEnabledAtPath(path)](./kibana-plugin-server.configservice.isenabledatpath.md) | | |
|
||||
| [optionalAtPath(path, ConfigClass)](./kibana-plugin-server.configservice.optionalatpath.md) | | Same as <code>atPath</code>, but returns <code>undefined</code> if there is no config at the specified path.[ConfigService.atPath()](./kibana-plugin-server.configservice.atpath.md) |
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ConfigService](./kibana-plugin-server.configservice.md) > [optionalAtPath](./kibana-plugin-server.configservice.optionalatpath.md)
|
||||
|
||||
## ConfigService.optionalAtPath() method
|
||||
|
||||
Same as `atPath`<!-- -->, but returns `undefined` if there is no config at the specified path.
|
||||
|
||||
[ConfigService.atPath()](./kibana-plugin-server.configservice.atpath.md)
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
optionalAtPath<TSchema extends Type<any>, TConfig>(path: ConfigPath, ConfigClass: ConfigWithSchema<TSchema, TConfig>): Observable<TConfig | undefined>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| path | <code>ConfigPath</code> | |
|
||||
| ConfigClass | <code>ConfigWithSchema<TSchema, TConfig></code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Observable<TConfig | undefined>`
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) > [adminClient$](./kibana-plugin-server.elasticsearchservicesetup.adminclient$.md)
|
||||
|
||||
## ElasticsearchServiceSetup.adminClient$ property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly adminClient$: Observable<ClusterClient>;
|
||||
```
|
|
@ -0,0 +1,9 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) > [createClient](./kibana-plugin-server.elasticsearchservicesetup.createclient.md)
|
||||
|
||||
## ElasticsearchServiceSetup.createClient property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly createClient: (type: string, config: ElasticsearchClientConfig) => ClusterClient;
|
||||
```
|
|
@ -0,0 +1,9 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) > [dataClient$](./kibana-plugin-server.elasticsearchservicesetup.dataclient$.md)
|
||||
|
||||
## ElasticsearchServiceSetup.dataClient$ property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly dataClient$: Observable<ClusterClient>;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) > [legacy](./kibana-plugin-server.elasticsearchservicesetup.legacy.md)
|
||||
|
||||
## ElasticsearchServiceSetup.legacy property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly legacy: {
|
||||
readonly config$: Observable<ElasticsearchConfig>;
|
||||
};
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md)
|
||||
|
||||
## ElasticsearchServiceSetup interface
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface ElasticsearchServiceSetup
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [adminClient$](./kibana-plugin-server.elasticsearchservicesetup.adminclient$.md) | <code>Observable<ClusterClient></code> | |
|
||||
| [createClient](./kibana-plugin-server.elasticsearchservicesetup.createclient.md) | <code>(type: string, config: ElasticsearchClientConfig) => ClusterClient</code> | |
|
||||
| [dataClient$](./kibana-plugin-server.elasticsearchservicesetup.dataclient$.md) | <code>Observable<ClusterClient></code> | |
|
||||
| [legacy](./kibana-plugin-server.elasticsearchservicesetup.legacy.md) | <code>{`<p/>` readonly config$: Observable<ElasticsearchConfig>;`<p/>` }</code> | |
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
| Class | Description |
|
||||
| --- | --- |
|
||||
| [ClusterClient](./kibana-plugin-server.clusterclient.md) | Represents an Elasticsearch cluster API client and allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via <code>asScoped(...)</code>). |
|
||||
| [ConfigService](./kibana-plugin-server.configservice.md) | |
|
||||
| [ScopedClusterClient](./kibana-plugin-server.scopedclusterclient.md) | Serves the same purpose as "normal" <code>ClusterClient</code> but exposes additional <code>callAsCurrentUser</code> method that doesn't use credentials of the Kibana internal user (as <code>callAsInternalUser</code> does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API |
|
||||
|
||||
## Interfaces
|
||||
|
@ -15,9 +16,11 @@
|
|||
| --- | --- |
|
||||
| [CallAPIOptions](./kibana-plugin-server.callapioptions.md) | The set of options that defines how API call should be made and result be processed. |
|
||||
| [CoreSetup](./kibana-plugin-server.coresetup.md) | |
|
||||
| [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) | |
|
||||
| [Logger](./kibana-plugin-server.logger.md) | Logger exposes all the necessary methods to log any type of information and this is the interface used by the logging consumers including plugins. |
|
||||
| [LoggerFactory](./kibana-plugin-server.loggerfactory.md) | The single purpose of <code>LoggerFactory</code> interface is to define a way to retrieve a context-based logger instance. |
|
||||
| [LogMeta](./kibana-plugin-server.logmeta.md) | Contextual metadata |
|
||||
| [Plugin](./kibana-plugin-server.plugin.md) | The interface that should be returned by a <code>PluginInitializer</code>. |
|
||||
| [PluginInitializerContext](./kibana-plugin-server.plugininitializercontext.md) | Context that's available to plugins during initialization stage. |
|
||||
| [PluginSetupContext](./kibana-plugin-server.pluginsetupcontext.md) | Context passed to the plugins <code>setup</code> method. |
|
||||
|
||||
|
@ -28,5 +31,6 @@
|
|||
| [APICaller](./kibana-plugin-server.apicaller.md) | |
|
||||
| [ElasticsearchClientConfig](./kibana-plugin-server.elasticsearchclientconfig.md) | |
|
||||
| [Headers](./kibana-plugin-server.headers.md) | |
|
||||
| [PluginInitializer](./kibana-plugin-server.plugininitializer.md) | The <code>plugin</code> export at the root of a plugin's <code>server</code> directory should conform to this interface. |
|
||||
| [PluginName](./kibana-plugin-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. |
|
||||
|
||||
|
|
19
docs/development/core/server/kibana-plugin-server.plugin.md
Normal file
19
docs/development/core/server/kibana-plugin-server.plugin.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md)
|
||||
|
||||
## Plugin interface
|
||||
|
||||
The interface that should be returned by a `PluginInitializer`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<PluginName, unknown> =
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [setup](./kibana-plugin-server.plugin.setup.md) | <code>(pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup></code> | |
|
||||
| [stop](./kibana-plugin-server.plugin.stop.md) | <code>() => void</code> | |
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [setup](./kibana-plugin-server.plugin.setup.md)
|
||||
|
||||
## Plugin.setup property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
setup: (pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
```
|
|
@ -0,0 +1,9 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [stop](./kibana-plugin-server.plugin.stop.md)
|
||||
|
||||
## Plugin.stop property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stop?: () => void;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
[Home](./index) > [kibana-plugin-server](./kibana-plugin-server.md) > [PluginInitializer](./kibana-plugin-server.plugininitializer.md)
|
||||
|
||||
## PluginInitializer type
|
||||
|
||||
The `plugin` export at the root of a plugin's `server` directory should conform to this interface.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type PluginInitializer<TSetup, TPluginsSetup extends Record<PluginName, unknown> = {}> = (coreContext: PluginInitializerContext) => Plugin<TSetup, TPluginsSetup>;
|
||||
```
|
|
@ -37,7 +37,7 @@ shasum -a 512 kibana-{version}-linux-x86_64.tar.gz <1>
|
|||
tar -xzf kibana-{version}-linux-x86_64.tar.gz
|
||||
cd kibana-{version}-linux-x86_64/ <2>
|
||||
--------------------------------------------
|
||||
<1> Compare the SHA produced by or `shasum` with the
|
||||
<1> Compare the SHA produced by `shasum` with the
|
||||
https://artifacts.elastic.co/downloads/kibana/kibana-{version}-linux-x86_64.tar.gz.sha512[published SHA].
|
||||
<2> This directory is known as `$KIBANA_HOME`.
|
||||
|
||||
|
@ -64,7 +64,7 @@ shasum -a 512 kibana-{version}-darwin-x86_64.tar.gz <1>
|
|||
tar -xzf kibana-{version}-darwin-x86_64.tar.gz
|
||||
cd kibana-{version}-darwin-x86_64/ <2>
|
||||
--------------------------------------------
|
||||
<1> Compare the SHA produced by or `shasum` with the
|
||||
<1> Compare the SHA produced by `shasum` with the
|
||||
https://artifacts.elastic.co/downloads/kibana/kibana-{version}-darwin-x86_64.tar.gz.sha512[published SHA].
|
||||
<2> This directory is known as `$KIBANA_HOME`.
|
||||
|
||||
|
|
|
@ -249,7 +249,6 @@
|
|||
"webpack-merge": "4.1.4",
|
||||
"whatwg-fetch": "^3.0.0",
|
||||
"wreck": "^14.0.2",
|
||||
"x-pack": "8.0.0",
|
||||
"yauzl": "2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -23,6 +23,11 @@ module.exports = {
|
|||
],
|
||||
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.mjs', '.js', '.json', '.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
react: {
|
||||
version: semver.valid(semver.coerce(PKG.dependencies.react)),
|
||||
},
|
||||
|
|
|
@ -156,6 +156,22 @@ ruleTester.run('@kbn/eslint/no-restricted-paths', rule, {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: 'const d = require("./deep/d.js")',
|
||||
filename: path.join(__dirname, './files/no_restricted_paths/server/b.js'),
|
||||
options: [
|
||||
{
|
||||
basePath: __dirname,
|
||||
zones: [
|
||||
{
|
||||
allowSameFolder: true,
|
||||
target: 'files/no_restricted_paths/**/*',
|
||||
from: ['files/no_restricted_paths/**/*', '!files/no_restricted_paths/server/b*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
invalid: [
|
||||
|
|
|
@ -51,8 +51,10 @@ function traverseToTopFolder(src, pattern) {
|
|||
}
|
||||
|
||||
function isSameFolderOrDescendent(src, imported, pattern) {
|
||||
const srcFileFolderRoot = traverseToTopFolder(src, pattern);
|
||||
const importedFileFolderRoot = traverseToTopFolder(imported, pattern);
|
||||
// to allow to exclude file by name in pattern (e.g., !**/index*) we start with file dirname and then traverse
|
||||
const srcFileFolderRoot = traverseToTopFolder(path.dirname(src), pattern);
|
||||
const importedFileFolderRoot = traverseToTopFolder(path.dirname(imported), pattern);
|
||||
|
||||
return srcFileFolderRoot === importedFileFolderRoot;
|
||||
}
|
||||
|
||||
|
|
199
packages/kbn-pm/dist/index.js
vendored
199
packages/kbn-pm/dist/index.js
vendored
|
@ -99,8 +99,17 @@ __webpack_require__.r(__webpack_exports__);
|
|||
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; });
|
||||
|
||||
/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(131);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return _utils_workspaces__WEBPACK_IMPORTED_MODULE_2__["copyWorkspacePackages"]; });
|
||||
/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjects", function() { return _utils_projects__WEBPACK_IMPORTED_MODULE_2__["getProjects"]; });
|
||||
|
||||
/* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(53);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Project", function() { return _utils_project__WEBPACK_IMPORTED_MODULE_3__["Project"]; });
|
||||
|
||||
/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(131);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__["copyWorkspacePackages"]; });
|
||||
|
||||
/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(132);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; });
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
|
@ -124,6 +133,9 @@ __webpack_require__.r(__webpack_exports__);
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
@ -2646,6 +2658,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "chmod", function() { return chmod; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readFile", function() { return readFile; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mkdirp", function() { return mkdirp; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isSymlink", function() { return isSymlink; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isDirectory", function() { return isDirectory; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isFile", function() { return isFile; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createSymlink", function() { return createSymlink; });
|
||||
|
@ -2685,7 +2698,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||
|
||||
|
||||
|
||||
const stat = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(fs__WEBPACK_IMPORTED_MODULE_1___default.a.stat);
|
||||
const lstat = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(fs__WEBPACK_IMPORTED_MODULE_1___default.a.lstat);
|
||||
const readFile = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(fs__WEBPACK_IMPORTED_MODULE_1___default.a.readFile);
|
||||
const symlink = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(fs__WEBPACK_IMPORTED_MODULE_1___default.a.symlink);
|
||||
const chmod = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(fs__WEBPACK_IMPORTED_MODULE_1___default.a.chmod);
|
||||
|
@ -2697,7 +2710,7 @@ const copyDirectory = Object(util__WEBPACK_IMPORTED_MODULE_5__["promisify"])(ncp
|
|||
|
||||
async function statTest(path, block) {
|
||||
try {
|
||||
return block((await stat(path)));
|
||||
return block((await lstat(path)));
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
return false;
|
||||
|
@ -2707,11 +2720,19 @@ async function statTest(path, block) {
|
|||
}
|
||||
}
|
||||
/**
|
||||
* Test if a path points to a directory.
|
||||
* Test if a path points to a symlink.
|
||||
* @param path
|
||||
*/
|
||||
|
||||
|
||||
async function isSymlink(path) {
|
||||
return await statTest(path, stats => stats.isSymbolicLink());
|
||||
}
|
||||
/**
|
||||
* Test if a path points to a directory.
|
||||
* @param path
|
||||
*/
|
||||
|
||||
async function isDirectory(path) {
|
||||
return await statTest(path, stats => stats.isDirectory());
|
||||
}
|
||||
|
@ -7822,14 +7843,16 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Project", function() { return Project; });
|
||||
/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
||||
/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16);
|
||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29);
|
||||
/* harmony import */ var util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_2__);
|
||||
/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(52);
|
||||
/* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(33);
|
||||
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(54);
|
||||
/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(92);
|
||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(23);
|
||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16);
|
||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__);
|
||||
/* harmony import */ var util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(29);
|
||||
/* harmony import */ var util__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(util__WEBPACK_IMPORTED_MODULE_3__);
|
||||
/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(52);
|
||||
/* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(33);
|
||||
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(54);
|
||||
/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(92);
|
||||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
|
||||
|
||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
|
@ -7859,9 +7882,10 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|||
|
||||
|
||||
|
||||
|
||||
class Project {
|
||||
static async fromPath(path) {
|
||||
const pkgJson = await Object(_package_json__WEBPACK_IMPORTED_MODULE_5__["readPackageJson"])(path);
|
||||
const pkgJson = await Object(_package_json__WEBPACK_IMPORTED_MODULE_6__["readPackageJson"])(path);
|
||||
return new Project(pkgJson, path);
|
||||
}
|
||||
|
||||
|
@ -7890,9 +7914,9 @@ class Project {
|
|||
|
||||
this.json = Object.freeze(packageJson);
|
||||
this.path = projectPath;
|
||||
this.packageJsonLocation = Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, 'package.json');
|
||||
this.nodeModulesLocation = Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, 'node_modules');
|
||||
this.targetLocation = Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, 'target');
|
||||
this.packageJsonLocation = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, 'package.json');
|
||||
this.nodeModulesLocation = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, 'node_modules');
|
||||
this.targetLocation = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, 'target');
|
||||
this.productionDependencies = this.json.dependencies || {};
|
||||
this.devDependencies = this.json.devDependencies || {};
|
||||
this.allDependencies = _objectSpread({}, this.devDependencies, this.productionDependencies);
|
||||
|
@ -7911,7 +7935,7 @@ class Project {
|
|||
if (dependentProjectIsInWorkspace) {
|
||||
expectedVersionInPackageJson = project.json.version;
|
||||
} else {
|
||||
const relativePathToProject = normalizePath(Object(path__WEBPACK_IMPORTED_MODULE_1__["relative"])(this.path, project.path));
|
||||
const relativePathToProject = normalizePath(Object(path__WEBPACK_IMPORTED_MODULE_2__["relative"])(this.path, project.path));
|
||||
expectedVersionInPackageJson = `link:${relativePathToProject}`;
|
||||
} // No issues!
|
||||
|
||||
|
@ -7922,15 +7946,15 @@ class Project {
|
|||
|
||||
let problemMsg;
|
||||
|
||||
if (Object(_package_json__WEBPACK_IMPORTED_MODULE_5__["isLinkDependency"])(versionInPackageJson) && dependentProjectIsInWorkspace) {
|
||||
if (Object(_package_json__WEBPACK_IMPORTED_MODULE_6__["isLinkDependency"])(versionInPackageJson) && dependentProjectIsInWorkspace) {
|
||||
problemMsg = `but should be using a workspace`;
|
||||
} else if (Object(_package_json__WEBPACK_IMPORTED_MODULE_5__["isLinkDependency"])(versionInPackageJson)) {
|
||||
} else if (Object(_package_json__WEBPACK_IMPORTED_MODULE_6__["isLinkDependency"])(versionInPackageJson)) {
|
||||
problemMsg = `using 'link:', but the path is wrong`;
|
||||
} else {
|
||||
problemMsg = `but it's not using the local package`;
|
||||
}
|
||||
|
||||
throw new _errors__WEBPACK_IMPORTED_MODULE_3__["CliError"](`[${this.name}] depends on [${project.name}] ${problemMsg}. Update its package.json to the expected value below.`, {
|
||||
throw new _errors__WEBPACK_IMPORTED_MODULE_4__["CliError"](`[${this.name}] depends on [${project.name}] ${problemMsg}. Update its package.json to the expected value below.`, {
|
||||
actual: `"${project.name}": "${versionInPackageJson}"`,
|
||||
expected: `"${project.name}": "${expectedVersionInPackageJson}"`,
|
||||
package: `${this.name} (${this.packageJsonLocation})`
|
||||
|
@ -7948,7 +7972,7 @@ class Project {
|
|||
|
||||
|
||||
getIntermediateBuildDirectory() {
|
||||
return Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, this.getBuildConfig().intermediateBuildDirectory || '.');
|
||||
return Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, this.getBuildConfig().intermediateBuildDirectory || '.');
|
||||
}
|
||||
|
||||
getCleanConfig() {
|
||||
|
@ -7968,7 +7992,7 @@ class Project {
|
|||
|
||||
if (typeof raw === 'string') {
|
||||
return {
|
||||
[this.name]: Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, raw)
|
||||
[this.name]: Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, raw)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7976,25 +8000,25 @@ class Project {
|
|||
const binsConfig = {};
|
||||
|
||||
for (const binName of Object.keys(raw)) {
|
||||
binsConfig[binName] = Object(path__WEBPACK_IMPORTED_MODULE_1__["resolve"])(this.path, raw[binName]);
|
||||
binsConfig[binName] = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.path, raw[binName]);
|
||||
}
|
||||
|
||||
return binsConfig;
|
||||
}
|
||||
|
||||
throw new _errors__WEBPACK_IMPORTED_MODULE_3__["CliError"](`[${this.name}] has an invalid "bin" field in its package.json, ` + `expected an object or a string`, {
|
||||
binConfig: Object(util__WEBPACK_IMPORTED_MODULE_2__["inspect"])(raw),
|
||||
throw new _errors__WEBPACK_IMPORTED_MODULE_4__["CliError"](`[${this.name}] has an invalid "bin" field in its package.json, ` + `expected an object or a string`, {
|
||||
binConfig: Object(util__WEBPACK_IMPORTED_MODULE_3__["inspect"])(raw),
|
||||
package: `${this.name} (${this.packageJsonLocation})`
|
||||
});
|
||||
}
|
||||
|
||||
async runScript(scriptName, args = []) {
|
||||
_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\n\nRunning script [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(scriptName)}] in [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(this.name)}]:\n`));
|
||||
return Object(_scripts__WEBPACK_IMPORTED_MODULE_6__["runScriptInPackage"])(scriptName, args, this);
|
||||
_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\n\nRunning script [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(scriptName)}] in [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(this.name)}]:\n`));
|
||||
return Object(_scripts__WEBPACK_IMPORTED_MODULE_7__["runScriptInPackage"])(scriptName, args, this);
|
||||
}
|
||||
|
||||
runScriptStreaming(scriptName, args = []) {
|
||||
return Object(_scripts__WEBPACK_IMPORTED_MODULE_6__["runScriptInPackageStreaming"])(scriptName, args, this);
|
||||
return Object(_scripts__WEBPACK_IMPORTED_MODULE_7__["runScriptInPackageStreaming"])(scriptName, args, this);
|
||||
}
|
||||
|
||||
hasDependencies() {
|
||||
|
@ -8004,8 +8028,45 @@ class Project {
|
|||
async installDependencies({
|
||||
extraArgs
|
||||
}) {
|
||||
_log__WEBPACK_IMPORTED_MODULE_4__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\n\nInstalling dependencies in [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(this.name)}]:\n`));
|
||||
return Object(_scripts__WEBPACK_IMPORTED_MODULE_6__["installInDir"])(this.path, extraArgs);
|
||||
_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(chalk__WEBPACK_IMPORTED_MODULE_0___default.a.bold(`\n\nInstalling dependencies in [${chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(this.name)}]:\n`));
|
||||
await Object(_scripts__WEBPACK_IMPORTED_MODULE_7__["installInDir"])(this.path, extraArgs);
|
||||
await this.removeExtraneousNodeModules();
|
||||
}
|
||||
/**
|
||||
* Yarn workspaces symlinks workspace projects to the root node_modules, even
|
||||
* when there is no depenency on the project. This results in unnecicary, and
|
||||
* often duplicated code in the build archives.
|
||||
*/
|
||||
|
||||
|
||||
async removeExtraneousNodeModules() {
|
||||
// this is only relevant for the root workspace
|
||||
if (!this.isWorkspaceRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspacesInfo = await Object(_scripts__WEBPACK_IMPORTED_MODULE_7__["yarnWorkspacesInfo"])(this.path);
|
||||
const unusedWorkspaces = new Set(Object.keys(workspacesInfo)); // check for any cross-project dependency
|
||||
|
||||
for (const name of Object.keys(workspacesInfo)) {
|
||||
const workspace = workspacesInfo[name];
|
||||
workspace.workspaceDependencies.forEach(w => unusedWorkspaces.delete(w));
|
||||
}
|
||||
|
||||
unusedWorkspaces.forEach(name => {
|
||||
const {
|
||||
dependencies,
|
||||
devDependencies
|
||||
} = this.json;
|
||||
const nodeModulesPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(this.nodeModulesLocation, name);
|
||||
const isDependency = dependencies && dependencies.hasOwnProperty(name);
|
||||
const isDevDependency = devDependencies && devDependencies.hasOwnProperty(name);
|
||||
|
||||
if (!isDependency && !isDevDependency && fs__WEBPACK_IMPORTED_MODULE_1___default.a.existsSync(nodeModulesPath)) {
|
||||
_log__WEBPACK_IMPORTED_MODULE_5__["log"].write(`No dependency on ${name}, removing link in node_modules`);
|
||||
fs__WEBPACK_IMPORTED_MODULE_1___default.a.unlinkSync(nodeModulesPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // We normalize all path separators to `/` in generated files
|
||||
|
@ -13451,6 +13512,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "installInDir", function() { return installInDir; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackage", function() { return runScriptInPackage; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runScriptInPackageStreaming", function() { return runScriptInPackageStreaming; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "yarnWorkspacesInfo", function() { return yarnWorkspacesInfo; });
|
||||
/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(93);
|
||||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
|
@ -13505,6 +13567,14 @@ function runScriptInPackageStreaming(script, args, pkg) {
|
|||
prefix: pkg.name
|
||||
});
|
||||
}
|
||||
async function yarnWorkspacesInfo(directory) {
|
||||
const workspacesInfo = await Object(_child_process__WEBPACK_IMPORTED_MODULE_0__["spawn"])('yarn', ['workspaces', 'info', '--json'], {
|
||||
cwd: directory,
|
||||
stdio: 'pipe'
|
||||
});
|
||||
const stdout = JSON.parse(workspacesInfo.stdout);
|
||||
return JSON.parse(stdout.data);
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
/* 93 */
|
||||
|
@ -13557,17 +13627,17 @@ function generateColors() {
|
|||
}
|
||||
|
||||
function spawn(command, args, opts) {
|
||||
return execa__WEBPACK_IMPORTED_MODULE_1___default()(command, args, _objectSpread({}, opts, {
|
||||
return execa__WEBPACK_IMPORTED_MODULE_1___default()(command, args, _objectSpread({
|
||||
stdio: 'inherit'
|
||||
}));
|
||||
}, opts));
|
||||
}
|
||||
const nextColor = generateColors();
|
||||
function spawnStreaming(command, args, opts, {
|
||||
prefix
|
||||
}) {
|
||||
const spawned = execa__WEBPACK_IMPORTED_MODULE_1___default()(command, args, _objectSpread({}, opts, {
|
||||
const spawned = execa__WEBPACK_IMPORTED_MODULE_1___default()(command, args, _objectSpread({
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
}));
|
||||
}, opts));
|
||||
const color = nextColor();
|
||||
const prefixedStdout = strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default()({
|
||||
tag: `${color.bold(prefix)}:`
|
||||
|
@ -17423,10 +17493,16 @@ async function workspacePackagePaths(rootPath) {
|
|||
return workspaceProjectsPaths;
|
||||
}
|
||||
async function copyWorkspacePackages(rootPath) {
|
||||
const workspaceProjects = await getWorkspaceProjects(rootPath);
|
||||
const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(rootPath, {});
|
||||
const projects = await Object(_projects__WEBPACK_IMPORTED_MODULE_6__["getProjects"])(rootPath, projectPaths);
|
||||
|
||||
for (const project of projects.values()) {
|
||||
const dest = path__WEBPACK_IMPORTED_MODULE_1___default.a.resolve(rootPath, 'node_modules', project.name);
|
||||
|
||||
if ((await Object(_fs__WEBPACK_IMPORTED_MODULE_4__["isSymlink"])(dest)) === false) {
|
||||
continue;
|
||||
} // Remove the symlink
|
||||
|
||||
for (const project of workspaceProjects.values()) {
|
||||
const dest = path__WEBPACK_IMPORTED_MODULE_1___default.a.resolve(rootPath, 'node_modules', project.name); // Remove the symlink
|
||||
|
||||
await Object(_fs__WEBPACK_IMPORTED_MODULE_4__["unlink"])(dest); // Copy in the package
|
||||
|
||||
|
@ -17434,19 +17510,6 @@ async function copyWorkspacePackages(rootPath) {
|
|||
}
|
||||
}
|
||||
|
||||
async function getWorkspaceProjects(rootPath) {
|
||||
const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(rootPath, {});
|
||||
const projects = await Object(_projects__WEBPACK_IMPORTED_MODULE_6__["getProjects"])(rootPath, projectPaths);
|
||||
|
||||
for (const [key, project] of projects.entries()) {
|
||||
if (!project.isWorkspaceProject) {
|
||||
projects.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
function packagesFromGlobPattern({
|
||||
pattern,
|
||||
rootPath
|
||||
|
@ -17496,7 +17559,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/**
|
||||
* Returns all the paths where plugins are located
|
||||
*/
|
||||
function getProjectPaths(rootPath, options) {
|
||||
function getProjectPaths(rootPath, options = {}) {
|
||||
const skipKibanaPlugins = Boolean(options['skip-kibana-plugins']);
|
||||
const ossOnly = Boolean(options.oss);
|
||||
const projectPaths = [rootPath, Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(rootPath, 'packages/*')]; // This is needed in order to install the dependencies for the declared
|
||||
|
@ -31713,9 +31776,10 @@ __webpack_require__.r(__webpack_exports__);
|
|||
|
||||
async function buildProductionProjects({
|
||||
kibanaRoot,
|
||||
buildRoots
|
||||
buildRoot,
|
||||
onlyOSS
|
||||
}) {
|
||||
const projects = await getProductionProjects(kibanaRoot);
|
||||
const projects = await getProductionProjects(kibanaRoot, onlyOSS);
|
||||
const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["buildProjectGraph"])(projects);
|
||||
const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["topologicallyBatchProjects"])(projects, projectGraph);
|
||||
const projectNames = [...projects.values()].map(project => project.name);
|
||||
|
@ -31725,10 +31789,7 @@ async function buildProductionProjects({
|
|||
for (const project of batch) {
|
||||
await deleteTarget(project);
|
||||
await buildProject(project);
|
||||
|
||||
for (const buildRoot of buildRoots) {
|
||||
await copyToBuild(project, kibanaRoot, buildRoot);
|
||||
}
|
||||
await copyToBuild(project, kibanaRoot, buildRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31736,17 +31797,33 @@ async function buildProductionProjects({
|
|||
* Returns the subset of projects that should be built into the production
|
||||
* bundle. As we copy these into Kibana's `node_modules` during the build step,
|
||||
* and let Kibana's build process be responsible for installing dependencies,
|
||||
* we only include Kibana's transitive _production_ dependencies.
|
||||
* we only include Kibana's transitive _production_ dependencies. If onlyOSS
|
||||
* is supplied, we omit projects with build.oss in their package.json set to false.
|
||||
*/
|
||||
|
||||
async function getProductionProjects(rootPath) {
|
||||
async function getProductionProjects(rootPath, onlyOSS) {
|
||||
const projectPaths = Object(_config__WEBPACK_IMPORTED_MODULE_3__["getProjectPaths"])(rootPath, {});
|
||||
const projects = await Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["getProjects"])(rootPath, projectPaths);
|
||||
const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])([projects.get('kibana')], projects, {
|
||||
const projectsSubset = [projects.get('kibana')];
|
||||
|
||||
if (projects.has('x-pack')) {
|
||||
projectsSubset.push(projects.get('x-pack'));
|
||||
}
|
||||
|
||||
const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, {
|
||||
onlyProductionDependencies: true
|
||||
}); // We remove Kibana, as we're already building Kibana
|
||||
|
||||
productionProjects.delete('kibana');
|
||||
|
||||
if (onlyOSS) {
|
||||
productionProjects.forEach(project => {
|
||||
if (project.getBuildConfig().oss === false) {
|
||||
productionProjects.delete(project.json.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return productionProjects;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ import { linkProjectExecutables } from '../utils/link_project_executables';
|
|||
import { IPackageJson } from '../utils/package_json';
|
||||
import { Project } from '../utils/project';
|
||||
import { buildProjectGraph } from '../utils/projects';
|
||||
import { installInDir, runScriptInPackageStreaming } from '../utils/scripts';
|
||||
import { installInDir, runScriptInPackageStreaming, yarnWorkspacesInfo } from '../utils/scripts';
|
||||
import { BootstrapCommand } from './bootstrap';
|
||||
|
||||
const mockInstallInDir = installInDir as jest.Mock;
|
||||
const mockRunScriptInPackageStreaming = runScriptInPackageStreaming as jest.Mock;
|
||||
const mockLinkProjectExecutables = linkProjectExecutables as jest.Mock;
|
||||
const mockYarnWorkspacesInfo = yarnWorkspacesInfo as jest.Mock;
|
||||
|
||||
const createProject = (packageJson: IPackageJson, path = '.') => {
|
||||
const project = new Project(
|
||||
|
@ -57,6 +58,10 @@ const noop = () => {
|
|||
// noop
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockYarnWorkspacesInfo.mockResolvedValue({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
|
|
|
@ -27,7 +27,7 @@ export interface IProjectPathOptions {
|
|||
/**
|
||||
* Returns all the paths where plugins are located
|
||||
*/
|
||||
export function getProjectPaths(rootPath: string, options: IProjectPathOptions) {
|
||||
export function getProjectPaths(rootPath: string, options: IProjectPathOptions = {}) {
|
||||
const skipKibanaPlugins = Boolean(options['skip-kibana-plugins']);
|
||||
const ossOnly = Boolean(options.oss);
|
||||
|
||||
|
|
|
@ -19,4 +19,7 @@
|
|||
|
||||
export { run } from './cli';
|
||||
export { buildProductionProjects, prepareExternalProjectDependencies } from './production';
|
||||
export { getProjects } from './utils/projects';
|
||||
export { Project } from './utils/project';
|
||||
export { copyWorkspacePackages } from './utils/workspaces';
|
||||
export { getProjectPaths } from './config';
|
||||
|
|
|
@ -35,12 +35,14 @@ import {
|
|||
|
||||
export async function buildProductionProjects({
|
||||
kibanaRoot,
|
||||
buildRoots,
|
||||
buildRoot,
|
||||
onlyOSS,
|
||||
}: {
|
||||
kibanaRoot: string;
|
||||
buildRoots: string[];
|
||||
buildRoot: string;
|
||||
onlyOSS?: boolean;
|
||||
}) {
|
||||
const projects = await getProductionProjects(kibanaRoot);
|
||||
const projects = await getProductionProjects(kibanaRoot, onlyOSS);
|
||||
const projectGraph = buildProjectGraph(projects);
|
||||
const batchedProjects = topologicallyBatchProjects(projects, projectGraph);
|
||||
|
||||
|
@ -51,9 +53,7 @@ export async function buildProductionProjects({
|
|||
for (const project of batch) {
|
||||
await deleteTarget(project);
|
||||
await buildProject(project);
|
||||
for (const buildRoot of buildRoots) {
|
||||
await copyToBuild(project, kibanaRoot, buildRoot);
|
||||
}
|
||||
await copyToBuild(project, kibanaRoot, buildRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,19 +62,33 @@ export async function buildProductionProjects({
|
|||
* Returns the subset of projects that should be built into the production
|
||||
* bundle. As we copy these into Kibana's `node_modules` during the build step,
|
||||
* and let Kibana's build process be responsible for installing dependencies,
|
||||
* we only include Kibana's transitive _production_ dependencies.
|
||||
* we only include Kibana's transitive _production_ dependencies. If onlyOSS
|
||||
* is supplied, we omit projects with build.oss in their package.json set to false.
|
||||
*/
|
||||
async function getProductionProjects(rootPath: string) {
|
||||
async function getProductionProjects(rootPath: string, onlyOSS?: boolean) {
|
||||
const projectPaths = getProjectPaths(rootPath, {});
|
||||
const projects = await getProjects(rootPath, projectPaths);
|
||||
const projectsSubset = [projects.get('kibana')!];
|
||||
|
||||
const productionProjects = includeTransitiveProjects([projects.get('kibana')!], projects, {
|
||||
if (projects.has('x-pack')) {
|
||||
projectsSubset.push(projects.get('x-pack')!);
|
||||
}
|
||||
|
||||
const productionProjects = includeTransitiveProjects(projectsSubset, projects, {
|
||||
onlyProductionDependencies: true,
|
||||
});
|
||||
|
||||
// We remove Kibana, as we're already building Kibana
|
||||
productionProjects.delete('kibana');
|
||||
|
||||
if (onlyOSS) {
|
||||
productionProjects.forEach(project => {
|
||||
if (project.getBuildConfig().oss === false) {
|
||||
productionProjects.delete(project.json.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return productionProjects;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"main": "./target/index.js",
|
||||
"kibana": {
|
||||
"build": {
|
||||
"oss": false
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/bar": "link:../bar"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`kbn-pm production builds and copies only OSS projects for production 1`] = `
|
||||
Array [
|
||||
"packages/bar/package.json",
|
||||
"packages/bar/src/index.js",
|
||||
"packages/bar/target/index.js",
|
||||
"packages/bar/yarn.lock",
|
||||
"packages/baz/index.js",
|
||||
"packages/baz/package.json",
|
||||
"packages/quux/index.js",
|
||||
"packages/quux/package.json",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`kbn-pm production builds and copies projects for production 1`] = `
|
||||
Array [
|
||||
"packages/bar/package.json",
|
||||
|
@ -53,6 +66,11 @@ Object {
|
|||
"@babel/preset-env": "^7.3.4",
|
||||
"moment": "2.20.1",
|
||||
},
|
||||
"kibana": Object {
|
||||
"build": Object {
|
||||
"oss": false,
|
||||
},
|
||||
},
|
||||
"main": "./target/index.js",
|
||||
"name": "@elastic/foo",
|
||||
"private": true,
|
||||
|
|
|
@ -27,31 +27,38 @@ import { getProjects } from '../../utils/projects';
|
|||
import { buildProductionProjects } from '../build_production_projects';
|
||||
|
||||
describe('kbn-pm production', () => {
|
||||
let tmpDir: string;
|
||||
let buildRoot: string;
|
||||
|
||||
const timeout = 1 * 60 * 1000;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = tempy.directory();
|
||||
buildRoot = tempy.directory();
|
||||
const fixturesPath = resolve(__dirname, '__fixtures__');
|
||||
|
||||
// Copy all the test fixtures into a tmp dir, as we will be mutating them
|
||||
await copy(['**/*'], tmpDir, {
|
||||
cwd: fixturesPath,
|
||||
dot: true,
|
||||
nodir: true,
|
||||
parents: true,
|
||||
});
|
||||
|
||||
const projects = await getProjects(tmpDir, ['.', './packages/*']);
|
||||
|
||||
for (const project of projects.values()) {
|
||||
// This will both install dependencies and generate `yarn.lock` files
|
||||
await project.installDependencies({
|
||||
extraArgs: ['--silent', '--no-progress'],
|
||||
});
|
||||
}
|
||||
}, timeout);
|
||||
|
||||
test(
|
||||
'builds and copies projects for production',
|
||||
async () => {
|
||||
const tmpDir = tempy.directory();
|
||||
const buildRoot = tempy.directory();
|
||||
const fixturesPath = resolve(__dirname, '__fixtures__');
|
||||
|
||||
// Copy all the test fixtures into a tmp dir, as we will be mutating them
|
||||
await copy(['**/*'], tmpDir, {
|
||||
cwd: fixturesPath,
|
||||
dot: true,
|
||||
nodir: true,
|
||||
parents: true,
|
||||
});
|
||||
|
||||
const projects = await getProjects(tmpDir, ['.', './packages/*']);
|
||||
|
||||
for (const project of projects.values()) {
|
||||
// This will both install dependencies and generate `yarn.lock` files
|
||||
await project.installDependencies({
|
||||
extraArgs: ['--silent', '--no-progress'],
|
||||
});
|
||||
}
|
||||
|
||||
await buildProductionProjects({ kibanaRoot: tmpDir, buildRoots: [buildRoot] });
|
||||
await buildProductionProjects({ kibanaRoot: tmpDir, buildRoot });
|
||||
|
||||
const files = await globby(['**/*', '!**/node_modules/**'], {
|
||||
cwd: buildRoot,
|
||||
|
@ -65,6 +72,20 @@ describe('kbn-pm production', () => {
|
|||
}
|
||||
}
|
||||
},
|
||||
2 * 60 * 1000
|
||||
timeout
|
||||
);
|
||||
|
||||
test(
|
||||
'builds and copies only OSS projects for production',
|
||||
async () => {
|
||||
await buildProductionProjects({ kibanaRoot: tmpDir, buildRoot, onlyOSS: true });
|
||||
|
||||
const files = await globby(['**/*', '!**/node_modules/**'], {
|
||||
cwd: buildRoot,
|
||||
});
|
||||
|
||||
expect(files.sort()).toMatchSnapshot();
|
||||
},
|
||||
timeout
|
||||
);
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ Object {
|
|||
"<repoRoot>/packages/kbn-pm/src/utils/bar/bin/bar.js",
|
||||
],
|
||||
],
|
||||
"isSymlink": Array [],
|
||||
"mkdirp": Array [],
|
||||
"readFile": Array [],
|
||||
"unlink": Array [],
|
||||
|
@ -54,6 +55,7 @@ Object {
|
|||
"<repoRoot>/packages/kbn-pm/src/utils/bar/bin/bar.js",
|
||||
],
|
||||
],
|
||||
"isSymlink": Array [],
|
||||
"mkdirp": Array [
|
||||
Array [
|
||||
"<repoRoot>/packages/kbn-pm/src/utils/foo/node_modules/.bin",
|
||||
|
|
|
@ -33,8 +33,8 @@ function generateColors() {
|
|||
|
||||
export function spawn(command: string, args: string[], opts: execa.Options) {
|
||||
return execa(command, args, {
|
||||
...opts,
|
||||
stdio: 'inherit',
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,8 @@ export function spawnStreaming(
|
|||
{ prefix }: { prefix: string }
|
||||
) {
|
||||
const spawned = execa(command, args, {
|
||||
...opts,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
...opts,
|
||||
});
|
||||
|
||||
const color = nextColor();
|
||||
|
|
|
@ -24,7 +24,7 @@ import { ncp } from 'ncp';
|
|||
import { dirname, relative } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const stat = promisify(fs.stat);
|
||||
const lstat = promisify(fs.lstat);
|
||||
const readFile = promisify(fs.readFile);
|
||||
const symlink = promisify(fs.symlink);
|
||||
const chmod = promisify(fs.chmod);
|
||||
|
@ -37,7 +37,7 @@ export { chmod, readFile, mkdirp };
|
|||
|
||||
async function statTest(path: string, block: (stats: fs.Stats) => boolean) {
|
||||
try {
|
||||
return block(await stat(path));
|
||||
return block(await lstat(path));
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
return false;
|
||||
|
@ -46,6 +46,14 @@ async function statTest(path: string, block: (stats: fs.Stats) => boolean) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a path points to a symlink.
|
||||
* @param path
|
||||
*/
|
||||
export async function isSymlink(path: string) {
|
||||
return await statTest(path, stats => stats.isSymbolicLink());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a path points to a directory.
|
||||
* @param path
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs';
|
||||
import { relative, resolve as resolvePath } from 'path';
|
||||
import { inspect } from 'util';
|
||||
|
||||
|
@ -30,11 +31,17 @@ import {
|
|||
isLinkDependency,
|
||||
readPackageJson,
|
||||
} from './package_json';
|
||||
import { installInDir, runScriptInPackage, runScriptInPackageStreaming } from './scripts';
|
||||
import {
|
||||
installInDir,
|
||||
runScriptInPackage,
|
||||
runScriptInPackageStreaming,
|
||||
yarnWorkspacesInfo,
|
||||
} from './scripts';
|
||||
|
||||
interface BuildConfig {
|
||||
skip?: boolean;
|
||||
intermediateBuildDirectory?: string;
|
||||
oss?: boolean;
|
||||
}
|
||||
|
||||
interface CleanConfig {
|
||||
|
@ -190,7 +197,41 @@ export class Project {
|
|||
|
||||
public async installDependencies({ extraArgs }: { extraArgs: string[] }) {
|
||||
log.write(chalk.bold(`\n\nInstalling dependencies in [${chalk.green(this.name)}]:\n`));
|
||||
return installInDir(this.path, extraArgs);
|
||||
await installInDir(this.path, extraArgs);
|
||||
await this.removeExtraneousNodeModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Yarn workspaces symlinks workspace projects to the root node_modules, even
|
||||
* when there is no depenency on the project. This results in unnecicary, and
|
||||
* often duplicated code in the build archives.
|
||||
*/
|
||||
public async removeExtraneousNodeModules() {
|
||||
// this is only relevant for the root workspace
|
||||
if (!this.isWorkspaceRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspacesInfo = await yarnWorkspacesInfo(this.path);
|
||||
const unusedWorkspaces = new Set(Object.keys(workspacesInfo));
|
||||
|
||||
// check for any cross-project dependency
|
||||
for (const name of Object.keys(workspacesInfo)) {
|
||||
const workspace = workspacesInfo[name];
|
||||
workspace.workspaceDependencies.forEach(w => unusedWorkspaces.delete(w));
|
||||
}
|
||||
|
||||
unusedWorkspaces.forEach(name => {
|
||||
const { dependencies, devDependencies } = this.json;
|
||||
const nodeModulesPath = resolvePath(this.nodeModulesLocation, name);
|
||||
const isDependency = dependencies && dependencies.hasOwnProperty(name);
|
||||
const isDevDependency = devDependencies && devDependencies.hasOwnProperty(name);
|
||||
|
||||
if (!isDependency && !isDevDependency && fs.existsSync(nodeModulesPath)) {
|
||||
log.write(`No dependency on ${name}, removing link in node_modules`);
|
||||
fs.unlinkSync(nodeModulesPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,15 @@
|
|||
import { spawn, spawnStreaming } from './child_process';
|
||||
import { Project } from './project';
|
||||
|
||||
interface WorkspaceInfo {
|
||||
location: string;
|
||||
workspaceDependencies: string[];
|
||||
}
|
||||
|
||||
interface WorkspacesInfo {
|
||||
[s: string]: WorkspaceInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install all dependencies in the given directory
|
||||
*/
|
||||
|
@ -56,3 +65,13 @@ export function runScriptInPackageStreaming(script: string, args: string[], pkg:
|
|||
prefix: pkg.name,
|
||||
});
|
||||
}
|
||||
|
||||
export async function yarnWorkspacesInfo(directory: string): Promise<WorkspacesInfo> {
|
||||
const workspacesInfo = await spawn('yarn', ['workspaces', 'info', '--json'], {
|
||||
cwd: directory,
|
||||
stdio: 'pipe',
|
||||
});
|
||||
|
||||
const stdout = JSON.parse(workspacesInfo.stdout);
|
||||
return JSON.parse(stdout.data);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import path from 'path';
|
|||
import { promisify } from 'util';
|
||||
|
||||
import { getProjectPaths } from '../config';
|
||||
import { copyDirectory, unlink } from './fs';
|
||||
import { copyDirectory, isSymlink, unlink } from './fs';
|
||||
import { readPackageJson } from './package_json';
|
||||
import { getProjects } from './projects';
|
||||
|
||||
|
@ -56,29 +56,22 @@ export async function workspacePackagePaths(rootPath: string): Promise<string[]>
|
|||
}
|
||||
|
||||
export async function copyWorkspacePackages(rootPath: string): Promise<void> {
|
||||
const workspaceProjects = await getWorkspaceProjects(rootPath);
|
||||
|
||||
for (const project of workspaceProjects.values()) {
|
||||
const dest = path.resolve(rootPath, 'node_modules', project.name);
|
||||
|
||||
// Remove the symlink
|
||||
await unlink(dest);
|
||||
// Copy in the package
|
||||
await copyDirectory(project.path, dest);
|
||||
}
|
||||
}
|
||||
|
||||
async function getWorkspaceProjects(rootPath: string) {
|
||||
const projectPaths = getProjectPaths(rootPath, {});
|
||||
const projects = await getProjects(rootPath, projectPaths);
|
||||
|
||||
for (const [key, project] of projects.entries()) {
|
||||
if (!project.isWorkspaceProject) {
|
||||
projects.delete(key);
|
||||
}
|
||||
}
|
||||
for (const project of projects.values()) {
|
||||
const dest = path.resolve(rootPath, 'node_modules', project.name);
|
||||
|
||||
return projects;
|
||||
if ((await isSymlink(dest)) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the symlink
|
||||
await unlink(dest);
|
||||
|
||||
// Copy in the package
|
||||
await copyDirectory(project.path, dest);
|
||||
}
|
||||
}
|
||||
|
||||
function packagesFromGlobPattern({ pattern, rootPath }: { pattern: string; rootPath: string }) {
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { statSync, lstatSync, realpathSync } from 'fs';
|
||||
import { statSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { fromRoot } from '../../legacy/utils';
|
||||
import { fromRoot, IS_KIBANA_DISTRIBUTABLE } from '../../legacy/utils';
|
||||
import { getConfig } from '../../legacy/server/path';
|
||||
import { bootstrap } from '../../core/server';
|
||||
import { readKeystore } from './read_keystore';
|
||||
|
@ -41,17 +41,6 @@ function canRequire(path) {
|
|||
}
|
||||
}
|
||||
|
||||
function isSymlinkTo(link, dest) {
|
||||
try {
|
||||
const stat = lstatSync(link);
|
||||
return stat.isSymbolicLink() && realpathSync(link) === dest;
|
||||
} catch (error) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CLUSTER_MANAGER_PATH = resolve(__dirname, '../cluster/cluster_manager');
|
||||
const CAN_CLUSTER = canRequire(CLUSTER_MANAGER_PATH);
|
||||
|
||||
|
@ -60,10 +49,8 @@ const CAN_REPL = canRequire(REPL_PATH);
|
|||
|
||||
// xpack is installed in both dev and the distributable, it's optional if
|
||||
// install is a link to the source, not an actual install
|
||||
const XPACK_INSTALLED_DIR = resolve(__dirname, '../../../node_modules/x-pack');
|
||||
const XPACK_SOURCE_DIR = resolve(__dirname, '../../../x-pack');
|
||||
const XPACK_INSTALLED = canRequire(XPACK_INSTALLED_DIR);
|
||||
const XPACK_OPTIONAL = isSymlinkTo(XPACK_INSTALLED_DIR, XPACK_SOURCE_DIR);
|
||||
const XPACK_DIR = resolve(__dirname, '../../../x-pack');
|
||||
const XPACK_INSTALLED = canRequire(XPACK_DIR);
|
||||
|
||||
const pathCollector = function () {
|
||||
const paths = [];
|
||||
|
@ -127,8 +114,8 @@ function applyConfigOverrides(rawConfig, opts, extraCliOptions) {
|
|||
get('plugins.paths'),
|
||||
opts.pluginPath,
|
||||
|
||||
XPACK_INSTALLED && (!XPACK_OPTIONAL || !opts.oss)
|
||||
? [XPACK_INSTALLED_DIR]
|
||||
XPACK_INSTALLED && !opts.oss
|
||||
? [XPACK_DIR]
|
||||
: [],
|
||||
)));
|
||||
|
||||
|
@ -183,7 +170,7 @@ export default function (program) {
|
|||
command.option('--repl', 'Run the server with a REPL prompt and access to the server object');
|
||||
}
|
||||
|
||||
if (XPACK_OPTIONAL) {
|
||||
if (!IS_KIBANA_DISTRIBUTABLE) {
|
||||
command
|
||||
.option('--oss', 'Start Kibana without X-Pack');
|
||||
}
|
||||
|
@ -226,7 +213,7 @@ export default function (program) {
|
|||
},
|
||||
features: {
|
||||
isClusterModeSupported: CAN_CLUSTER,
|
||||
isOssModeSupported: XPACK_OPTIONAL,
|
||||
isOssModeSupported: !IS_KIBANA_DISTRIBUTABLE,
|
||||
isXPackInstalled: XPACK_INSTALLED,
|
||||
isReplModeSupported: CAN_REPL,
|
||||
},
|
||||
|
|
|
@ -17,15 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export function isOSS() {
|
||||
try {
|
||||
require.resolve('x-pack');
|
||||
return false;
|
||||
} catch (error) {
|
||||
if (error.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error;
|
||||
}
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
return true;
|
||||
}
|
||||
export function isOSS() {
|
||||
return !fs.existsSync(path.resolve(__dirname, '../../../x-pack'));
|
||||
}
|
||||
|
|
|
@ -176,15 +176,15 @@ export interface OverlaySetup {
|
|||
}
|
||||
|
||||
// @public
|
||||
export interface Plugin<TSetup, TDependencies extends Record<string, unknown> = {}> {
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<string, unknown> = {}> {
|
||||
// (undocumented)
|
||||
setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise<TSetup>;
|
||||
setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
// (undocumented)
|
||||
stop?: () => void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type PluginInitializer<TSetup, TDependencies extends Record<string, unknown> = {}> = (core: PluginInitializerContext) => Plugin<TSetup, TDependencies>;
|
||||
export type PluginInitializer<TSetup, TPluginsSetup extends Record<string, unknown> = {}> = (core: PluginInitializerContext) => Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
// @public
|
||||
export interface PluginInitializerContext {
|
||||
|
|
|
@ -26,8 +26,8 @@ import { loadPluginBundle } from './plugin_loader';
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export interface Plugin<TSetup, TDependencies extends Record<string, unknown> = {}> {
|
||||
setup: (core: PluginSetupContext, dependencies: TDependencies) => TSetup | Promise<TSetup>;
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<string, unknown> = {}> {
|
||||
setup: (core: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
stop?: () => void;
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,9 @@ export interface Plugin<TSetup, TDependencies extends Record<string, unknown> =
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginInitializer<TSetup, TDependencies extends Record<string, unknown> = {}> = (
|
||||
export type PluginInitializer<TSetup, TPluginsSetup extends Record<string, unknown> = {}> = (
|
||||
core: PluginInitializerContext
|
||||
) => Plugin<TSetup, TDependencies>;
|
||||
) => Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
/**
|
||||
* Lightweight wrapper around discovered plugin that is responsible for instantiating
|
||||
|
@ -49,14 +49,14 @@ export type PluginInitializer<TSetup, TDependencies extends Record<string, unkno
|
|||
*/
|
||||
export class PluginWrapper<
|
||||
TSetup = unknown,
|
||||
TDependenciesSetup extends Record<PluginName, unknown> = Record<PluginName, unknown>
|
||||
TPluginsSetup extends Record<PluginName, unknown> = Record<PluginName, unknown>
|
||||
> {
|
||||
public readonly name: DiscoveredPlugin['id'];
|
||||
public readonly configPath: DiscoveredPlugin['configPath'];
|
||||
public readonly requiredDependencies: DiscoveredPlugin['requiredPlugins'];
|
||||
public readonly optionalDependencies: DiscoveredPlugin['optionalPlugins'];
|
||||
private initializer?: PluginInitializer<TSetup, TDependenciesSetup>;
|
||||
private instance?: Plugin<TSetup, TDependenciesSetup>;
|
||||
public readonly requiredPlugins: DiscoveredPlugin['requiredPlugins'];
|
||||
public readonly optionalPlugins: DiscoveredPlugin['optionalPlugins'];
|
||||
private initializer?: PluginInitializer<TSetup, TPluginsSetup>;
|
||||
private instance?: Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
constructor(
|
||||
readonly discoveredPlugin: DiscoveredPlugin,
|
||||
|
@ -64,8 +64,8 @@ export class PluginWrapper<
|
|||
) {
|
||||
this.name = discoveredPlugin.id;
|
||||
this.configPath = discoveredPlugin.configPath;
|
||||
this.requiredDependencies = discoveredPlugin.requiredPlugins;
|
||||
this.optionalDependencies = discoveredPlugin.optionalPlugins;
|
||||
this.requiredPlugins = discoveredPlugin.requiredPlugins;
|
||||
this.optionalPlugins = discoveredPlugin.optionalPlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,20 +74,20 @@ export class PluginWrapper<
|
|||
* @param addBasePath Function that adds the base path to a string for plugin bundle path.
|
||||
*/
|
||||
public async load(addBasePath: (path: string) => string) {
|
||||
this.initializer = await loadPluginBundle<TSetup, TDependenciesSetup>(addBasePath, this.name);
|
||||
this.initializer = await loadPluginBundle<TSetup, TPluginsSetup>(addBasePath, this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates plugin and calls `setup` function exposed by the plugin initializer.
|
||||
* @param setupContext Context that consists of various core services tailored specifically
|
||||
* for the `setup` lifecycle event.
|
||||
* @param dependencies The dictionary where the key is the dependency name and the value
|
||||
* @param plugins The dictionary where the key is the dependency name and the value
|
||||
* is the contract returned by the dependency's `setup` function.
|
||||
*/
|
||||
public async setup(setupContext: PluginSetupContext, dependencies: TDependenciesSetup) {
|
||||
public async setup(setupContext: PluginSetupContext, plugins: TPluginsSetup) {
|
||||
this.instance = await this.createPluginInstance();
|
||||
|
||||
return await this.instance.setup(setupContext, dependencies);
|
||||
return await this.instance.setup(setupContext, plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -62,34 +62,35 @@ export class PluginsService implements CoreService<PluginsServiceSetup> {
|
|||
// Load plugin bundles
|
||||
await this.loadPluginBundles(deps.basePath.addToPath);
|
||||
|
||||
// Setup each plugin with correct dependencies
|
||||
// Setup each plugin with required and optional plugin contracts
|
||||
const contracts = new Map<string, unknown>();
|
||||
for (const [pluginName, plugin] of this.plugins.entries()) {
|
||||
const dependencies = new Set([
|
||||
...plugin.requiredDependencies,
|
||||
...plugin.optionalDependencies.filter(optPlugin => this.plugins.get(optPlugin)),
|
||||
const pluginDeps = new Set([
|
||||
...plugin.requiredPlugins,
|
||||
...plugin.optionalPlugins.filter(optPlugin => this.plugins.get(optPlugin)),
|
||||
]);
|
||||
|
||||
const dependencyContracts = [...dependencies.keys()].reduce(
|
||||
(depContracts, dependency) => {
|
||||
const pluginDepContracts = [...pluginDeps.keys()].reduce(
|
||||
(depContracts, dependencyName) => {
|
||||
// Only set if present. Could be absent if plugin does not have client-side code or is a
|
||||
// missing optional dependency.
|
||||
if (contracts.get(dependency) !== undefined) {
|
||||
depContracts[dependency] = contracts.get(dependency);
|
||||
// missing optional plugin.
|
||||
if (contracts.has(dependencyName)) {
|
||||
depContracts[dependencyName] = contracts.get(dependencyName);
|
||||
}
|
||||
|
||||
return depContracts;
|
||||
},
|
||||
{} as { [dep: string]: unknown }
|
||||
{} as Record<PluginName, unknown>
|
||||
);
|
||||
|
||||
contracts.set(
|
||||
pluginName,
|
||||
await plugin.setup(
|
||||
createPluginSetupContext(this.coreContext, deps, plugin),
|
||||
dependencyContracts
|
||||
pluginDepContracts
|
||||
)
|
||||
);
|
||||
|
||||
this.satupPlugins.push(pluginName);
|
||||
}
|
||||
|
||||
|
@ -98,7 +99,7 @@ export class PluginsService implements CoreService<PluginsServiceSetup> {
|
|||
}
|
||||
|
||||
public async stop() {
|
||||
// Stop plugins in reverse dependency order.
|
||||
// Stop plugins in reverse topological order.
|
||||
for (const pluginName of this.satupPlugins.reverse()) {
|
||||
this.plugins.get(pluginName)!.stop();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ interface InjectedUiSettingsDefault {
|
|||
type?: string;
|
||||
readOnly?: boolean;
|
||||
options?: string[] | { [key: string]: any };
|
||||
/**
|
||||
* Whether a change in that setting will only take affect after a page reload.
|
||||
*/
|
||||
requiresPageReload?: boolean;
|
||||
}
|
||||
|
||||
// properties that come from legacyInjectedMetadata.uiSettings.user
|
||||
|
|
|
@ -25,7 +25,7 @@ import { distinctUntilChanged, first, map } from 'rxjs/operators';
|
|||
import { Config, ConfigPath, ConfigWithSchema, Env } from '.';
|
||||
import { Logger, LoggerFactory } from '../logging';
|
||||
|
||||
/** @internal */
|
||||
/** @public */
|
||||
export class ConfigService {
|
||||
private readonly log: Logger;
|
||||
|
||||
|
@ -37,7 +37,7 @@ export class ConfigService {
|
|||
|
||||
constructor(
|
||||
private readonly config$: Observable<Config>,
|
||||
readonly env: Env,
|
||||
private readonly env: Env,
|
||||
logger: LoggerFactory
|
||||
) {
|
||||
this.log = logger.get('config');
|
||||
|
@ -55,8 +55,8 @@ export class ConfigService {
|
|||
* Reads the subset of the config at the specified `path` and validates it
|
||||
* against the static `schema` on the given `ConfigClass`.
|
||||
*
|
||||
* @param path The path to the desired subset of the config.
|
||||
* @param ConfigClass A class (not an instance of a class) that contains a
|
||||
* @param path - The path to the desired subset of the config.
|
||||
* @param ConfigClass - A class (not an instance of a class) that contains a
|
||||
* static `schema` that we validate the config at the given `path` against.
|
||||
*/
|
||||
public atPath<TSchema extends Type<any>, TConfig>(
|
||||
|
@ -72,7 +72,7 @@ export class ConfigService {
|
|||
* Same as `atPath`, but returns `undefined` if there is no config at the
|
||||
* specified path.
|
||||
*
|
||||
* @see atPath
|
||||
* {@link ConfigService.atPath}
|
||||
*/
|
||||
public optionalAtPath<TSchema extends Type<any>, TConfig>(
|
||||
path: ConfigPath,
|
||||
|
|
|
@ -26,12 +26,14 @@ import { ClusterClient } from './cluster_client';
|
|||
import { ElasticsearchClientConfig } from './elasticsearch_client_config';
|
||||
import { ElasticsearchConfig } from './elasticsearch_config';
|
||||
|
||||
/** @internal */
|
||||
interface CoreClusterClients {
|
||||
config: ElasticsearchConfig;
|
||||
adminClient: ClusterClient;
|
||||
dataClient: ClusterClient;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface ElasticsearchServiceSetup {
|
||||
// Required for the BWC with the legacy Kibana only.
|
||||
readonly legacy: {
|
||||
|
|
|
@ -21,6 +21,7 @@ import { HttpServiceSetup } from './http';
|
|||
import { PluginsServiceSetup } from './plugins';
|
||||
|
||||
export { bootstrap } from './bootstrap';
|
||||
export { ConfigService } from './config';
|
||||
export {
|
||||
CallAPIOptions,
|
||||
ClusterClient,
|
||||
|
@ -30,8 +31,11 @@ export {
|
|||
APICaller,
|
||||
} from './elasticsearch';
|
||||
export { Logger, LoggerFactory, LogMeta, LogRecord, LogLevel } from './logging';
|
||||
|
||||
export {
|
||||
DiscoveredPlugin,
|
||||
Plugin,
|
||||
PluginInitializer,
|
||||
PluginInitializerContext,
|
||||
PluginName,
|
||||
PluginSetupContext,
|
||||
|
@ -43,3 +47,5 @@ export interface CoreSetup {
|
|||
elasticsearch: ElasticsearchServiceSetup;
|
||||
plugins: PluginsServiceSetup;
|
||||
}
|
||||
|
||||
export { ElasticsearchServiceSetup, HttpServiceSetup, PluginsServiceSetup };
|
||||
|
|
|
@ -38,16 +38,34 @@ export class ClusterClient {
|
|||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface CoreSetup {
|
||||
// Warning: (ae-forgotten-export) The symbol "ElasticsearchServiceSetup" needs to be exported by the entry point index.d.ts
|
||||
export class ConfigService {
|
||||
// Warning: (ae-forgotten-export) The symbol "Config" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "Env" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
constructor(config$: Observable<Config>, env: Env, logger: LoggerFactory);
|
||||
// Warning: (ae-forgotten-export) The symbol "ConfigPath" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "ConfigWithSchema" needs to be exported by the entry point index.d.ts
|
||||
atPath<TSchema extends Type<any>, TConfig>(path: ConfigPath, ConfigClass: ConfigWithSchema<TSchema, TConfig>): Observable<TConfig>;
|
||||
getConfig$(): Observable<Config>;
|
||||
// (undocumented)
|
||||
getUnusedPaths(): Promise<string[]>;
|
||||
// (undocumented)
|
||||
getUsedPaths(): Promise<string[]>;
|
||||
// (undocumented)
|
||||
isEnabledAtPath(path: ConfigPath): Promise<boolean>;
|
||||
optionalAtPath<TSchema extends Type<any>, TConfig>(path: ConfigPath, ConfigClass: ConfigWithSchema<TSchema, TConfig>): Observable<TConfig | undefined>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface CoreSetup {
|
||||
// (undocumented)
|
||||
elasticsearch: ElasticsearchServiceSetup;
|
||||
// Warning: (ae-forgotten-export) The symbol "HttpServiceSetup" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-incompatible-release-tags) The symbol "http" is marked as @public, but its signature references "HttpServiceSetup" which is marked as @internal
|
||||
//
|
||||
// (undocumented)
|
||||
http: HttpServiceSetup;
|
||||
// Warning: (ae-forgotten-export) The symbol "PluginsServiceSetup" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-incompatible-release-tags) The symbol "plugins" is marked as @public, but its signature references "PluginsServiceSetup" which is marked as @internal
|
||||
//
|
||||
// (undocumented)
|
||||
plugins: PluginsServiceSetup;
|
||||
|
@ -57,7 +75,6 @@ export interface CoreSetup {
|
|||
//
|
||||
// @internal
|
||||
export interface DiscoveredPlugin {
|
||||
// Warning: (ae-forgotten-export) The symbol "ConfigPath" needs to be exported by the entry point index.d.ts
|
||||
readonly configPath: ConfigPath;
|
||||
readonly id: PluginName;
|
||||
readonly optionalPlugins: ReadonlyArray<PluginName>;
|
||||
|
@ -74,9 +91,29 @@ export type ElasticsearchClientConfig = Pick<ConfigOptions, 'keepAlive' | 'log'
|
|||
ssl?: Partial<ElasticsearchConfig['ssl']>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ElasticsearchServiceSetup {
|
||||
// (undocumented)
|
||||
readonly adminClient$: Observable<ClusterClient>;
|
||||
// (undocumented)
|
||||
readonly createClient: (type: string, config: ElasticsearchClientConfig) => ClusterClient;
|
||||
// (undocumented)
|
||||
readonly dataClient$: Observable<ClusterClient>;
|
||||
// (undocumented)
|
||||
readonly legacy: {
|
||||
readonly config$: Observable<ElasticsearchConfig>;
|
||||
};
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type Headers = Record<string, string | string[] | undefined>;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "HttpServerInfo" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-internal-missing-underscore) The name HttpServiceSetup should be prefixed with an underscore because the declaration is marked as "@internal"
|
||||
//
|
||||
// @internal (undocumented)
|
||||
export type HttpServiceSetup = HttpServerInfo;
|
||||
|
||||
// @public
|
||||
export interface Logger {
|
||||
debug(message: string, meta?: LogMeta): void;
|
||||
|
@ -150,6 +187,17 @@ export interface LogRecord {
|
|||
timestamp: Date;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<PluginName, unknown> = {}> {
|
||||
// (undocumented)
|
||||
setup: (pluginSetupContext: PluginSetupContext, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
// (undocumented)
|
||||
stop?: () => void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type PluginInitializer<TSetup, TPluginsSetup extends Record<PluginName, unknown> = {}> = (coreContext: PluginInitializerContext) => Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
// @public
|
||||
export interface PluginInitializerContext {
|
||||
// (undocumented)
|
||||
|
@ -177,6 +225,19 @@ export interface PluginSetupContext {
|
|||
};
|
||||
}
|
||||
|
||||
// Warning: (ae-internal-missing-underscore) The name PluginsServiceSetup should be prefixed with an underscore because the declaration is marked as "@internal"
|
||||
//
|
||||
// @internal (undocumented)
|
||||
export interface PluginsServiceSetup {
|
||||
// (undocumented)
|
||||
contracts: Map<PluginName, unknown>;
|
||||
// (undocumented)
|
||||
uiPlugins: {
|
||||
public: Map<PluginName, DiscoveredPlugin>;
|
||||
internal: Map<PluginName, DiscoveredPluginInternal>;
|
||||
};
|
||||
}
|
||||
|
||||
// @public
|
||||
export class ScopedClusterClient {
|
||||
// (undocumented)
|
||||
|
@ -189,7 +250,7 @@ export class ScopedClusterClient {
|
|||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/core/server/plugins/plugin_context.ts:35:9 - (ae-forgotten-export) The symbol "EnvironmentMode" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/plugin_context.ts:39:9 - (ae-forgotten-export) The symbol "ConfigWithSchema" needs to be exported by the entry point index.d.ts
|
||||
// src/core/server/plugins/plugins_service.ts:33:24 - (ae-forgotten-export) The symbol "DiscoveredPluginInternal" needs to be exported by the entry point index.d.ts
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import { first, map, toArray } from 'rxjs/operators';
|
|||
import { Config, ConfigService, Env, ObjectToConfigAdapter } from '../../config';
|
||||
import { getEnvOptions } from '../../config/__mocks__/env';
|
||||
import { loggingServiceMock } from '../../logging/logging_service.mock';
|
||||
import { Plugin } from '../plugin';
|
||||
import { PluginWrapper } from '../plugin';
|
||||
import { PluginsConfig } from '../plugins_config';
|
||||
import { discover } from './plugins_discovery';
|
||||
|
||||
|
@ -142,10 +142,10 @@ test('properly iterates through plugin search locations', async () => {
|
|||
TEST_EXTRA_PLUGIN_PATH,
|
||||
]) {
|
||||
const discoveredPlugin = plugins.find(plugin => plugin.path === path)!;
|
||||
expect(discoveredPlugin).toBeInstanceOf(Plugin);
|
||||
expect(discoveredPlugin).toBeInstanceOf(PluginWrapper);
|
||||
expect(discoveredPlugin.configPath).toEqual(['core', 'config']);
|
||||
expect(discoveredPlugin.requiredDependencies).toEqual(['a', 'b']);
|
||||
expect(discoveredPlugin.optionalDependencies).toEqual(['c', 'd']);
|
||||
expect(discoveredPlugin.requiredPlugins).toEqual(['a', 'b']);
|
||||
expect(discoveredPlugin.optionalPlugins).toEqual(['c', 'd']);
|
||||
}
|
||||
|
||||
await expect(
|
||||
|
|
|
@ -23,7 +23,7 @@ import { bindNodeCallback, from, merge } from 'rxjs';
|
|||
import { catchError, filter, map, mergeMap, shareReplay } from 'rxjs/operators';
|
||||
import { CoreContext } from '../../core_context';
|
||||
import { Logger } from '../../logging';
|
||||
import { Plugin } from '../plugin';
|
||||
import { PluginWrapper } from '../plugin';
|
||||
import { createPluginInitializerContext } from '../plugin_context';
|
||||
import { PluginsConfig } from '../plugins_config';
|
||||
import { PluginDiscoveryError } from './plugin_discovery_error';
|
||||
|
@ -67,9 +67,11 @@ export function discover(config: PluginsConfig, coreContext: CoreContext) {
|
|||
);
|
||||
|
||||
return {
|
||||
plugin$: discoveryResults$.pipe(filter((entry): entry is Plugin => entry instanceof Plugin)),
|
||||
plugin$: discoveryResults$.pipe(
|
||||
filter((entry): entry is PluginWrapper => entry instanceof PluginWrapper)
|
||||
),
|
||||
error$: discoveryResults$.pipe(
|
||||
filter((entry): entry is PluginDiscoveryError => !(entry instanceof Plugin))
|
||||
filter((entry): entry is PluginDiscoveryError => !(entry instanceof PluginWrapper))
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -115,7 +117,11 @@ function createPlugin$(path: string, log: Logger, coreContext: CoreContext) {
|
|||
return from(parseManifest(path, coreContext.env.packageInfo)).pipe(
|
||||
map(manifest => {
|
||||
log.debug(`Successfully discovered plugin "${manifest.id}" at "${path}"`);
|
||||
return new Plugin(path, manifest, createPluginInitializerContext(coreContext, manifest));
|
||||
return new PluginWrapper(
|
||||
path,
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
);
|
||||
}),
|
||||
catchError(err => [err])
|
||||
);
|
||||
|
|
|
@ -22,5 +22,11 @@ export { PluginsService, PluginsServiceSetup } from './plugins_service';
|
|||
/** @internal */
|
||||
export { isNewPlatformPlugin } from './discovery';
|
||||
/** @internal */
|
||||
export { DiscoveredPlugin, DiscoveredPluginInternal, PluginName } from './plugin';
|
||||
export {
|
||||
DiscoveredPlugin,
|
||||
DiscoveredPluginInternal,
|
||||
Plugin,
|
||||
PluginInitializer,
|
||||
PluginName,
|
||||
} from './plugin';
|
||||
export { PluginInitializerContext, PluginSetupContext } from './plugin_context';
|
||||
|
|
|
@ -25,7 +25,7 @@ import { CoreContext } from '../core_context';
|
|||
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
|
||||
import { loggingServiceMock } from '../logging/logging_service.mock';
|
||||
|
||||
import { Plugin, PluginManifest } from './plugin';
|
||||
import { PluginWrapper, PluginManifest } from './plugin';
|
||||
import { createPluginInitializerContext, createPluginSetupContext } from './plugin_context';
|
||||
|
||||
const mockPluginInitializer = jest.fn();
|
||||
|
@ -78,7 +78,7 @@ afterEach(() => {
|
|||
|
||||
test('`constructor` correctly initializes plugin instance', () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'some-plugin-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -87,13 +87,13 @@ test('`constructor` correctly initializes plugin instance', () => {
|
|||
expect(plugin.name).toBe('some-plugin-id');
|
||||
expect(plugin.configPath).toBe('path');
|
||||
expect(plugin.path).toBe('some-plugin-path');
|
||||
expect(plugin.requiredDependencies).toEqual(['some-required-dep']);
|
||||
expect(plugin.optionalDependencies).toEqual(['some-optional-dep']);
|
||||
expect(plugin.requiredPlugins).toEqual(['some-required-dep']);
|
||||
expect(plugin.optionalPlugins).toEqual(['some-optional-dep']);
|
||||
});
|
||||
|
||||
test('`setup` fails if `plugin` initializer is not exported', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-without-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -108,7 +108,7 @@ test('`setup` fails if `plugin` initializer is not exported', async () => {
|
|||
|
||||
test('`setup` fails if plugin initializer is not a function', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-wrong-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -123,7 +123,7 @@ test('`setup` fails if plugin initializer is not a function', async () => {
|
|||
|
||||
test('`setup` fails if initializer does not return object', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -140,7 +140,7 @@ test('`setup` fails if initializer does not return object', async () => {
|
|||
|
||||
test('`setup` fails if object returned from initializer does not define `setup` function', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -159,7 +159,7 @@ test('`setup` fails if object returned from initializer does not define `setup`
|
|||
test('`setup` initializes plugin and calls appropriate lifecycle hook', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const initializerContext = createPluginInitializerContext(coreContext, manifest);
|
||||
const plugin = new Plugin('plugin-with-initializer-path', manifest, initializerContext);
|
||||
const plugin = new PluginWrapper('plugin-with-initializer-path', manifest, initializerContext);
|
||||
|
||||
const mockPluginInstance = { setup: jest.fn().mockResolvedValue({ contract: 'yes' }) };
|
||||
mockPluginInitializer.mockReturnValue(mockPluginInstance);
|
||||
|
@ -177,7 +177,7 @@ test('`setup` initializes plugin and calls appropriate lifecycle hook', async ()
|
|||
|
||||
test('`stop` fails if plugin is not set up', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -194,7 +194,7 @@ test('`stop` fails if plugin is not set up', async () => {
|
|||
|
||||
test('`stop` does nothing if plugin does not define `stop` function', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
@ -208,7 +208,7 @@ test('`stop` does nothing if plugin does not define `stop` function', async () =
|
|||
|
||||
test('`stop` calls `stop` defined by the plugin instance', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const plugin = new Plugin(
|
||||
const plugin = new PluginWrapper(
|
||||
'plugin-with-initializer-path',
|
||||
manifest,
|
||||
createPluginInitializerContext(coreContext, manifest)
|
||||
|
|
|
@ -124,15 +124,28 @@ export interface DiscoveredPluginInternal extends DiscoveredPlugin {
|
|||
readonly path: string;
|
||||
}
|
||||
|
||||
type PluginInitializer<TExposedSetup, TDependenciesSetup extends Record<PluginName, unknown>> = (
|
||||
coreContext: PluginInitializerContext
|
||||
) => {
|
||||
/**
|
||||
* The interface that should be returned by a `PluginInitializer`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface Plugin<TSetup, TPluginsSetup extends Record<PluginName, unknown> = {}> {
|
||||
setup: (
|
||||
pluginSetupContext: PluginSetupContext,
|
||||
dependencies: TDependenciesSetup
|
||||
) => TExposedSetup;
|
||||
plugins: TPluginsSetup
|
||||
) => TSetup | Promise<TSetup>;
|
||||
stop?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The `plugin` export at the root of a plugin's `server` directory should conform
|
||||
* to this interface.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginInitializer<TSetup, TPluginsSetup extends Record<PluginName, unknown> = {}> = (
|
||||
coreContext: PluginInitializerContext
|
||||
) => Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
/**
|
||||
* Lightweight wrapper around discovered plugin that is responsible for instantiating
|
||||
|
@ -140,20 +153,20 @@ type PluginInitializer<TExposedSetup, TDependenciesSetup extends Record<PluginNa
|
|||
*
|
||||
* @internal
|
||||
*/
|
||||
export class Plugin<
|
||||
export class PluginWrapper<
|
||||
TSetup = unknown,
|
||||
TDependenciesSetup extends Record<PluginName, unknown> = Record<PluginName, unknown>
|
||||
TPluginsSetup extends Record<PluginName, unknown> = Record<PluginName, unknown>
|
||||
> {
|
||||
public readonly name: PluginManifest['id'];
|
||||
public readonly configPath: PluginManifest['configPath'];
|
||||
public readonly requiredDependencies: PluginManifest['requiredPlugins'];
|
||||
public readonly optionalDependencies: PluginManifest['optionalPlugins'];
|
||||
public readonly requiredPlugins: PluginManifest['requiredPlugins'];
|
||||
public readonly optionalPlugins: PluginManifest['optionalPlugins'];
|
||||
public readonly includesServerPlugin: PluginManifest['server'];
|
||||
public readonly includesUiPlugin: PluginManifest['ui'];
|
||||
|
||||
private readonly log: Logger;
|
||||
|
||||
private instance?: ReturnType<PluginInitializer<TSetup, TDependenciesSetup>>;
|
||||
private instance?: Plugin<TSetup, TPluginsSetup>;
|
||||
|
||||
constructor(
|
||||
public readonly path: string,
|
||||
|
@ -163,8 +176,8 @@ export class Plugin<
|
|||
this.log = initializerContext.logger.get();
|
||||
this.name = manifest.id;
|
||||
this.configPath = manifest.configPath;
|
||||
this.requiredDependencies = manifest.requiredPlugins;
|
||||
this.optionalDependencies = manifest.optionalPlugins;
|
||||
this.requiredPlugins = manifest.requiredPlugins;
|
||||
this.optionalPlugins = manifest.optionalPlugins;
|
||||
this.includesServerPlugin = manifest.server;
|
||||
this.includesUiPlugin = manifest.ui;
|
||||
}
|
||||
|
@ -173,15 +186,15 @@ export class Plugin<
|
|||
* Instantiates plugin and calls `setup` function exposed by the plugin initializer.
|
||||
* @param setupContext Context that consists of various core services tailored specifically
|
||||
* for the `setup` lifecycle event.
|
||||
* @param dependencies The dictionary where the key is the dependency name and the value
|
||||
* @param plugins The dictionary where the key is the dependency name and the value
|
||||
* is the contract returned by the dependency's `setup` function.
|
||||
*/
|
||||
public async setup(setupContext: PluginSetupContext, dependencies: TDependenciesSetup) {
|
||||
public async setup(setupContext: PluginSetupContext, plugins: TPluginsSetup) {
|
||||
this.instance = this.createPluginInstance();
|
||||
|
||||
this.log.info('Setting up plugin');
|
||||
|
||||
return await this.instance.setup(setupContext, dependencies);
|
||||
return await this.instance.setup(setupContext, plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,7 +224,7 @@ export class Plugin<
|
|||
}
|
||||
|
||||
const { plugin: initializer } = pluginDefinition as {
|
||||
plugin: PluginInitializer<TSetup, TDependenciesSetup>;
|
||||
plugin: PluginInitializer<TSetup, TPluginsSetup>;
|
||||
};
|
||||
if (!initializer || typeof initializer !== 'function') {
|
||||
throw new Error(`Definition of plugin "${this.name}" should be a function (${this.path}).`);
|
||||
|
|
|
@ -23,7 +23,7 @@ import { ConfigWithSchema, EnvironmentMode } from '../config';
|
|||
import { CoreContext } from '../core_context';
|
||||
import { ClusterClient } from '../elasticsearch';
|
||||
import { LoggerFactory } from '../logging';
|
||||
import { Plugin, PluginManifest } from './plugin';
|
||||
import { PluginWrapper, PluginManifest } from './plugin';
|
||||
import { PluginsServiceSetupDeps } from './plugins_service';
|
||||
|
||||
/**
|
||||
|
@ -126,7 +126,7 @@ export function createPluginInitializerContext(
|
|||
export function createPluginSetupContext<TPlugin, TPluginDependencies>(
|
||||
coreContext: CoreContext,
|
||||
deps: PluginsServiceSetupDeps,
|
||||
plugin: Plugin<TPlugin, TPluginDependencies>
|
||||
plugin: PluginWrapper<TPlugin, TPluginDependencies>
|
||||
): PluginSetupContext {
|
||||
return {
|
||||
elasticsearch: {
|
||||
|
|
|
@ -27,7 +27,7 @@ import { getEnvOptions } from '../config/__mocks__/env';
|
|||
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
|
||||
import { loggingServiceMock } from '../logging/logging_service.mock';
|
||||
import { PluginDiscoveryError } from './discovery';
|
||||
import { Plugin } from './plugin';
|
||||
import { PluginWrapper } from './plugin';
|
||||
import { PluginsService } from './plugins_service';
|
||||
import { PluginsSystem } from './plugins_system';
|
||||
|
||||
|
@ -110,7 +110,7 @@ test('`setup` throws if discovered plugins with conflicting names', async () =>
|
|||
mockDiscover.mockReturnValue({
|
||||
error$: from([]),
|
||||
plugin$: from([
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-4',
|
||||
{
|
||||
id: 'conflicting-id',
|
||||
|
@ -124,7 +124,7 @@ test('`setup` throws if discovered plugins with conflicting names', async () =>
|
|||
},
|
||||
{ logger } as any
|
||||
),
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-5',
|
||||
{
|
||||
id: 'conflicting-id',
|
||||
|
@ -160,7 +160,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
|
|||
mockDiscover.mockReturnValue({
|
||||
error$: from([]),
|
||||
plugin$: from([
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-1',
|
||||
{
|
||||
id: 'explicitly-disabled-plugin',
|
||||
|
@ -174,7 +174,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
|
|||
},
|
||||
{ logger } as any
|
||||
),
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-2',
|
||||
{
|
||||
id: 'plugin-with-missing-required-deps',
|
||||
|
@ -188,7 +188,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
|
|||
},
|
||||
{ logger } as any
|
||||
),
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-3',
|
||||
{
|
||||
id: 'plugin-with-disabled-transitive-dep',
|
||||
|
@ -202,7 +202,7 @@ test('`setup` properly detects plugins that should be disabled.', async () => {
|
|||
},
|
||||
{ logger } as any
|
||||
),
|
||||
new Plugin(
|
||||
new PluginWrapper(
|
||||
'path-4',
|
||||
{
|
||||
id: 'another-explicitly-disabled-plugin',
|
||||
|
@ -247,7 +247,7 @@ Array [
|
|||
});
|
||||
|
||||
test('`setup` properly invokes `discover` and ignores non-critical errors.', async () => {
|
||||
const firstPlugin = new Plugin(
|
||||
const firstPlugin = new PluginWrapper(
|
||||
'path-1',
|
||||
{
|
||||
id: 'some-id',
|
||||
|
@ -262,7 +262,7 @@ test('`setup` properly invokes `discover` and ignores non-critical errors.', asy
|
|||
{ logger } as any
|
||||
);
|
||||
|
||||
const secondPlugin = new Plugin(
|
||||
const secondPlugin = new PluginWrapper(
|
||||
'path-2',
|
||||
{
|
||||
id: 'some-other-id',
|
||||
|
|
|
@ -24,7 +24,7 @@ import { CoreContext } from '../core_context';
|
|||
import { ElasticsearchServiceSetup } from '../elasticsearch/elasticsearch_service';
|
||||
import { Logger } from '../logging';
|
||||
import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery';
|
||||
import { DiscoveredPlugin, DiscoveredPluginInternal, Plugin, PluginName } from './plugin';
|
||||
import { DiscoveredPlugin, DiscoveredPluginInternal, PluginWrapper, PluginName } from './plugin';
|
||||
import { PluginsConfig } from './plugins_config';
|
||||
import { PluginsSystem } from './plugins_system';
|
||||
|
||||
|
@ -106,8 +106,11 @@ export class PluginsService implements CoreService<PluginsServiceSetup> {
|
|||
}
|
||||
}
|
||||
|
||||
private async handleDiscoveredPlugins(plugin$: Observable<Plugin>) {
|
||||
const pluginEnableStatuses = new Map<PluginName, { plugin: Plugin; isEnabled: boolean }>();
|
||||
private async handleDiscoveredPlugins(plugin$: Observable<PluginWrapper>) {
|
||||
const pluginEnableStatuses = new Map<
|
||||
PluginName,
|
||||
{ plugin: PluginWrapper; isEnabled: boolean }
|
||||
>();
|
||||
await plugin$
|
||||
.pipe(
|
||||
mergeMap(async plugin => {
|
||||
|
@ -139,13 +142,13 @@ export class PluginsService implements CoreService<PluginsServiceSetup> {
|
|||
|
||||
private shouldEnablePlugin(
|
||||
pluginName: PluginName,
|
||||
pluginEnableStatuses: Map<PluginName, { plugin: Plugin; isEnabled: boolean }>
|
||||
pluginEnableStatuses: Map<PluginName, { plugin: PluginWrapper; isEnabled: boolean }>
|
||||
): boolean {
|
||||
const pluginInfo = pluginEnableStatuses.get(pluginName);
|
||||
return (
|
||||
pluginInfo !== undefined &&
|
||||
pluginInfo.isEnabled &&
|
||||
pluginInfo.plugin.requiredDependencies.every(dependencyName =>
|
||||
pluginInfo.plugin.requiredPlugins.every(dependencyName =>
|
||||
this.shouldEnablePlugin(dependencyName, pluginEnableStatuses)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -25,7 +25,7 @@ import { getEnvOptions } from '../config/__mocks__/env';
|
|||
import { CoreContext } from '../core_context';
|
||||
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
|
||||
import { loggingServiceMock } from '../logging/logging_service.mock';
|
||||
import { Plugin, PluginName } from './plugin';
|
||||
import { PluginWrapper, PluginName } from './plugin';
|
||||
import { PluginsSystem } from './plugins_system';
|
||||
|
||||
const logger = loggingServiceMock.create();
|
||||
|
@ -37,7 +37,7 @@ function createPlugin(
|
|||
server = true,
|
||||
}: { required?: string[]; optional?: string[]; server?: boolean } = {}
|
||||
) {
|
||||
return new Plugin(
|
||||
return new PluginWrapper(
|
||||
'some-path',
|
||||
{
|
||||
id,
|
||||
|
@ -140,7 +140,7 @@ test('`setupPlugins` correctly orders plugins and returns exposed values', async
|
|||
createPlugin('order-3', { required: ['order-2'], optional: ['missing-dep'] }),
|
||||
{ 'order-2': 'added-as-2' },
|
||||
],
|
||||
] as Array<[Plugin, Record<PluginName, unknown>]>);
|
||||
] as Array<[PluginWrapper, Record<PluginName, unknown>]>);
|
||||
|
||||
const setupContextMap = new Map();
|
||||
|
||||
|
@ -251,7 +251,7 @@ test('`uiPlugins` returns ordered Maps of all plugin manifests', async () => {
|
|||
createPlugin('order-3', { required: ['order-2'], optional: ['missing-dep'] }),
|
||||
{ 'order-2': 'added-as-2' },
|
||||
],
|
||||
] as Array<[Plugin, Record<PluginName, unknown>]>);
|
||||
] as Array<[PluginWrapper, Record<PluginName, unknown>]>);
|
||||
|
||||
[...plugins.keys()].forEach(plugin => {
|
||||
pluginsSystem.addPlugin(plugin);
|
||||
|
|
|
@ -21,13 +21,13 @@ import { pick } from 'lodash';
|
|||
|
||||
import { CoreContext } from '../core_context';
|
||||
import { Logger } from '../logging';
|
||||
import { DiscoveredPlugin, DiscoveredPluginInternal, Plugin, PluginName } from './plugin';
|
||||
import { DiscoveredPlugin, DiscoveredPluginInternal, PluginWrapper, PluginName } from './plugin';
|
||||
import { createPluginSetupContext } from './plugin_context';
|
||||
import { PluginsServiceSetupDeps } from './plugins_service';
|
||||
|
||||
/** @internal */
|
||||
export class PluginsSystem {
|
||||
private readonly plugins = new Map<PluginName, Plugin>();
|
||||
private readonly plugins = new Map<PluginName, PluginWrapper>();
|
||||
private readonly log: Logger;
|
||||
// `satup`, the past-tense version of the noun `setup`.
|
||||
private readonly satupPlugins: PluginName[] = [];
|
||||
|
@ -36,14 +36,14 @@ export class PluginsSystem {
|
|||
this.log = coreContext.logger.get('plugins-system');
|
||||
}
|
||||
|
||||
public addPlugin(plugin: Plugin) {
|
||||
public addPlugin(plugin: PluginWrapper) {
|
||||
this.plugins.set(plugin.name, plugin);
|
||||
}
|
||||
|
||||
public async setupPlugins(deps: PluginsServiceSetupDeps) {
|
||||
const exposedValues = new Map<PluginName, unknown>();
|
||||
const contracts = new Map<PluginName, unknown>();
|
||||
if (this.plugins.size === 0) {
|
||||
return exposedValues;
|
||||
return contracts;
|
||||
}
|
||||
|
||||
const sortedPlugins = this.getTopologicallySortedPluginNames();
|
||||
|
@ -57,29 +57,31 @@ export class PluginsSystem {
|
|||
|
||||
this.log.debug(`Setting up plugin "${pluginName}"...`);
|
||||
|
||||
const exposedDependencyValues = [
|
||||
...plugin.requiredDependencies,
|
||||
...plugin.optionalDependencies,
|
||||
].reduce(
|
||||
(dependencies, dependencyName) => {
|
||||
dependencies[dependencyName] = exposedValues.get(dependencyName);
|
||||
return dependencies;
|
||||
const pluginDepContracts = [...plugin.requiredPlugins, ...plugin.optionalPlugins].reduce(
|
||||
(depContracts, dependencyName) => {
|
||||
// Only set if present. Could be absent if plugin does not have server-side code or is a
|
||||
// missing optional dependency.
|
||||
if (contracts.has(dependencyName)) {
|
||||
depContracts[dependencyName] = contracts.get(dependencyName);
|
||||
}
|
||||
|
||||
return depContracts;
|
||||
},
|
||||
{} as Record<PluginName, unknown>
|
||||
);
|
||||
|
||||
exposedValues.set(
|
||||
contracts.set(
|
||||
pluginName,
|
||||
await plugin.setup(
|
||||
createPluginSetupContext(this.coreContext, deps, plugin),
|
||||
exposedDependencyValues
|
||||
pluginDepContracts
|
||||
)
|
||||
);
|
||||
|
||||
this.satupPlugins.push(pluginName);
|
||||
}
|
||||
|
||||
return exposedValues;
|
||||
return contracts;
|
||||
}
|
||||
|
||||
public async stopPlugins() {
|
||||
|
@ -151,8 +153,8 @@ export class PluginsSystem {
|
|||
return [
|
||||
pluginName,
|
||||
new Set([
|
||||
...plugin.requiredDependencies,
|
||||
...plugin.optionalDependencies.filter(dependency => this.plugins.has(dependency)),
|
||||
...plugin.requiredPlugins,
|
||||
...plugin.optionalPlugins.filter(dependency => this.plugins.has(dependency)),
|
||||
]),
|
||||
] as [PluginName, Set<PluginName>];
|
||||
})
|
||||
|
|
|
@ -68,13 +68,13 @@ import { mkdirp } from '../lib';
|
|||
*/
|
||||
|
||||
export const BuildPackagesTask = {
|
||||
global: true,
|
||||
description: 'Building distributable versions of packages',
|
||||
async run(config, log, builds) {
|
||||
async run(config, log, build) {
|
||||
await mkdirp(config.resolveFromRepo('target'));
|
||||
await buildProductionProjects({
|
||||
kibanaRoot: config.resolveFromRepo(),
|
||||
buildRoots: builds.map(build => build.resolvePath()),
|
||||
buildRoot: build.resolvePath(),
|
||||
onlyOSS: build.isOss(),
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -40,12 +40,12 @@ export const CleanPackagesTask = {
|
|||
async run(config, log, build) {
|
||||
await deleteAll([
|
||||
build.resolvePath('packages'),
|
||||
build.resolvePath('x-pack'),
|
||||
build.resolvePath('yarn.lock'),
|
||||
], log);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export const CleanTypescriptTask = {
|
||||
description:
|
||||
'Cleaning typescript source files that have been transpiled to JS',
|
||||
|
@ -70,103 +70,112 @@ export const CleanExtraFilesFromModulesTask = {
|
|||
minimatch.makeRe(pattern, { nocase: true })
|
||||
);
|
||||
|
||||
const regularExpressions = makeRegexps([
|
||||
// tests
|
||||
'**/test',
|
||||
'**/tests',
|
||||
'**/__tests__',
|
||||
'**/mocha.opts',
|
||||
'**/*.test.js',
|
||||
'**/*.snap',
|
||||
'**/coverage',
|
||||
|
||||
// docs
|
||||
'**/doc',
|
||||
'**/docs',
|
||||
'**/CONTRIBUTING.md',
|
||||
'**/Contributing.md',
|
||||
'**/contributing.md',
|
||||
'**/History.md',
|
||||
'**/HISTORY.md',
|
||||
'**/history.md',
|
||||
'**/CHANGELOG.md',
|
||||
'**/Changelog.md',
|
||||
'**/changelog.md',
|
||||
|
||||
// examples
|
||||
'**/example',
|
||||
'**/examples',
|
||||
'**/demo',
|
||||
'**/samples',
|
||||
|
||||
// bins
|
||||
'**/.bin',
|
||||
|
||||
// linters
|
||||
'**/.eslintrc',
|
||||
'**/.eslintrc.js',
|
||||
'**/.eslintrc.yml',
|
||||
'**/.prettierrc',
|
||||
'**/.jshintrc',
|
||||
'**/.babelrc',
|
||||
'**/.jscs.json',
|
||||
'**/.lint',
|
||||
|
||||
// hints
|
||||
'**/*.flow',
|
||||
'**/*.webidl',
|
||||
'**/*.map',
|
||||
'**/@types',
|
||||
|
||||
// scripts
|
||||
'**/*.sh',
|
||||
'**/*.bat',
|
||||
'**/*.exe',
|
||||
'**/Gruntfile.js',
|
||||
'**/gulpfile.js',
|
||||
'**/Makefile',
|
||||
|
||||
// untranspiled sources
|
||||
'**/*.coffee',
|
||||
'**/*.scss',
|
||||
'**/*.sass',
|
||||
'**/.ts',
|
||||
'**/.tsx',
|
||||
|
||||
// editors
|
||||
'**/.editorconfig',
|
||||
'**/.vscode',
|
||||
|
||||
// git
|
||||
'**/.gitattributes',
|
||||
'**/.gitkeep',
|
||||
'**/.gitempty',
|
||||
'**/.gitmodules',
|
||||
'**/.keep',
|
||||
'**/.empty',
|
||||
|
||||
// ci
|
||||
'**/.travis.yml',
|
||||
'**/.coveralls.yml',
|
||||
'**/.instanbul.yml',
|
||||
'**/appveyor.yml',
|
||||
'**/.zuul.yml',
|
||||
|
||||
// metadata
|
||||
'**/package-lock.json',
|
||||
'**/component.json',
|
||||
'**/bower.json',
|
||||
'**/yarn.lock',
|
||||
|
||||
// misc
|
||||
'**/.*ignore',
|
||||
'**/.DS_Store',
|
||||
'**/Dockerfile',
|
||||
'**/docker-compose.yml',
|
||||
]);
|
||||
|
||||
log.info('Deleted %d files', await scanDelete({
|
||||
directory: build.resolvePath('node_modules'),
|
||||
regularExpressions: makeRegexps([
|
||||
// tests
|
||||
'**/test',
|
||||
'**/tests',
|
||||
'**/__tests__',
|
||||
'**/mocha.opts',
|
||||
'**/*.test.js',
|
||||
'**/*.snap',
|
||||
'**/coverage',
|
||||
|
||||
// docs
|
||||
'**/doc',
|
||||
'**/docs',
|
||||
'**/CONTRIBUTING.md',
|
||||
'**/Contributing.md',
|
||||
'**/contributing.md',
|
||||
'**/History.md',
|
||||
'**/HISTORY.md',
|
||||
'**/history.md',
|
||||
'**/CHANGELOG.md',
|
||||
'**/Changelog.md',
|
||||
'**/changelog.md',
|
||||
|
||||
// examples
|
||||
'**/example',
|
||||
'**/examples',
|
||||
'**/demo',
|
||||
'**/samples',
|
||||
|
||||
// bins
|
||||
'**/.bin',
|
||||
|
||||
// linters
|
||||
'**/.eslintrc',
|
||||
'**/.eslintrc.js',
|
||||
'**/.eslintrc.yml',
|
||||
'**/.prettierrc',
|
||||
'**/.jshintrc',
|
||||
'**/.babelrc',
|
||||
'**/.jscs.json',
|
||||
'**/.lint',
|
||||
|
||||
// hints
|
||||
'**/*.flow',
|
||||
'**/*.webidl',
|
||||
'**/*.map',
|
||||
'**/@types',
|
||||
|
||||
// scripts
|
||||
'**/*.sh',
|
||||
'**/*.bat',
|
||||
'**/*.exe',
|
||||
'**/Gruntfile.js',
|
||||
'**/gulpfile.js',
|
||||
'**/Makefile',
|
||||
|
||||
// untranspiled sources
|
||||
'**/*.coffee',
|
||||
'**/*.scss',
|
||||
'**/*.sass',
|
||||
'**/.ts',
|
||||
'**/.tsx',
|
||||
|
||||
// editors
|
||||
'**/.editorconfig',
|
||||
'**/.vscode',
|
||||
|
||||
// git
|
||||
'**/.gitattributes',
|
||||
'**/.gitkeep',
|
||||
'**/.gitempty',
|
||||
'**/.gitmodules',
|
||||
'**/.keep',
|
||||
'**/.empty',
|
||||
|
||||
// ci
|
||||
'**/.travis.yml',
|
||||
'**/.coveralls.yml',
|
||||
'**/.instanbul.yml',
|
||||
'**/appveyor.yml',
|
||||
'**/.zuul.yml',
|
||||
|
||||
// metadata
|
||||
'**/package-lock.json',
|
||||
'**/component.json',
|
||||
'**/bower.json',
|
||||
'**/yarn.lock',
|
||||
|
||||
// misc
|
||||
'**/.*ignore',
|
||||
'**/.DS_Store',
|
||||
'**/Dockerfile',
|
||||
'**/docker-compose.yml'
|
||||
])
|
||||
regularExpressions
|
||||
}));
|
||||
|
||||
if (!build.isOss()) {
|
||||
log.info('Deleted %d files', await scanDelete({
|
||||
directory: build.resolvePath('x-pack/node_modules'),
|
||||
regularExpressions
|
||||
}));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -194,7 +203,7 @@ export const CleanExtraBrowsersTask = {
|
|||
|
||||
async run(config, log, build) {
|
||||
const getBrowserPathsForPlatform = platform => {
|
||||
const reportingDir = 'node_modules/x-pack/plugins/reporting';
|
||||
const reportingDir = 'x-pack/plugins/reporting';
|
||||
const chromiumDir = '.chromium';
|
||||
const chromiumPath = p =>
|
||||
build.resolvePathForPlatform(platform, reportingDir, chromiumDir, p);
|
||||
|
|
|
@ -27,14 +27,7 @@ export const CreateArchivesSourcesTask = {
|
|||
// copy all files from generic build source directory into platform-specific build directory
|
||||
await scanCopy({
|
||||
source: build.resolvePath(),
|
||||
destination: build.resolvePathForPlatform(platform),
|
||||
filter: record => !(record.isDirectory && record.name === 'node_modules')
|
||||
});
|
||||
|
||||
await scanCopy({
|
||||
source: build.resolvePath('node_modules'),
|
||||
destination: build.resolvePathForPlatform(platform, 'node_modules'),
|
||||
time: new Date()
|
||||
destination: build.resolvePathForPlatform(platform)
|
||||
});
|
||||
|
||||
log.debug('Generic build source copied into', platform.getName(), 'specific build directory');
|
||||
|
|
|
@ -50,7 +50,6 @@ export const CreatePackageJsonTask = {
|
|||
};
|
||||
|
||||
if (build.isOss()) {
|
||||
delete newPkg.dependencies['x-pack'];
|
||||
newPkg.workspaces.packages = newPkg.workspaces.packages.filter(p => !p.startsWith('x-pack'));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,18 +17,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { exec } from '../lib';
|
||||
import { Project } from '@kbn/pm';
|
||||
|
||||
export const InstallDependenciesTask = {
|
||||
description: 'Installing node_modules, including production builds of packages',
|
||||
|
||||
async run(config, log, build) {
|
||||
// We're using --no-bin-links to support systems that don't have symlinks.
|
||||
// This is commonly seen in shared folders on virtual machines
|
||||
const args = ['--production', '--ignore-optional', '--frozen-lockfile', '--no-bin-links', '--prefer-offline'];
|
||||
const project = await Project.fromPath(build.resolvePath());
|
||||
|
||||
await exec(log, 'yarn', args, {
|
||||
cwd: build.resolvePath(),
|
||||
await project.installDependencies({
|
||||
extraArgs: [
|
||||
'--production',
|
||||
'--ignore-optional',
|
||||
'--frozen-lockfile',
|
||||
'--prefer-offline',
|
||||
|
||||
// We're using --no-bin-links to support systems that don't have symlinks.
|
||||
// This is commonly seen in shared folders on virtual machines
|
||||
'--no-bin-links',
|
||||
]
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ export const CleanClientModulesOnDLLTask = {
|
|||
`${baseDir}/src/cli`,
|
||||
`${baseDir}/src/cli_keystore`,
|
||||
`${baseDir}/src/cli_plugin`,
|
||||
`${baseDir}/node_modules/x-pack`,
|
||||
`${baseDir}/x-pack`,
|
||||
...kbnWebpackLoaders.map(loader => `${baseDir}/node_modules/${loader}`)
|
||||
];
|
||||
const discoveredLegacyCorePluginEntries = await globby([
|
||||
|
|
|
@ -33,10 +33,7 @@ export async function buildSass({ log, kibanaDir }) {
|
|||
resolve(kibanaDir, 'src/legacy/core_plugins')
|
||||
];
|
||||
|
||||
const paths = [
|
||||
resolve(kibanaDir, 'x-pack'),
|
||||
resolve(kibanaDir, 'node_modules/x-pack')
|
||||
];
|
||||
const paths = [ resolve(kibanaDir, 'x-pack') ];
|
||||
|
||||
const { spec$ } = findPluginSpecs({ plugins: { scanDirs, paths } });
|
||||
const enabledPlugins = await spec$.pipe(toArray()).toPromise();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
export const INSTRUCTION_VARIANT = {
|
||||
ESC: 'esc',
|
||||
OSX: 'osx',
|
||||
DEB: 'deb',
|
||||
RPM: 'rpm',
|
||||
|
@ -35,6 +36,7 @@ export const INSTRUCTION_VARIANT = {
|
|||
};
|
||||
|
||||
const DISPLAY_MAP = {
|
||||
[INSTRUCTION_VARIANT.ESC]: 'Elastic Cloud',
|
||||
[INSTRUCTION_VARIANT.OSX]: 'macOS',
|
||||
[INSTRUCTION_VARIANT.DEB]: 'DEB',
|
||||
[INSTRUCTION_VARIANT.RPM]: 'RPM',
|
||||
|
|
|
@ -113,7 +113,12 @@
|
|||
data-test-subj="tab-count-{{ editSection.index }}"
|
||||
aria-label="{{:: editSection.count + ' ' + editSection.title}}"
|
||||
>
|
||||
({{ editSection.count }})
|
||||
<span ng-if="editSection.count != editSection.totalCount">
|
||||
({{ editSection.count }} / {{ editSection.totalCount }})
|
||||
</span>
|
||||
<span ng-if="editSection.count == editSection.totalCount">
|
||||
({{ editSection.count }})
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -58,7 +58,7 @@ function updateSourceFiltersTable($scope, $state) {
|
|||
filterFilter={$scope.fieldFilter}
|
||||
fieldWildcardMatcher={$scope.fieldWildcardMatcher}
|
||||
onAddOrRemoveFilter={() => {
|
||||
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.indexPatternListProvider);
|
||||
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, $scope.indexPatternListProvider);
|
||||
$scope.refreshFilters();
|
||||
$scope.$apply();
|
||||
}}
|
||||
|
@ -191,7 +191,7 @@ uiModules.get('apps/management')
|
|||
});
|
||||
|
||||
$scope.$watch('indexPattern.fields', function () {
|
||||
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, indexPatternListProvider);
|
||||
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
|
||||
$scope.refreshFilters();
|
||||
$scope.fields = $scope.indexPattern.getNonScriptedFields();
|
||||
updateIndexedFieldsTable($scope, $state);
|
||||
|
@ -294,6 +294,7 @@ uiModules.get('apps/management')
|
|||
};
|
||||
|
||||
$scope.$watch('fieldFilter', () => {
|
||||
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
|
||||
if ($scope.fieldFilter === undefined) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -20,39 +20,59 @@
|
|||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
function filterBy(items, key, filter) {
|
||||
const lowercaseFilter = (filter || '').toLowerCase();
|
||||
return items.filter(item => item[key].toLowerCase().includes(lowercaseFilter));
|
||||
}
|
||||
|
||||
function getCounts(fields, sourceFilters, fieldFilter = '') {
|
||||
const fieldCount = _.countBy(filterBy(fields, 'name', fieldFilter), function (field) {
|
||||
return field.scripted ? 'scripted' : 'indexed';
|
||||
});
|
||||
|
||||
_.defaults(fieldCount, {
|
||||
indexed: 0,
|
||||
scripted: 0,
|
||||
sourceFilters: sourceFilters ? filterBy(sourceFilters, 'value', fieldFilter).length : 0,
|
||||
});
|
||||
|
||||
return fieldCount;
|
||||
}
|
||||
|
||||
export function IndicesEditSectionsProvider() {
|
||||
|
||||
return function (indexPattern, indexPatternListProvider) {
|
||||
const fieldCount = _.countBy(indexPattern.fields, function (field) {
|
||||
return (field.scripted) ? 'scripted' : 'indexed';
|
||||
});
|
||||
|
||||
_.defaults(fieldCount, {
|
||||
indexed: 0,
|
||||
scripted: 0,
|
||||
sourceFilters: indexPattern.sourceFilters ? indexPattern.sourceFilters.length : 0,
|
||||
});
|
||||
return function (indexPattern, fieldFilter, indexPatternListProvider) {
|
||||
const totalCount = getCounts(indexPattern.fields, indexPattern.sourceFilters);
|
||||
const filteredCount = getCounts(indexPattern.fields, indexPattern.sourceFilters, fieldFilter);
|
||||
|
||||
const editSections = [];
|
||||
|
||||
editSections.push({
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.fieldsHeader', { defaultMessage: 'Fields' }),
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.fieldsHeader', {
|
||||
defaultMessage: 'Fields',
|
||||
}),
|
||||
index: 'indexedFields',
|
||||
count: fieldCount.indexed
|
||||
count: filteredCount.indexed,
|
||||
totalCount: totalCount.indexed,
|
||||
});
|
||||
|
||||
if(indexPatternListProvider.areScriptedFieldsEnabled(indexPattern)) {
|
||||
if (indexPatternListProvider.areScriptedFieldsEnabled(indexPattern)) {
|
||||
editSections.push({
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.scriptedHeader', { defaultMessage: 'Scripted fields' }),
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.scriptedHeader', {
|
||||
defaultMessage: 'Scripted fields',
|
||||
}),
|
||||
index: 'scriptedFields',
|
||||
count: fieldCount.scripted
|
||||
count: filteredCount.scripted,
|
||||
totalCount: totalCount.scripted,
|
||||
});
|
||||
}
|
||||
|
||||
editSections.push({
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.sourceHeader', { defaultMessage: 'Source filters' }),
|
||||
title: i18n.translate('kbn.management.editIndexPattern.tabs.sourceHeader', {
|
||||
defaultMessage: 'Source filters',
|
||||
}),
|
||||
index: 'sourceFilters',
|
||||
count: fieldCount.sourceFilters
|
||||
count: filteredCount.sourceFilters,
|
||||
totalCount: totalCount.sourceFilters,
|
||||
});
|
||||
|
||||
return editSections;
|
||||
|
|
|
@ -68,6 +68,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "array",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -85,6 +86,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "boolean",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -104,6 +106,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -121,6 +124,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "image",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -140,6 +144,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "json",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -157,6 +162,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "number",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -178,6 +184,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"banana",
|
||||
],
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "select",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -195,6 +202,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -212,6 +220,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "json",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -229,6 +238,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "markdown",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -246,6 +256,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "number",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -267,6 +278,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"banana",
|
||||
],
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "select",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -284,6 +296,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -326,6 +339,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "array",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -343,6 +357,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "boolean",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -362,6 +377,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -379,6 +395,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "image",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -398,6 +415,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "json",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -415,6 +433,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "number",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -436,6 +455,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"banana",
|
||||
],
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "select",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -453,6 +473,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -470,6 +491,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "json",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -487,6 +509,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "markdown",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -504,6 +527,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "number",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -525,6 +549,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"banana",
|
||||
],
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "select",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -542,6 +567,7 @@ exports[`AdvancedSettings should render normally 1`] = `
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -659,6 +685,7 @@ exports[`AdvancedSettings should render specific setting if given setting key 1`
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
@ -699,6 +726,7 @@ exports[`AdvancedSettings should render specific setting if given setting key 1`
|
|||
"optionLabels": undefined,
|
||||
"options": undefined,
|
||||
"readonly": false,
|
||||
"requiresPageReload": false,
|
||||
"type": "string",
|
||||
"value": undefined,
|
||||
},
|
||||
|
|
|
@ -283,6 +283,34 @@ class FieldUI extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
showPageReloadToast = () => {
|
||||
if (this.props.setting.requiresPageReload) {
|
||||
toastNotifications.add({
|
||||
title: this.props.intl.formatMessage({
|
||||
id: 'kbn.management.settings.field.requiresPageReloadToastDescription',
|
||||
defaultMessage: 'Please reload the page for the "{settingName}" setting to take effect.',
|
||||
}, {
|
||||
settingName: this.props.setting.displayName || this.props.setting.name,
|
||||
}),
|
||||
text: (
|
||||
<>
|
||||
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton size="s" onClick={() => window.location.reload()}>
|
||||
{this.props.intl.formatMessage({
|
||||
id: 'kbn.management.settings.field.requiresPageReloadToastButtonLabel',
|
||||
defaultMessage: 'Reload page'
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
),
|
||||
color: 'success',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
saveEdit = async () => {
|
||||
const { name, defVal, type } = this.props.setting;
|
||||
const { changeImage, savedValue, unsavedValue, isJsonArray } = this.state;
|
||||
|
@ -314,6 +342,8 @@ class FieldUI extends PureComponent {
|
|||
await this.props.save(name, valueToSave);
|
||||
}
|
||||
|
||||
this.showPageReloadToast();
|
||||
|
||||
if (changeImage) {
|
||||
this.cancelChangeImage();
|
||||
}
|
||||
|
@ -334,6 +364,7 @@ class FieldUI extends PureComponent {
|
|||
this.setLoading(true);
|
||||
try {
|
||||
await this.props.clear(name);
|
||||
this.showPageReloadToast();
|
||||
this.cancelChangeImage();
|
||||
this.clearError();
|
||||
} catch (e) {
|
||||
|
|
|
@ -25,10 +25,13 @@ import { Field } from './field';
|
|||
|
||||
jest.mock('ui/notify', () => ({
|
||||
toastNotifications: {
|
||||
addDanger: () => {}
|
||||
addDanger: () => {},
|
||||
add: jest.fn(),
|
||||
}
|
||||
}));
|
||||
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
jest.mock('brace/theme/textmate', () => 'brace/theme/textmate');
|
||||
jest.mock('brace/mode/markdown', () => 'brace/mode/markdown');
|
||||
|
||||
|
@ -394,4 +397,28 @@ describe('Field', () => {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should show a reload toast when saving setting requiring a page reload', async () => {
|
||||
const setting = {
|
||||
...settings.string,
|
||||
requiresPageReload: true,
|
||||
};
|
||||
const wrapper = mountWithIntl(
|
||||
<Field.WrappedComponent
|
||||
setting={setting}
|
||||
save={save}
|
||||
clear={clear}
|
||||
/>
|
||||
);
|
||||
wrapper.instance().onFieldChange({ target: { value: 'a new value' } });
|
||||
wrapper.update();
|
||||
findTestSubject(wrapper, `advancedSetting-saveEditField-${setting.name}`).simulate('click');
|
||||
expect(save).toHaveBeenCalled();
|
||||
await save();
|
||||
expect(toastNotifications.add).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
title: expect.stringContaining('Please reload the page'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,6 +45,7 @@ export function toEditableConfig({ def, name, value, isCustom, isOverridden }) {
|
|||
description: def.description,
|
||||
options: def.options,
|
||||
optionLabels: def.optionLabels,
|
||||
requiresPageReload: !!def.requiresPageReload,
|
||||
};
|
||||
|
||||
return conf;
|
||||
|
|
|
@ -37,49 +37,86 @@ function getIfExists(config, key) {
|
|||
|
||||
export function createElasticCloudInstructions(config) {
|
||||
const apmServerUrl = getIfExists(config, 'xpack.cloud.apm.url');
|
||||
const secretToken = getIfExists(config, 'xpack.cloud.apm.secret_token');
|
||||
const instructionSets = [];
|
||||
|
||||
if (!apmServerUrl) {
|
||||
instructionSets.push(getApmServerInstructionSet(config));
|
||||
}
|
||||
|
||||
instructionSets.push(getApmAgentInstructionSet(config));
|
||||
|
||||
return {
|
||||
instructionSets: [
|
||||
instructionSets,
|
||||
};
|
||||
}
|
||||
|
||||
function getApmServerInstructionSet(config) {
|
||||
const apmUiUrl = getIfExists(config, 'xpack.cloud.apm.ui.url');
|
||||
return {
|
||||
title: i18n.translate('kbn.server.tutorials.apm.apmServer.title', {
|
||||
defaultMessage: 'APM Server',
|
||||
}),
|
||||
instructionVariants: [
|
||||
{
|
||||
title: i18n.translate('kbn.server.tutorials.apm.elasticCloudInstructions.title', {
|
||||
defaultMessage: 'APM Agents',
|
||||
}),
|
||||
instructionVariants: [
|
||||
id: INSTRUCTION_VARIANT.ESC,
|
||||
instructions: [
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.NODE,
|
||||
instructions: createNodeAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.DJANGO,
|
||||
instructions: createDjangoAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.FLASK,
|
||||
instructions: createFlaskAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.RAILS,
|
||||
instructions: createRailsAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.RACK,
|
||||
instructions: createRackAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.JS,
|
||||
instructions: createJsAgentInstructions(apmServerUrl),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.GO,
|
||||
instructions: createGoAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.JAVA,
|
||||
instructions: createJavaAgentInstructions(apmServerUrl, secretToken),
|
||||
title: 'Enable the APM Server in the ESS console',
|
||||
textPre: i18n.translate('kbn.server.tutorials.apm.elasticCloud.textPre', {
|
||||
defaultMessage:
|
||||
'To enable the APM Server go to [the ESS console]({essConsoleLink}). Once enabled, refresh this page.',
|
||||
values: {
|
||||
essConsoleLink: apmUiUrl,
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function getApmAgentInstructionSet(config) {
|
||||
const apmServerUrl = getIfExists(config, 'xpack.cloud.apm.url');
|
||||
const secretToken = getIfExists(config, 'xpack.cloud.apm.secret_token');
|
||||
|
||||
return {
|
||||
title: i18n.translate('kbn.server.tutorials.apm.elasticCloudInstructions.title', {
|
||||
defaultMessage: 'APM Agents',
|
||||
}),
|
||||
instructionVariants: [
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.NODE,
|
||||
instructions: createNodeAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.DJANGO,
|
||||
instructions: createDjangoAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.FLASK,
|
||||
instructions: createFlaskAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.RAILS,
|
||||
instructions: createRailsAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.RACK,
|
||||
instructions: createRackAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.JS,
|
||||
instructions: createJsAgentInstructions(apmServerUrl),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.GO,
|
||||
instructions: createGoAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
{
|
||||
id: INSTRUCTION_VARIANT.JAVA,
|
||||
instructions: createJavaAgentInstructions(apmServerUrl, secretToken),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ export function getUiSettingDefaults() {
|
|||
},
|
||||
}),
|
||||
type: 'select',
|
||||
options: ['Browser', ...moment.tz.names()]
|
||||
options: ['Browser', ...moment.tz.names()],
|
||||
requiresPageReload: true,
|
||||
},
|
||||
'dateFormat:scaled': {
|
||||
name: i18n.translate('kbn.advancedSettings.dateFormat.scaledTitle', {
|
||||
|
@ -863,6 +864,7 @@ export function getUiSettingDefaults() {
|
|||
description: i18n.translate('kbn.advancedSettings.darkModeText', {
|
||||
defaultMessage: `Enable a dark mode for the Kibana UI. A page refresh is required for the setting to be applied.`,
|
||||
}),
|
||||
requiresPageReload: true,
|
||||
},
|
||||
'filters:pinnedByDefault': {
|
||||
name: i18n.translate('kbn.advancedSettings.pinFiltersTitle', {
|
||||
|
@ -1042,6 +1044,7 @@ export function getUiSettingDefaults() {
|
|||
defaultMessage: 'Turn off all unnecessary animations in the Kibana UI. Refresh the page to apply the changes.',
|
||||
}),
|
||||
category: ['accessibility'],
|
||||
requiresPageReload: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,17 +22,26 @@ import React from 'react';
|
|||
import aggToComponent from '../lib/agg_to_component';
|
||||
import { sortable } from 'react-anything-sortable';
|
||||
import { UnsupportedAgg } from './unsupported_agg';
|
||||
import { TemporaryUnsupportedAgg } from './temporary_unsupported_agg';
|
||||
|
||||
import { isMetricEnabled } from '../../lib/check_ui_restrictions';
|
||||
|
||||
function Agg(props) {
|
||||
const { model } = props;
|
||||
const { model, uiRestrictions } = props;
|
||||
|
||||
let Component = aggToComponent[model.type];
|
||||
|
||||
if (!Component) {
|
||||
Component = UnsupportedAgg;
|
||||
} else if (!isMetricEnabled(model.type, uiRestrictions)) {
|
||||
Component = TemporaryUnsupportedAgg;
|
||||
}
|
||||
|
||||
const style = {
|
||||
cursor: 'default',
|
||||
...props.style,
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={props.className}
|
||||
|
@ -50,6 +59,7 @@ function Agg(props) {
|
|||
panel={props.panel}
|
||||
series={props.series}
|
||||
siblings={props.siblings}
|
||||
uiRestrictions={props.uiRestrictions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -70,6 +80,7 @@ Agg.propTypes = {
|
|||
series: PropTypes.object,
|
||||
siblings: PropTypes.array,
|
||||
sortData: PropTypes.string,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export default sortable(Agg);
|
||||
|
|
|
@ -22,6 +22,7 @@ import React from 'react';
|
|||
import { EuiComboBox } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
import { isMetricEnabled } from '../../lib/check_ui_restrictions';
|
||||
|
||||
const metricAggs = [
|
||||
{
|
||||
|
@ -169,41 +170,45 @@ function filterByPanelType(panelType) {
|
|||
}
|
||||
|
||||
function AggSelectUi(props) {
|
||||
const { siblings, panelType, value, onChange, intl, ...rest } = props;
|
||||
const selectedOption = allAggOptions.find(option => {
|
||||
return value === option.value;
|
||||
const { siblings, panelType, value, onChange, intl, uiRestrictions, ...rest } = props;
|
||||
|
||||
const selectedOptions = allAggOptions.filter(option => {
|
||||
return value === option.value && isMetricEnabled(option.value, uiRestrictions);
|
||||
});
|
||||
const selectedOptions = selectedOption ? [selectedOption] : [];
|
||||
|
||||
let enablePipelines = siblings.some(
|
||||
s => !!metricAggs.find(m => m.value === s.type)
|
||||
);
|
||||
|
||||
if (siblings.length <= 1) enablePipelines = false;
|
||||
|
||||
let options;
|
||||
if (panelType === 'metrics') {
|
||||
options = metricAggs;
|
||||
} else {
|
||||
const disableSiblingAggs = agg => ({ ...agg, disabled: !enablePipelines || !isMetricEnabled(agg.value, uiRestrictions) });
|
||||
|
||||
options = [
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.aggSelect.aggGroups.metricAggLabel', defaultMessage: 'Metric Aggregations' }),
|
||||
options: metricAggs,
|
||||
options: metricAggs
|
||||
.map(agg => ({ ...agg, disabled: !isMetricEnabled(agg.value, uiRestrictions) })),
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'tsvb.aggSelect.aggGroups.parentPipelineAggLabel', defaultMessage: 'Parent Pipeline Aggregations' }),
|
||||
options: pipelineAggs
|
||||
.filter(filterByPanelType(panelType))
|
||||
.map(agg => ({ ...agg, disabled: !enablePipelines })),
|
||||
.map(disableSiblingAggs),
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({
|
||||
id: 'tsvb.aggSelect.aggGroups.siblingPipelineAggLabel', defaultMessage: 'Sibling Pipeline Aggregations' }),
|
||||
options: siblingAggs.map(agg => ({ ...agg, disabled: !enablePipelines })),
|
||||
options: siblingAggs.map(disableSiblingAggs),
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.aggSelect.aggGroups.specialAggLabel', defaultMessage: 'Special Aggregations' }),
|
||||
options: specialAggs.map(agg => ({ ...agg, disabled: !enablePipelines })),
|
||||
options: specialAggs.map(disableSiblingAggs),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -233,6 +238,7 @@ AggSelectUi.propTypes = {
|
|||
panelType: PropTypes.string,
|
||||
siblings: PropTypes.array,
|
||||
value: PropTypes.string,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
const AggSelect = injectI18n(AggSelectUi);
|
||||
|
|
|
@ -24,26 +24,39 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import generateByTypeFilter from '../lib/generate_by_type_filter';
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
import { isFieldEnabled } from '../../lib/check_ui_restrictions';
|
||||
|
||||
function FieldSelectUi({
|
||||
type,
|
||||
fields,
|
||||
indexPattern,
|
||||
value,
|
||||
onChange,
|
||||
disabled,
|
||||
restrict,
|
||||
intl,
|
||||
uiRestrictions,
|
||||
...rest
|
||||
}) {
|
||||
|
||||
function FieldSelectUi(props) {
|
||||
const { type, fields, indexPattern, value, onChange, disabled, restrict, intl, ...rest } = props;
|
||||
if (type === 'count') {
|
||||
return null;
|
||||
}
|
||||
const options = (fields[indexPattern] || [])
|
||||
.filter(generateByTypeFilter(restrict))
|
||||
.map(field => {
|
||||
return { label: field.name, value: field.name };
|
||||
});
|
||||
|
||||
const selectedOption = options.find(option => {
|
||||
return value === option.value;
|
||||
});
|
||||
const typeFilter = generateByTypeFilter(restrict);
|
||||
const options = (fields[indexPattern] || [])
|
||||
.filter(field => typeFilter(field) && isFieldEnabled(field.name, type, uiRestrictions))
|
||||
.map(field => ({ label: field.name, value: field.name }));
|
||||
|
||||
const selectedOption = options.find(option => value === option.value);
|
||||
const selectedOptions = selectedOption ? [selectedOption] : [];
|
||||
|
||||
return (
|
||||
<EuiComboBox
|
||||
placeholder={intl.formatMessage({ id: 'tsvb.fieldSelect.selectFieldPlaceholder', defaultMessage: 'Select field…' })}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'tsvb.fieldSelect.selectFieldPlaceholder',
|
||||
defaultMessage: 'Select field...',
|
||||
})}
|
||||
isDisabled={disabled}
|
||||
options={options}
|
||||
selectedOptions={selectedOptions}
|
||||
|
@ -57,7 +70,7 @@ function FieldSelectUi(props) {
|
|||
FieldSelectUi.defaultProps = {
|
||||
indexPattern: '*',
|
||||
disabled: false,
|
||||
restrict: 'none'
|
||||
restrict: 'none',
|
||||
};
|
||||
|
||||
FieldSelectUi.propTypes = {
|
||||
|
@ -68,7 +81,8 @@ FieldSelectUi.propTypes = {
|
|||
onChange: PropTypes.func,
|
||||
restrict: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.string
|
||||
value: PropTypes.string,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
const FieldSelect = injectI18n(FieldSelectUi);
|
||||
|
|
|
@ -28,8 +28,7 @@ import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFormLabel }
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
function StandardAgg(props) {
|
||||
const { model, panel, series, fields } = props;
|
||||
|
||||
const { model, panel, series, fields, uiRestrictions } = props;
|
||||
const handleChange = createChangeHandler(props.onChange, model);
|
||||
const handleSelectChange = createSelectHandler(handleChange);
|
||||
let restrict = 'numeric';
|
||||
|
@ -61,6 +60,7 @@ function StandardAgg(props) {
|
|||
panelType={props.panel.type}
|
||||
siblings={props.siblings}
|
||||
value={model.type}
|
||||
uiRestrictions={uiRestrictions}
|
||||
onChange={handleSelectChange('type')}
|
||||
fullWidth
|
||||
/>
|
||||
|
@ -85,6 +85,7 @@ function StandardAgg(props) {
|
|||
indexPattern={indexPattern}
|
||||
value={model.field}
|
||||
onChange={handleSelectChange('field')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
fullWidth
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -95,7 +96,6 @@ function StandardAgg(props) {
|
|||
</EuiFlexGroup>
|
||||
</AggRow>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
StandardAgg.propTypes = {
|
||||
|
@ -108,6 +108,7 @@ StandardAgg.propTypes = {
|
|||
panel: PropTypes.object,
|
||||
series: PropTypes.object,
|
||||
siblings: PropTypes.array,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export default StandardAgg;
|
||||
|
|
|
@ -128,6 +128,7 @@ const StandardSiblingAggUi = props => {
|
|||
panelType={props.panel.type}
|
||||
siblings={props.siblings}
|
||||
value={model.type}
|
||||
uiRestrictions={props.uiRestrictions}
|
||||
onChange={handleSelectChange('type')}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -165,6 +166,7 @@ StandardSiblingAggUi.propTypes = {
|
|||
panel: PropTypes.object,
|
||||
series: PropTypes.object,
|
||||
siblings: PropTypes.array,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export const StandardSiblingAgg = injectI18n(StandardSiblingAggUi);
|
||||
|
|
|
@ -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 AggRow from './agg_row';
|
||||
import React from 'react';
|
||||
import { EuiCode, EuiTitle } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export function TemporaryUnsupportedAgg(props) {
|
||||
return (
|
||||
<AggRow
|
||||
disableDelete={props.disableDelete}
|
||||
model={props.model}
|
||||
onAdd={props.onAdd}
|
||||
onDelete={props.onDelete}
|
||||
siblings={props.siblings}
|
||||
>
|
||||
<EuiTitle className="tvbAggRow__unavailable" size="xxxs">
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="tsvb.unsupportedAgg.aggIsTemporaryUnsupportedDescription"
|
||||
defaultMessage="The {modelType} aggregation is currently unsupported."
|
||||
values={{ modelType: (<EuiCode>{props.model.type}</EuiCode>) }}
|
||||
/>
|
||||
</span>
|
||||
</EuiTitle>
|
||||
</AggRow>
|
||||
);
|
||||
}
|
|
@ -25,8 +25,9 @@ import Agg from '../aggs/agg';
|
|||
|
||||
export default function createAggRowRender(props) {
|
||||
return (row, index, items) => {
|
||||
const { panel, model, fields } = props;
|
||||
const { panel, model, fields, uiRestrictions } = props;
|
||||
const changeHandler = seriesChangeHandler(props, items);
|
||||
|
||||
return (
|
||||
<Agg
|
||||
key={row.id}
|
||||
|
@ -39,6 +40,7 @@ export default function createAggRowRender(props) {
|
|||
panel={panel}
|
||||
series={model}
|
||||
siblings={items}
|
||||
uiRestrictions={uiRestrictions}
|
||||
sortData={row.id}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -107,6 +107,7 @@ class GaugePanelConfigUi extends Component {
|
|||
limit={1}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
|
@ -340,6 +341,7 @@ GaugePanelConfigUi.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
const GaugePanelConfig = injectI18n(GaugePanelConfigUi);
|
||||
|
|
|
@ -110,6 +110,7 @@ class MarkdownPanelConfigUi extends Component {
|
|||
fields={this.props.fields}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
|
@ -315,7 +316,8 @@ MarkdownPanelConfigUi.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
dateFormat: PropTypes.string
|
||||
dateFormat: PropTypes.string,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
const MarkdownPanelConfig = injectI18n(MarkdownPanelConfigUi);
|
||||
|
|
|
@ -76,6 +76,7 @@ class MetricPanelConfig extends Component {
|
|||
limit={2}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
|
@ -191,6 +192,7 @@ MetricPanelConfig.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
export default MetricPanelConfig;
|
||||
|
|
|
@ -161,6 +161,7 @@ class TablePanelConfig extends Component {
|
|||
fields={this.props.fields}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
</div>
|
||||
|
@ -280,6 +281,7 @@ TablePanelConfig.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
export default TablePanelConfig;
|
||||
|
|
|
@ -119,6 +119,7 @@ class TimeseriesPanelConfigUi extends Component {
|
|||
fields={this.props.fields}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
|
@ -379,6 +380,7 @@ TimeseriesPanelConfigUi.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
const TimeseriesPanelConfig = injectI18n(TimeseriesPanelConfigUi);
|
||||
|
|
|
@ -77,6 +77,7 @@ class TopNPanelConfig extends Component {
|
|||
fields={this.props.fields}
|
||||
model={this.props.model}
|
||||
name={this.props.name}
|
||||
visData$={this.props.visData$}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
|
@ -246,6 +247,7 @@ TopNPanelConfig.propTypes = {
|
|||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
export default TopNPanelConfig;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { assign, get } from 'lodash';
|
||||
|
||||
import timeseries from './vis_types/timeseries/series';
|
||||
import metric from './vis_types/metric/series';
|
||||
|
@ -46,7 +46,10 @@ class Series extends Component {
|
|||
this.state = {
|
||||
visible: true,
|
||||
selectedTab: 'metrics',
|
||||
uiRestrictions: undefined,
|
||||
};
|
||||
|
||||
this.visDataSubscription = null;
|
||||
}
|
||||
|
||||
switchTab = (selectedTab) => {
|
||||
|
@ -56,7 +59,7 @@ class Series extends Component {
|
|||
handleChange = (part) => {
|
||||
if (this.props.onChange) {
|
||||
const { model } = this.props;
|
||||
const doc = _.assign({}, model, part);
|
||||
const doc = assign({}, model, part);
|
||||
this.props.onChange(doc);
|
||||
}
|
||||
};
|
||||
|
@ -71,12 +74,25 @@ class Series extends Component {
|
|||
|
||||
toggleVisible = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({ visible: !this.state.visible });
|
||||
|
||||
this.setState({
|
||||
visible: !this.state.visible
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.visData$) {
|
||||
this.visDataSubscription = this.props.visData$
|
||||
.subscribe(visData => this.setState({
|
||||
uiRestrictions: get(visData, 'uiRestrictions')
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { panel } = this.props;
|
||||
const Component = lookup[panel.type];
|
||||
|
||||
if (Component) {
|
||||
const params = {
|
||||
className: this.props.className,
|
||||
|
@ -98,6 +114,7 @@ class Series extends Component {
|
|||
selectedTab: this.state.selectedTab,
|
||||
sortData: this.props.sortData,
|
||||
style: this.props.style,
|
||||
uiRestrictions: this.state.uiRestrictions,
|
||||
switchTab: this.switchTab,
|
||||
toggleVisible: this.toggleVisible,
|
||||
togglePanelActivation: this.togglePanelActivation,
|
||||
|
@ -116,6 +133,11 @@ class Series extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.visDataSubscription) {
|
||||
this.visDataSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Series.defaultProps = {
|
||||
|
@ -139,6 +161,7 @@ Series.propTypes = {
|
|||
onTouchStart: PropTypes.func,
|
||||
model: PropTypes.object,
|
||||
panel: PropTypes.object,
|
||||
visData$: PropTypes.object,
|
||||
sortData: PropTypes.string,
|
||||
};
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ class SeriesEditor extends Component {
|
|||
onClone={() => this.handleClone(row)}
|
||||
onDelete={handleDelete.bind(null, props, row)}
|
||||
onShouldSortItem={(direction) => this.sortSeries(index, direction, allSeries)}
|
||||
visData$={this.props.visData$}
|
||||
model={row}
|
||||
panel={model}
|
||||
sortData={row.id}
|
||||
|
@ -115,7 +116,8 @@ SeriesEditor.propTypes = {
|
|||
limit: PropTypes.number,
|
||||
model: PropTypes.object,
|
||||
name: PropTypes.string,
|
||||
onChange: PropTypes.func
|
||||
onChange: PropTypes.func,
|
||||
visData$: PropTypes.object,
|
||||
};
|
||||
|
||||
export default SeriesEditor;
|
||||
|
|
|
@ -20,71 +20,77 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import uuid from 'uuid';
|
||||
import { get } from 'lodash';
|
||||
|
||||
import { SplitByTerms } from './splits/terms';
|
||||
import { SplitByFilter } from './splits/filter';
|
||||
import SplitByFilters from './splits/filters';
|
||||
import SplitByEverything from './splits/everything';
|
||||
import { SplitByFilters } from './splits/filters';
|
||||
import { SplitByEverything } from './splits/everything';
|
||||
import { SplitUnsupported } from './splits/unsupported_split';
|
||||
import { isGroupByFieldsEnabled } from '../lib/check_ui_restrictions';
|
||||
|
||||
const SPLIT_MODES = {
|
||||
FILTERS: 'filters',
|
||||
FILTER: 'filter',
|
||||
TERMS: 'terms',
|
||||
EVERYTHING: 'everything',
|
||||
};
|
||||
|
||||
class Split extends Component {
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { model } = nextProps;
|
||||
if (model.split_mode === 'filters' && !model.split_filters) {
|
||||
this.props.onChange({
|
||||
split_filters: [
|
||||
{ color: model.color, id: uuid.v1() }
|
||||
]
|
||||
{ color: model.color, id: uuid.v1() },
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getComponent(splitMode, uiRestrictions) {
|
||||
if (!isGroupByFieldsEnabled(splitMode, uiRestrictions)) {
|
||||
return SplitUnsupported;
|
||||
}
|
||||
|
||||
switch (splitMode) {
|
||||
case SPLIT_MODES.TERMS:
|
||||
return SplitByTerms;
|
||||
case SPLIT_MODES.FILTER:
|
||||
return SplitByFilter;
|
||||
case SPLIT_MODES.FILTERS:
|
||||
return SplitByFilters;
|
||||
default:
|
||||
return SplitByEverything;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { model, panel } = this.props;
|
||||
const { model, panel, uiRestrictions } = this.props;
|
||||
const indexPattern = model.override_index_pattern &&
|
||||
model.series_index_pattern ||
|
||||
panel.index_pattern;
|
||||
if (model.split_mode === 'filter') {
|
||||
return (
|
||||
<SplitByFilter
|
||||
model={model}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (model.split_mode === 'filters') {
|
||||
return (
|
||||
<SplitByFilters
|
||||
model={model}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (model.split_mode === 'terms') {
|
||||
return (
|
||||
<SplitByTerms
|
||||
model={model}
|
||||
indexPattern={indexPattern}
|
||||
fields={this.props.fields}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<SplitByEverything
|
||||
model={model}
|
||||
onChange={this.props.onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const splitMode = get(this.props, 'model.split_mode', SPLIT_MODES.EVERYTHING);
|
||||
|
||||
const Component = this.getComponent(splitMode, uiRestrictions);
|
||||
|
||||
return (
|
||||
<Component
|
||||
model={model}
|
||||
indexPattern={indexPattern}
|
||||
fields={this.props.fields}
|
||||
onChange={this.props.onChange}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
Split.propTypes = {
|
||||
fields: PropTypes.object,
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
panel: PropTypes.object
|
||||
panel: PropTypes.object,
|
||||
};
|
||||
|
||||
export default Split;
|
||||
|
|
|
@ -55,6 +55,7 @@ exports[`src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
|
|||
}
|
||||
indexPattern="kibana_sample_data_flights"
|
||||
onChange={[Function]}
|
||||
type="terms"
|
||||
value="OriginCityName"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
*/
|
||||
|
||||
import createSelectHandler from '../lib/create_select_handler';
|
||||
import GroupBySelect from './group_by_select';
|
||||
import { GroupBySelect } from './group_by_select';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
function SplitByEverything(props) {
|
||||
const { onChange, model } = props;
|
||||
export const SplitByEverything = (props) => {
|
||||
const { onChange, model, uiRestrictions } = props;
|
||||
const htmlId = htmlIdGenerator();
|
||||
const handleSelectChange = createSelectHandler(onChange);
|
||||
return (
|
||||
|
@ -41,18 +41,18 @@ function SplitByEverything(props) {
|
|||
<GroupBySelect
|
||||
value={model.split_mode}
|
||||
onChange={handleSelectChange('split_mode')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
SplitByEverything.propTypes = {
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func
|
||||
onChange: PropTypes.func,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export default SplitByEverything;
|
||||
|
||||
|
|
|
@ -19,14 +19,14 @@
|
|||
|
||||
import createTextHandler from '../lib/create_text_handler';
|
||||
import createSelectHandler from '../lib/create_select_handler';
|
||||
import GroupBySelect from './group_by_select';
|
||||
import { GroupBySelect } from './group_by_select';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldText } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const SplitByFilter = props => {
|
||||
const { onChange } = props;
|
||||
const { onChange, uiRestrictions } = props;
|
||||
const defaults = { filter: '' };
|
||||
const model = { ...defaults, ...props.model };
|
||||
const htmlId = htmlIdGenerator();
|
||||
|
@ -45,6 +45,7 @@ export const SplitByFilter = props => {
|
|||
<GroupBySelect
|
||||
value={model.split_mode}
|
||||
onChange={handleSelectChange('split_mode')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
|
@ -68,5 +69,6 @@ export const SplitByFilter = props => {
|
|||
|
||||
SplitByFilter.propTypes = {
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func
|
||||
onChange: PropTypes.func,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
|
|
@ -18,18 +18,18 @@
|
|||
*/
|
||||
|
||||
import createSelectHandler from '../lib/create_select_handler';
|
||||
import GroupBySelect from './group_by_select';
|
||||
import { GroupBySelect } from './group_by_select';
|
||||
import FilterItems from './filter_items';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
function SplitByFilters(props) {
|
||||
const { onChange, model } = props;
|
||||
export const SplitByFilters = (props) => {
|
||||
const { onChange, model, uiRestrictions } = props;
|
||||
const htmlId = htmlIdGenerator();
|
||||
const handleSelectChange = createSelectHandler(onChange);
|
||||
return(
|
||||
return (
|
||||
<div>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
|
@ -43,6 +43,7 @@ function SplitByFilters(props) {
|
|||
<GroupBySelect
|
||||
value={model.split_mode}
|
||||
onChange={handleSelectChange('split_mode')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
|
@ -55,11 +56,10 @@ function SplitByFilters(props) {
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
SplitByFilters.propTypes = {
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func
|
||||
onChange: PropTypes.func,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export default SplitByFilters;
|
||||
|
|
|
@ -23,31 +23,43 @@ import {
|
|||
EuiComboBox,
|
||||
} from '@elastic/eui';
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
import { isGroupByFieldsEnabled } from '../../lib/check_ui_restrictions';
|
||||
|
||||
function GroupBySelectUi(props) {
|
||||
const { intl } = props;
|
||||
const modeOptions = [
|
||||
const { intl, uiRestrictions } = props;
|
||||
const modeOptions = ([
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.everythingLabel', defaultMessage: 'Everything' }),
|
||||
value: 'everything'
|
||||
label: intl.formatMessage({
|
||||
id: 'tsvb.splits.groupBySelect.modeOptions.everythingLabel',
|
||||
defaultMessage: 'Everything',
|
||||
}),
|
||||
value: 'everything',
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.filterLabel', defaultMessage: 'Filter' }),
|
||||
value: 'filter'
|
||||
value: 'filter',
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.filtersLabel', defaultMessage: 'Filters' }),
|
||||
value: 'filters'
|
||||
label: intl.formatMessage({
|
||||
id: 'tsvb.splits.groupBySelect.modeOptions.filtersLabel',
|
||||
defaultMessage: 'Filters',
|
||||
}),
|
||||
value: 'filters',
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.termsLabel', defaultMessage: 'Terms' }),
|
||||
value: 'terms'
|
||||
}
|
||||
];
|
||||
value: 'terms',
|
||||
},
|
||||
]).map(field => ({
|
||||
...field,
|
||||
disabled: !isGroupByFieldsEnabled(field.value, uiRestrictions),
|
||||
}));
|
||||
|
||||
const selectedValue = props.value || 'everything';
|
||||
const selectedOption = modeOptions.find(option => {
|
||||
return selectedValue === option.value;
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiComboBox
|
||||
id={props.id}
|
||||
|
@ -58,13 +70,12 @@ function GroupBySelectUi(props) {
|
|||
singleSelection={{ asPlainText: true }}
|
||||
/>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
GroupBySelectUi.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string
|
||||
value: PropTypes.string,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
const GroupBySelect = injectI18n(GroupBySelectUi);
|
||||
export default GroupBySelect;
|
||||
export const GroupBySelect = injectI18n(GroupBySelectUi);
|
||||
|
|
|
@ -20,18 +20,26 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { get, find } from 'lodash';
|
||||
import GroupBySelect from './group_by_select';
|
||||
import { GroupBySelect } from './group_by_select';
|
||||
import createTextHandler from '../lib/create_text_handler';
|
||||
import createSelectHandler from '../lib/create_select_handler';
|
||||
import FieldSelect from '../aggs/field_select';
|
||||
import MetricSelect from '../aggs/metric_select';
|
||||
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldNumber, EuiComboBox, EuiFieldText } from '@elastic/eui';
|
||||
import {
|
||||
htmlIdGenerator,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiFieldNumber,
|
||||
EuiComboBox,
|
||||
EuiFieldText
|
||||
} from '@elastic/eui';
|
||||
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
|
||||
import { FIELD_TYPES } from '../../../common/field_types';
|
||||
|
||||
const DEFAULTS = { terms_direction: 'desc', terms_size: 10, terms_order_by: '_count' };
|
||||
|
||||
export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesModel, fields }) => {
|
||||
export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesModel, fields, uiRestrictions }) => {
|
||||
const htmlId = htmlIdGenerator();
|
||||
const handleTextChange = createTextHandler(onChange);
|
||||
const handleSelectChange = createSelectHandler(onChange);
|
||||
|
@ -76,6 +84,7 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
|
|||
<GroupBySelect
|
||||
value={model.split_mode}
|
||||
onChange={handleSelectChange('split_mode')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
|
@ -93,6 +102,8 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
|
|||
onChange={handleSelectChange('terms_field')}
|
||||
value={model.terms_field}
|
||||
fields={fields}
|
||||
uiRestrictions={uiRestrictions}
|
||||
type={'terms'}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
|
@ -186,7 +197,8 @@ SplitByTermsUI.propTypes = {
|
|||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
indexPattern: PropTypes.string,
|
||||
fields: PropTypes.object
|
||||
fields: PropTypes.object,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export const SplitByTerms = injectI18n(SplitByTermsUI);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 createSelectHandler from '../lib/create_select_handler';
|
||||
import { GroupBySelect } from './group_by_select';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiCode, EuiTitle } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const SplitUnsupported = (props) => {
|
||||
const { onChange, model, uiRestrictions } = props;
|
||||
const htmlId = htmlIdGenerator();
|
||||
const handleSelectChange = createSelectHandler(onChange);
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
id={htmlId('group')}
|
||||
label={(<FormattedMessage
|
||||
id="tsvb.splits.everything.groupByLabel"
|
||||
defaultMessage="Group by"
|
||||
/>)}
|
||||
>
|
||||
<GroupBySelect
|
||||
value={model.split_mode}
|
||||
onChange={handleSelectChange('split_mode')}
|
||||
uiRestrictions={uiRestrictions}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle className="tvbAggRow__unavailable" size="xxxs">
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="tsvb.unsupportedSplit.splitIsUnsupportedDescription"
|
||||
defaultMessage="Split by {modelType} is unsupported."
|
||||
values={{ modelType: (<EuiCode>{model.split_mode}</EuiCode>) }}
|
||||
/>
|
||||
</span>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
||||
SplitUnsupported.propTypes = {
|
||||
model: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue