diff --git a/Jenkinsfile b/Jenkinsfile index 98cc6994f229b..51aac31122c83 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,54 +4,56 @@ library 'kibana-pipeline-library' kibanaLibrary.load() kibanaPipeline(timeoutMinutes: 135, checkPrChanges: true) { - githubPr.withDefaultPrComments { - catchError { - retryable.enable() - parallel([ - 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), - 'x-pack-intake-agent': workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh'), - 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ - 'oss-firefoxSmoke': kibanaPipeline.functionalTestProcess('kibana-firefoxSmoke', './test/scripts/jenkins_firefox_smoke.sh'), - 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), - 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), - 'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3), - 'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4), - 'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5), - 'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6), - 'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7), - 'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8), - 'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9), - 'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10), - 'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11), - 'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12), - 'oss-accessibility': kibanaPipeline.functionalTestProcess('kibana-accessibility', './test/scripts/jenkins_accessibility.sh'), - // 'oss-visualRegression': kibanaPipeline.functionalTestProcess('visualRegression', './test/scripts/jenkins_visual_regression.sh'), - ]), - 'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ - 'xpack-firefoxSmoke': kibanaPipeline.functionalTestProcess('xpack-firefoxSmoke', './test/scripts/jenkins_xpack_firefox_smoke.sh'), - 'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1), - 'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2), - 'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3), - 'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4), - 'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5), - 'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6), - 'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7), - 'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8), - 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), - 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), - 'xpack-accessibility': kibanaPipeline.functionalTestProcess('xpack-accessibility', './test/scripts/jenkins_xpack_accessibility.sh'), - 'xpack-siemCypress': { processNumber -> - whenChanged(['x-pack/plugins/siem/', 'x-pack/legacy/plugins/siem/', 'x-pack/test/siem_cypress/']) { - kibanaPipeline.functionalTestProcess('xpack-siemCypress', './test/scripts/jenkins_siem_cypress.sh')(processNumber) - } - }, + ciStats.trackBuild { + githubPr.withDefaultPrComments { + catchError { + retryable.enable() + parallel([ + 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), + 'x-pack-intake-agent': workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh'), + 'kibana-oss-agent': workers.functional('kibana-oss-tests', { kibanaPipeline.buildOss() }, [ + 'oss-firefoxSmoke': kibanaPipeline.functionalTestProcess('kibana-firefoxSmoke', './test/scripts/jenkins_firefox_smoke.sh'), + 'oss-ciGroup1': kibanaPipeline.ossCiGroupProcess(1), + 'oss-ciGroup2': kibanaPipeline.ossCiGroupProcess(2), + 'oss-ciGroup3': kibanaPipeline.ossCiGroupProcess(3), + 'oss-ciGroup4': kibanaPipeline.ossCiGroupProcess(4), + 'oss-ciGroup5': kibanaPipeline.ossCiGroupProcess(5), + 'oss-ciGroup6': kibanaPipeline.ossCiGroupProcess(6), + 'oss-ciGroup7': kibanaPipeline.ossCiGroupProcess(7), + 'oss-ciGroup8': kibanaPipeline.ossCiGroupProcess(8), + 'oss-ciGroup9': kibanaPipeline.ossCiGroupProcess(9), + 'oss-ciGroup10': kibanaPipeline.ossCiGroupProcess(10), + 'oss-ciGroup11': kibanaPipeline.ossCiGroupProcess(11), + 'oss-ciGroup12': kibanaPipeline.ossCiGroupProcess(12), + 'oss-accessibility': kibanaPipeline.functionalTestProcess('kibana-accessibility', './test/scripts/jenkins_accessibility.sh'), + // 'oss-visualRegression': kibanaPipeline.functionalTestProcess('visualRegression', './test/scripts/jenkins_visual_regression.sh'), + ]), + 'kibana-xpack-agent': workers.functional('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [ + 'xpack-firefoxSmoke': kibanaPipeline.functionalTestProcess('xpack-firefoxSmoke', './test/scripts/jenkins_xpack_firefox_smoke.sh'), + 'xpack-ciGroup1': kibanaPipeline.xpackCiGroupProcess(1), + 'xpack-ciGroup2': kibanaPipeline.xpackCiGroupProcess(2), + 'xpack-ciGroup3': kibanaPipeline.xpackCiGroupProcess(3), + 'xpack-ciGroup4': kibanaPipeline.xpackCiGroupProcess(4), + 'xpack-ciGroup5': kibanaPipeline.xpackCiGroupProcess(5), + 'xpack-ciGroup6': kibanaPipeline.xpackCiGroupProcess(6), + 'xpack-ciGroup7': kibanaPipeline.xpackCiGroupProcess(7), + 'xpack-ciGroup8': kibanaPipeline.xpackCiGroupProcess(8), + 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), + 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), + 'xpack-accessibility': kibanaPipeline.functionalTestProcess('xpack-accessibility', './test/scripts/jenkins_xpack_accessibility.sh'), + 'xpack-siemCypress': { processNumber -> + whenChanged(['x-pack/plugins/siem/', 'x-pack/legacy/plugins/siem/', 'x-pack/test/siem_cypress/']) { + kibanaPipeline.functionalTestProcess('xpack-siemCypress', './test/scripts/jenkins_siem_cypress.sh')(processNumber) + } + }, - // 'xpack-visualRegression': kibanaPipeline.functionalTestProcess('xpack-visualRegression', './test/scripts/jenkins_xpack_visual_regression.sh'), - ]), - ]) + // 'xpack-visualRegression': kibanaPipeline.functionalTestProcess('xpack-visualRegression', './test/scripts/jenkins_xpack_visual_regression.sh'), + ]), + ]) + } } - } - retryable.printFlakyFailures() - kibanaPipeline.sendMail() + retryable.printFlakyFailures() + kibanaPipeline.sendMail() + } } diff --git a/docs/developer/core-development.asciidoc b/docs/developer/core-development.asciidoc index 447a4c6d2601b..8f356abd095f2 100644 --- a/docs/developer/core-development.asciidoc +++ b/docs/developer/core-development.asciidoc @@ -7,6 +7,7 @@ * <> * <> * <> +* <> include::core/development-basepath.asciidoc[] @@ -19,3 +20,5 @@ include::core/development-elasticsearch.asciidoc[] include::core/development-unit-tests.asciidoc[] include::core/development-functional-tests.asciidoc[] + +include::core/development-es-snapshots.asciidoc[] diff --git a/docs/developer/core/development-es-snapshots.asciidoc b/docs/developer/core/development-es-snapshots.asciidoc new file mode 100644 index 0000000000000..4cd4f31e582db --- /dev/null +++ b/docs/developer/core/development-es-snapshots.asciidoc @@ -0,0 +1,113 @@ +[[development-es-snapshots]] +=== Daily Elasticsearch Snapshots + +For local development and CI, Kibana, by default, uses Elasticsearch snapshots that are built daily when running tasks that require Elasticsearch (e.g. functional tests). + +A snapshot is just a group of tarballs, one for each supported distribution/architecture/os of Elasticsearch, and a JSON-based manifest file containing metadata about the distributions. + +https://ci.kibana.dev/es-snapshots[A dashboard] is available that shows the current status and compatibility of the latest Elasticsearch snapshots. + +==== Process Overview + +1. Elasticsearch snapshots are built for each current tracked branch of Kibana. +2. Each snapshot is uploaded to a public Google Cloud Storage bucket, `kibana-ci-es-snapshots-daily`. +** At this point, the snapshot is not automatically used in CI or local development. It needs to be tested/verified first. +3. Each snapshot is tested with the latest commit of the corresponding Kibana branch, using the full CI suite. +4. After CI +** If the snapshot passes, it is promoted and automatically used in CI and local development. +** If the snapshot fails, the issue must be investigated and resolved. A new incompatibility may exist between Elasticsearch and Kibana. + +==== Using the latest snapshot + +When developing locally, you may wish to use the most recent Elasticsearch snapshot, even if it's failing CI. To do so, prefix your commands with the follow environment variable: + +["source","bash"] +----------- +KBN_ES_SNAPSHOT_USE_UNVERIFIED=true +----------- + +You can use this flag with any command that downloads and runs Elasticsearch snapshots, such as `scripts/es` or the FTR. + +For example, to run functional tests with the latest snapshot: + +["source","bash"] +----------- +KBN_ES_SNAPSHOT_USE_UNVERIFIED=true node scripts/functional_tests_server +----------- + +===== For Pull Requests + +Currently, there is not a way to run your pull request with the latest unverified snapshot without a code change. You can, however, do it with a small code change. + +1. Edit `Jenkinsfile` in the root of the Kibana repo +2. Add `env.KBN_ES_SNAPSHOT_USE_UNVERIFIED = 'true'` at the top of the file. +3. Commit the change + +Your pull request should then use the latest snapshot the next time that it runs. Just don't merge the change to `Jenkinsfile`! + +==== Google Cloud Storage buckets + +===== kibana-ci-es-snapshots-daily + +This bucket stores snapshots that are created on a daily basis, and is the primary location used by `kbn-es` to download snapshots. + +Snapshots are automatically deleted after 10 days. + +The file structure for this bucket looks like this: + +* `/manifest-latest.json` +* `/manifest-latest-verified.json` +* `/archives//*.tar.gz` +* `/archives//*.tar.gz.sha512` +* `/archives//manifest.json` + +===== kibana-ci-es-snapshots-permanent + +This bucket stores only the most recently promoted snapshot for each version. Old snapshots are only deleted when new ones are uploaded. + +This bucket serves as permanent snapshot storage for old branches/versions that are no longer being built. `kbn-es` checks the daily bucket first, followed by this one if no snapshots were found. + +The file structure for this bucket looks like this: + +* `/*.tar.gz` +* `/*.tar.gz.sha512` +* `/manifest.json` + +==== How snapshots are built, tested, and promoted + +Each day, a https://kibana-ci.elastic.co/job/elasticsearch+snapshots+trigger/[Jenkins job] runs that triggers Elasticsearch builds for each currently tracked branch/version. This job is automatically updated with the correct branches whenever we release new versions of Kibana. + +===== Build + +https://kibana-ci.elastic.co/job/elasticsearch+snapshots+build/[This Jenkins job] builds the Elasticsearch snapshots and uploads them to GCS. + +The Jenkins job pipeline definition is https://github.com/elastic/kibana/blob/master/.ci/es-snapshots/Jenkinsfile_build_es[in the kibana repo]. + +1. Checkout Elasticsearch repo for the given branch/version. +2. Run `./gradlew -p distribution/archives assemble --parallel` to create all of the Elasticsearch distributions. +3. Create a tarball for each distribution. +4. Create a manifest JSON file containing info about the distribution, as well as its download URL. +5. Upload the tarballs and manifest to a unique location in the GCS bucket `kibana-ci-es-snapshots-daily`. +** e.g. `/archives/` +6. Replace `/manifest-latest.json` in GCS with this newest manifest. +** This allows the `KBN_ES_SNAPSHOT_USE_UNVERIFIED` flag to work. +7. Trigger the verification job, to run the full Kibana CI test suite with this snapshot. + +===== Verification and Promotion + +https://kibana-ci.elastic.co/job/elasticsearch+snapshots+verify/[This Jenkins job] tests the latest Elasticsearch snapshot with the full Kibana CI pipeline, and promotes if it there are no test failures. + +The Jenkins job pipeline definition is https://github.com/elastic/kibana/blob/master/.ci/es-snapshots/Jenkinsfile_verify_es[in the kibana repo]. + +1. Checkout Kibana and set up CI environment as normal. +2. Set the `ES_SNAPSHOT_MANIFEST` env var to point to the latest snapshot manifest. +3. Run CI (functional tests, integration tests, etc). +4. After CI +** If there was a test failure or other build error, send out an e-mail notification and stop. +** If there were no errors, promote the snapshot. + +Promotion is done as part of the same pipeline: + +1. Replace the manifest at `kibana-ci-es-snapshots-daily//manifest-latest-verified.json` with the manifest from the tested snapshot. +** At this point, the snapshot has been promoted and will automatically be used in CI and in local development. +2. Replace the snapshot at `kibana-ci-es-snapshots-permanent//` with the tested snapshot by copying all of the tarballs and the manifest file. \ No newline at end of file diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index b8cffb36b821a..a91a5bec988b7 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -263,13 +263,14 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectAttribute](./kibana-plugin-core-server.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-core-server.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-core-server.savedobjectattribute.md) | | [SavedObjectMigrationFn](./kibana-plugin-core-server.savedobjectmigrationfn.md) | A migration function for a [saved object type](./kibana-plugin-core-server.savedobjectstype.md) used to migrate it to a given version | -| [SavedObjectSanitizedDoc](./kibana-plugin-core-server.savedobjectsanitizeddoc.md) | | +| [SavedObjectSanitizedDoc](./kibana-plugin-core-server.savedobjectsanitizeddoc.md) | Describes Saved Object documents that have passed through the migration framework and are guaranteed to have a references root property. | | [SavedObjectsClientContract](./kibana-plugin-core-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.See [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) | | [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. | | [SavedObjectsClientFactoryProvider](./kibana-plugin-core-server.savedobjectsclientfactoryprovider.md) | Provider to invoke to retrieve a [SavedObjectsClientFactory](./kibana-plugin-core-server.savedobjectsclientfactory.md). | | [SavedObjectsClientWrapperFactory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. | | [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) | Describe a [saved object type mapping](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) field.Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation | | [SavedObjectsNamespaceType](./kibana-plugin-core-server.savedobjectsnamespacetype.md) | The namespace type dictates how a saved object can be interacted in relation to namespaces. Each type is mutually exclusive: \* single (default): this type of saved object is namespace-isolated, e.g., it exists in only one namespace. \* multiple: this type of saved object is shareable, e.g., it can exist in one or more namespaces. \* agnostic: this type of saved object is global.Note: do not write logic that uses this value directly; instead, use the appropriate accessors in the [type registry](./kibana-plugin-core-server.savedobjecttyperegistry.md). | +| [SavedObjectUnsanitizedDoc](./kibana-plugin-core-server.savedobjectunsanitizeddoc.md) | Describes Saved Object documents from Kibana < 7.0.0 which don't have a references root property defined. This type should only be used in migrations. | | [ScopeableRequest](./kibana-plugin-core-server.scopeablerequest.md) | A user credentials container. It accommodates the necessary auth credentials to impersonate the current user.See [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md). | | [ServiceStatusLevel](./kibana-plugin-core-server.servicestatuslevel.md) | A convenience type that represents the union of each value in [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md). | | [SharedGlobalConfig](./kibana-plugin-core-server.sharedglobalconfig.md) | | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsanitizeddoc.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsanitizeddoc.md index 47feb50e9a827..6d4e252fe7532 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsanitizeddoc.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsanitizeddoc.md @@ -4,6 +4,7 @@ ## SavedObjectSanitizedDoc type +Describes Saved Object documents that have passed through the migration framework and are guaranteed to have a `references` root property. Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectunsanitizeddoc.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectunsanitizeddoc.md new file mode 100644 index 0000000000000..be51400addbbc --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectunsanitizeddoc.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectUnsanitizedDoc](./kibana-plugin-core-server.savedobjectunsanitizeddoc.md) + +## SavedObjectUnsanitizedDoc type + +Describes Saved Object documents from Kibana < 7.0.0 which don't have a `references` root property defined. This type should only be used in migrations. + +Signature: + +```typescript +export declare type SavedObjectUnsanitizedDoc = SavedObjectDoc & Partial; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md new file mode 100644 index 0000000000000..43ff9a930b974 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [$$spec](./kibana-plugin-plugins-data-public.field.__spec.md) + +## Field.$$spec property + +Signature: + +```typescript +$$spec: FieldSpec; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md similarity index 68% rename from docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md index cf7470c035a53..c3b2ac8d30b5a 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [(constructor)](./kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md) +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [(constructor)](./kibana-plugin-plugins-data-public.field._constructor_.md) -## IndexPatternField.(constructor) +## Field.(constructor) Constructs a new instance of the `Field` class diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md new file mode 100644 index 0000000000000..fcfd7d73c8b0c --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [aggregatable](./kibana-plugin-plugins-data-public.field.aggregatable.md) + +## Field.aggregatable property + +Signature: + +```typescript +aggregatable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.conflictdescriptions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.conflictdescriptions.md new file mode 100644 index 0000000000000..21b6917c4aad4 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.conflictdescriptions.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [conflictDescriptions](./kibana-plugin-plugins-data-public.field.conflictdescriptions.md) + +## Field.conflictDescriptions property + +Signature: + +```typescript +conflictDescriptions?: Record; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md new file mode 100644 index 0000000000000..4f51d88a3046e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [count](./kibana-plugin-plugins-data-public.field.count.md) + +## Field.count property + +Signature: + +```typescript +count?: number; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md new file mode 100644 index 0000000000000..0846a7595cf90 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [displayName](./kibana-plugin-plugins-data-public.field.displayname.md) + +## Field.displayName property + +Signature: + +```typescript +displayName?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md new file mode 100644 index 0000000000000..efe1bceb43361 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [esTypes](./kibana-plugin-plugins-data-public.field.estypes.md) + +## Field.esTypes property + +Signature: + +```typescript +esTypes?: string[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md new file mode 100644 index 0000000000000..fd7be589e87a7 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [filterable](./kibana-plugin-plugins-data-public.field.filterable.md) + +## Field.filterable property + +Signature: + +```typescript +filterable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md new file mode 100644 index 0000000000000..431e043d1fecc --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [format](./kibana-plugin-plugins-data-public.field.format.md) + +## Field.format property + +Signature: + +```typescript +format: any; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md new file mode 100644 index 0000000000000..59420747e0958 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [indexPattern](./kibana-plugin-plugins-data-public.field.indexpattern.md) + +## Field.indexPattern property + +Signature: + +```typescript +indexPattern?: IndexPattern; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md new file mode 100644 index 0000000000000..d51857090356f --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [lang](./kibana-plugin-plugins-data-public.field.lang.md) + +## Field.lang property + +Signature: + +```typescript +lang?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md new file mode 100644 index 0000000000000..86ff2b2c28ae9 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md @@ -0,0 +1,41 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) + +## Field class + +Signature: + +```typescript +export declare class Field implements IFieldType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(indexPattern, spec, shortDotsEnable)](./kibana-plugin-plugins-data-public.field._constructor_.md) | | Constructs a new instance of the Field class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [$$spec](./kibana-plugin-plugins-data-public.field.__spec.md) | | FieldSpec | | +| [aggregatable](./kibana-plugin-plugins-data-public.field.aggregatable.md) | | boolean | | +| [conflictDescriptions](./kibana-plugin-plugins-data-public.field.conflictdescriptions.md) | | Record<string, string[]> | | +| [count](./kibana-plugin-plugins-data-public.field.count.md) | | number | | +| [displayName](./kibana-plugin-plugins-data-public.field.displayname.md) | | string | | +| [esTypes](./kibana-plugin-plugins-data-public.field.estypes.md) | | string[] | | +| [filterable](./kibana-plugin-plugins-data-public.field.filterable.md) | | boolean | | +| [format](./kibana-plugin-plugins-data-public.field.format.md) | | any | | +| [indexPattern](./kibana-plugin-plugins-data-public.field.indexpattern.md) | | IndexPattern | | +| [lang](./kibana-plugin-plugins-data-public.field.lang.md) | | string | | +| [name](./kibana-plugin-plugins-data-public.field.name.md) | | string | | +| [script](./kibana-plugin-plugins-data-public.field.script.md) | | string | | +| [scripted](./kibana-plugin-plugins-data-public.field.scripted.md) | | boolean | | +| [searchable](./kibana-plugin-plugins-data-public.field.searchable.md) | | boolean | | +| [sortable](./kibana-plugin-plugins-data-public.field.sortable.md) | | boolean | | +| [subType](./kibana-plugin-plugins-data-public.field.subtype.md) | | IFieldSubType | | +| [type](./kibana-plugin-plugins-data-public.field.type.md) | | string | | +| [visualizable](./kibana-plugin-plugins-data-public.field.visualizable.md) | | boolean | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md new file mode 100644 index 0000000000000..d2a9b9b86aefc --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [name](./kibana-plugin-plugins-data-public.field.name.md) + +## Field.name property + +Signature: + +```typescript +name: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md new file mode 100644 index 0000000000000..676ff9bdfc35a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [script](./kibana-plugin-plugins-data-public.field.script.md) + +## Field.script property + +Signature: + +```typescript +script?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md new file mode 100644 index 0000000000000..1f6c8105e3f61 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [scripted](./kibana-plugin-plugins-data-public.field.scripted.md) + +## Field.scripted property + +Signature: + +```typescript +scripted?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md new file mode 100644 index 0000000000000..186d344f50378 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [searchable](./kibana-plugin-plugins-data-public.field.searchable.md) + +## Field.searchable property + +Signature: + +```typescript +searchable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md new file mode 100644 index 0000000000000..0cd4b14d0e1e5 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [sortable](./kibana-plugin-plugins-data-public.field.sortable.md) + +## Field.sortable property + +Signature: + +```typescript +sortable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md new file mode 100644 index 0000000000000..bef3b2131fa47 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [subType](./kibana-plugin-plugins-data-public.field.subtype.md) + +## Field.subType property + +Signature: + +```typescript +subType?: IFieldSubType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md new file mode 100644 index 0000000000000..490615edcf097 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [type](./kibana-plugin-plugins-data-public.field.type.md) + +## Field.type property + +Signature: + +```typescript +type: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md new file mode 100644 index 0000000000000..f32a5c456dc5d --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [visualizable](./kibana-plugin-plugins-data-public.field.visualizable.md) + +## Field.visualizable property + +Signature: + +```typescript +visualizable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._constructor_.md new file mode 100644 index 0000000000000..e38da6600696c --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._constructor_.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [(constructor)](./kibana-plugin-plugins-data-public.fieldformat._constructor_.md) + +## FieldFormat.(constructor) + +Constructs a new instance of the `FieldFormat` class + +Signature: + +```typescript +constructor(_params?: IFieldFormatMetaParams, getConfig?: FieldFormatsGetConfigFn); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| \_params | IFieldFormatMetaParams | | +| getConfig | FieldFormatsGetConfigFn | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._params.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._params.md new file mode 100644 index 0000000000000..ac3f256a9afc3 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat._params.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [\_params](./kibana-plugin-plugins-data-public.fieldformat._params.md) + +## FieldFormat.\_params property + +Signature: + +```typescript +protected readonly _params: any; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convert.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convert.md new file mode 100644 index 0000000000000..0535585cb4718 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convert.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [convert](./kibana-plugin-plugins-data-public.fieldformat.convert.md) + +## FieldFormat.convert() method + +Convert a raw value to a formatted string + +Signature: + +```typescript +convert(value: any, contentType?: FieldFormatsContentType, options?: HtmlContextTypeOptions | TextContextTypeOptions): string; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| value | any | | +| contentType | FieldFormatsContentType | | +| options | HtmlContextTypeOptions | TextContextTypeOptions | | + +Returns: + +`string` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convertobject.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convertobject.md new file mode 100644 index 0000000000000..436124ac08387 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.convertobject.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [convertObject](./kibana-plugin-plugins-data-public.fieldformat.convertobject.md) + +## FieldFormat.convertObject property + + {FieldFormatConvert} have to remove the private because of https://github.com/Microsoft/TypeScript/issues/17293 + +Signature: + +```typescript +convertObject: FieldFormatConvert | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.fieldtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.fieldtype.md new file mode 100644 index 0000000000000..1d109a599d2d9 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.fieldtype.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [fieldType](./kibana-plugin-plugins-data-public.fieldformat.fieldtype.md) + +## FieldFormat.fieldType property + + {string} - Field Format Type + +Signature: + +```typescript +static fieldType: string | string[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.from.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.from.md new file mode 100644 index 0000000000000..ec497de59d236 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.from.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [from](./kibana-plugin-plugins-data-public.fieldformat.from.md) + +## FieldFormat.from() method + +Signature: + +```typescript +static from(convertFn: FieldFormatConvertFunction): FieldFormatInstanceType; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| convertFn | FieldFormatConvertFunction | | + +Returns: + +`FieldFormatInstanceType` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconfig.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconfig.md new file mode 100644 index 0000000000000..446e0c237ce13 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconfig.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [getConfig](./kibana-plugin-plugins-data-public.fieldformat.getconfig.md) + +## FieldFormat.getConfig property + +Signature: + +```typescript +protected getConfig: FieldFormatsGetConfigFn | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconverterfor.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconverterfor.md new file mode 100644 index 0000000000000..f4eeb5eed06a0 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getconverterfor.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [getConverterFor](./kibana-plugin-plugins-data-public.fieldformat.getconverterfor.md) + +## FieldFormat.getConverterFor() method + +Get a convert function that is bound to a specific contentType + +Signature: + +```typescript +getConverterFor(contentType?: FieldFormatsContentType): FieldFormatConvertFunction; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contentType | FieldFormatsContentType | | + +Returns: + +`FieldFormatConvertFunction` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getparamdefaults.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getparamdefaults.md new file mode 100644 index 0000000000000..59afdc25df350 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.getparamdefaults.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [getParamDefaults](./kibana-plugin-plugins-data-public.fieldformat.getparamdefaults.md) + +## FieldFormat.getParamDefaults() method + +Get parameter defaults {object} - parameter defaults + +Signature: + +```typescript +getParamDefaults(): Record; +``` +Returns: + +`Record` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md new file mode 100644 index 0000000000000..945ac7ededff6 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [htmlConvert](./kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md) + +## FieldFormat.htmlConvert property + + {htmlConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 + +Signature: + +```typescript +htmlConvert: HtmlContextTypeConvert | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.id.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.id.md new file mode 100644 index 0000000000000..91c3ff4f2d9a3 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.id.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [id](./kibana-plugin-plugins-data-public.fieldformat.id.md) + +## FieldFormat.id property + + {string} - Field Format Id + +Signature: + +```typescript +static id: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.isinstanceoffieldformat.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.isinstanceoffieldformat.md new file mode 100644 index 0000000000000..c6afa27fe5952 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.isinstanceoffieldformat.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [isInstanceOfFieldFormat](./kibana-plugin-plugins-data-public.fieldformat.isinstanceoffieldformat.md) + +## FieldFormat.isInstanceOfFieldFormat() method + +Signature: + +```typescript +static isInstanceOfFieldFormat(fieldFormat: any): fieldFormat is FieldFormat; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| fieldFormat | any | | + +Returns: + +`fieldFormat is FieldFormat` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md new file mode 100644 index 0000000000000..b53e301c46c1c --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md @@ -0,0 +1,46 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) + +## FieldFormat class + +Signature: + +```typescript +export declare abstract class FieldFormat +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(\_params, getConfig)](./kibana-plugin-plugins-data-public.fieldformat._constructor_.md) | | Constructs a new instance of the FieldFormat class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [\_params](./kibana-plugin-plugins-data-public.fieldformat._params.md) | | any | | +| [convertObject](./kibana-plugin-plugins-data-public.fieldformat.convertobject.md) | | FieldFormatConvert | undefined | {FieldFormatConvert} have to remove the private because of https://github.com/Microsoft/TypeScript/issues/17293 | +| [fieldType](./kibana-plugin-plugins-data-public.fieldformat.fieldtype.md) | static | string | string[] | {string} - Field Format Type | +| [getConfig](./kibana-plugin-plugins-data-public.fieldformat.getconfig.md) | | FieldFormatsGetConfigFn | undefined | | +| [htmlConvert](./kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md) | | HtmlContextTypeConvert | undefined | {htmlConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 | +| [id](./kibana-plugin-plugins-data-public.fieldformat.id.md) | static | string | {string} - Field Format Id | +| [textConvert](./kibana-plugin-plugins-data-public.fieldformat.textconvert.md) | | TextContextTypeConvert | undefined | {textConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 | +| [title](./kibana-plugin-plugins-data-public.fieldformat.title.md) | static | string | {string} - Field Format Title | +| [type](./kibana-plugin-plugins-data-public.fieldformat.type.md) | | any | {Function} - ref to child class | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [convert(value, contentType, options)](./kibana-plugin-plugins-data-public.fieldformat.convert.md) | | Convert a raw value to a formatted string | +| [from(convertFn)](./kibana-plugin-plugins-data-public.fieldformat.from.md) | static | | +| [getConverterFor(contentType)](./kibana-plugin-plugins-data-public.fieldformat.getconverterfor.md) | | Get a convert function that is bound to a specific contentType | +| [getParamDefaults()](./kibana-plugin-plugins-data-public.fieldformat.getparamdefaults.md) | | Get parameter defaults {object} - parameter defaults | +| [isInstanceOfFieldFormat(fieldFormat)](./kibana-plugin-plugins-data-public.fieldformat.isinstanceoffieldformat.md) | static | | +| [param(name)](./kibana-plugin-plugins-data-public.fieldformat.param.md) | | Get the value of a param. This value may be a default value. | +| [params()](./kibana-plugin-plugins-data-public.fieldformat.params.md) | | Get all of the params in a single object {object} | +| [setupContentType()](./kibana-plugin-plugins-data-public.fieldformat.setupcontenttype.md) | | | +| [toJSON()](./kibana-plugin-plugins-data-public.fieldformat.tojson.md) | | Serialize this format to a simple POJO, with only the params that are not default {object} | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.param.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.param.md new file mode 100644 index 0000000000000..1e7fd9d161429 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.param.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [param](./kibana-plugin-plugins-data-public.fieldformat.param.md) + +## FieldFormat.param() method + +Get the value of a param. This value may be a default value. + +Signature: + +```typescript +param(name: string): any; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | | + +Returns: + +`any` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.params.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.params.md new file mode 100644 index 0000000000000..5825af4925d06 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.params.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [params](./kibana-plugin-plugins-data-public.fieldformat.params.md) + +## FieldFormat.params() method + +Get all of the params in a single object {object} + +Signature: + +```typescript +params(): Record; +``` +Returns: + +`Record` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.setupcontenttype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.setupcontenttype.md new file mode 100644 index 0000000000000..41f5f2446f22a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.setupcontenttype.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [setupContentType](./kibana-plugin-plugins-data-public.fieldformat.setupcontenttype.md) + +## FieldFormat.setupContentType() method + +Signature: + +```typescript +setupContentType(): FieldFormatConvert; +``` +Returns: + +`FieldFormatConvert` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.textconvert.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.textconvert.md new file mode 100644 index 0000000000000..57ccca9136081 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.textconvert.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [textConvert](./kibana-plugin-plugins-data-public.fieldformat.textconvert.md) + +## FieldFormat.textConvert property + + {textConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 + +Signature: + +```typescript +textConvert: TextContextTypeConvert | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.title.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.title.md new file mode 100644 index 0000000000000..b19246758f080 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.title.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [title](./kibana-plugin-plugins-data-public.fieldformat.title.md) + +## FieldFormat.title property + + {string} - Field Format Title + +Signature: + +```typescript +static title: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.tojson.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.tojson.md new file mode 100644 index 0000000000000..5fa7d4841537b --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.tojson.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [toJSON](./kibana-plugin-plugins-data-public.fieldformat.tojson.md) + +## FieldFormat.toJSON() method + +Serialize this format to a simple POJO, with only the params that are not default + + {object} + +Signature: + +```typescript +toJSON(): { + id: unknown; + params: _.Dictionary | undefined; + }; +``` +Returns: + +`{ + id: unknown; + params: _.Dictionary | undefined; + }` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.type.md new file mode 100644 index 0000000000000..394a2e3cc9afb --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.type.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [type](./kibana-plugin-plugins-data-public.fieldformat.type.md) + +## FieldFormat.type property + + {Function} - ref to child class + +Signature: + +```typescript +type: any; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md deleted file mode 100644 index f52a3324af36f..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [$$spec](./kibana-plugin-plugins-data-public.indexpatternfield.__spec.md) - -## IndexPatternField.$$spec property - -Signature: - -```typescript -$$spec: FieldSpec; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md deleted file mode 100644 index 267c8f786b5dd..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [aggregatable](./kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md) - -## IndexPatternField.aggregatable property - -Signature: - -```typescript -aggregatable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md deleted file mode 100644 index 8e848276f21c4..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [count](./kibana-plugin-plugins-data-public.indexpatternfield.count.md) - -## IndexPatternField.count property - -Signature: - -```typescript -count?: number; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md deleted file mode 100644 index ed9630f92fc97..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [displayName](./kibana-plugin-plugins-data-public.indexpatternfield.displayname.md) - -## IndexPatternField.displayName property - -Signature: - -```typescript -displayName?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md deleted file mode 100644 index dec74df099d43..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [esTypes](./kibana-plugin-plugins-data-public.indexpatternfield.estypes.md) - -## IndexPatternField.esTypes property - -Signature: - -```typescript -esTypes?: string[]; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md deleted file mode 100644 index 4290c4a2f86b3..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [filterable](./kibana-plugin-plugins-data-public.indexpatternfield.filterable.md) - -## IndexPatternField.filterable property - -Signature: - -```typescript -filterable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md deleted file mode 100644 index d5df8ed628cb0..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [format](./kibana-plugin-plugins-data-public.indexpatternfield.format.md) - -## IndexPatternField.format property - -Signature: - -```typescript -format: any; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md deleted file mode 100644 index d1a1ee0905c6e..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [indexPattern](./kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md) - -## IndexPatternField.indexPattern property - -Signature: - -```typescript -indexPattern?: IndexPattern; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md deleted file mode 100644 index f731be8f613cf..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [lang](./kibana-plugin-plugins-data-public.indexpatternfield.lang.md) - -## IndexPatternField.lang property - -Signature: - -```typescript -lang?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md deleted file mode 100644 index df0de6ce0e541..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md +++ /dev/null @@ -1,40 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) - -## IndexPatternField class - -Signature: - -```typescript -export declare class Field implements IFieldType -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(indexPattern, spec, shortDotsEnable)](./kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md) | | Constructs a new instance of the Field class | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [$$spec](./kibana-plugin-plugins-data-public.indexpatternfield.__spec.md) | | FieldSpec | | -| [aggregatable](./kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md) | | boolean | | -| [count](./kibana-plugin-plugins-data-public.indexpatternfield.count.md) | | number | | -| [displayName](./kibana-plugin-plugins-data-public.indexpatternfield.displayname.md) | | string | | -| [esTypes](./kibana-plugin-plugins-data-public.indexpatternfield.estypes.md) | | string[] | | -| [filterable](./kibana-plugin-plugins-data-public.indexpatternfield.filterable.md) | | boolean | | -| [format](./kibana-plugin-plugins-data-public.indexpatternfield.format.md) | | any | | -| [indexPattern](./kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md) | | IndexPattern | | -| [lang](./kibana-plugin-plugins-data-public.indexpatternfield.lang.md) | | string | | -| [name](./kibana-plugin-plugins-data-public.indexpatternfield.name.md) | | string | | -| [script](./kibana-plugin-plugins-data-public.indexpatternfield.script.md) | | string | | -| [scripted](./kibana-plugin-plugins-data-public.indexpatternfield.scripted.md) | | boolean | | -| [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) | | boolean | | -| [sortable](./kibana-plugin-plugins-data-public.indexpatternfield.sortable.md) | | boolean | | -| [subType](./kibana-plugin-plugins-data-public.indexpatternfield.subtype.md) | | IFieldSubType | | -| [type](./kibana-plugin-plugins-data-public.indexpatternfield.type.md) | | string | | -| [visualizable](./kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md) | | boolean | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md deleted file mode 100644 index cb24621e73209..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [name](./kibana-plugin-plugins-data-public.indexpatternfield.name.md) - -## IndexPatternField.name property - -Signature: - -```typescript -name: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md deleted file mode 100644 index 132ba25a47637..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [script](./kibana-plugin-plugins-data-public.indexpatternfield.script.md) - -## IndexPatternField.script property - -Signature: - -```typescript -script?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md deleted file mode 100644 index 1dd6bc865a75d..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [scripted](./kibana-plugin-plugins-data-public.indexpatternfield.scripted.md) - -## IndexPatternField.scripted property - -Signature: - -```typescript -scripted?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md deleted file mode 100644 index 42f984d851435..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) - -## IndexPatternField.searchable property - -Signature: - -```typescript -searchable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md deleted file mode 100644 index 72d225185140b..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [sortable](./kibana-plugin-plugins-data-public.indexpatternfield.sortable.md) - -## IndexPatternField.sortable property - -Signature: - -```typescript -sortable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md deleted file mode 100644 index 2d807f8a5739c..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [subType](./kibana-plugin-plugins-data-public.indexpatternfield.subtype.md) - -## IndexPatternField.subType property - -Signature: - -```typescript -subType?: IFieldSubType; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md deleted file mode 100644 index c8483c9b83c9a..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [type](./kibana-plugin-plugins-data-public.indexpatternfield.type.md) - -## IndexPatternField.type property - -Signature: - -```typescript -type: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md deleted file mode 100644 index dd661ae779c11..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [visualizable](./kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md) - -## IndexPatternField.visualizable property - -Signature: - -```typescript -visualizable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 604ac5120922b..0fd82ffb2240c 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -11,9 +11,10 @@ | [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) | | | [AggTypeFieldFilters](./kibana-plugin-plugins-data-public.aggtypefieldfilters.md) | A registry to store which are used to filter down available fields for a specific visualization and . | | [AggTypeFilters](./kibana-plugin-plugins-data-public.aggtypefilters.md) | A registry to store which are used to filter down available aggregations for a specific visualization and . | +| [Field](./kibana-plugin-plugins-data-public.field.md) | | +| [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) | | | [FilterManager](./kibana-plugin-plugins-data-public.filtermanager.md) | | | [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) | | -| [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) | | | [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) | | | [IndexPatternSelect](./kibana-plugin-plugins-data-public.indexpatternselect.md) | | | [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index 4d7a0b3cfbbca..bd617990a00a2 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -9,7 +9,7 @@ ```typescript setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; search: ISearchSetup; }; @@ -26,7 +26,7 @@ setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { `{ fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; search: ISearchSetup; }` diff --git a/package.json b/package.json index bf5f270cabe99..bfea8c7423f9c 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "**/@types/hapi": "^17.0.18", "**/@types/angular": "^1.6.56", "**/@types/hoist-non-react-statics": "^3.3.1", + "**/@types/chai": "^4.2.11", "**/typescript": "3.7.2", "**/graphql-toolkit/lodash": "^4.17.13", "**/hoist-non-react-statics": "^3.3.2", diff --git a/packages/kbn-dev-utils/package.json b/packages/kbn-dev-utils/package.json index ee9f349f49051..08b2e5b226967 100644 --- a/packages/kbn-dev-utils/package.json +++ b/packages/kbn-dev-utils/package.json @@ -10,6 +10,7 @@ "kbn:watch": "yarn build --watch" }, "dependencies": { + "axios": "^0.19.0", "chalk": "^2.4.2", "dedent": "^0.7.0", "execa": "^4.0.0", diff --git a/packages/kbn-dev-utils/src/ci_stats_reporter/README.md b/packages/kbn-dev-utils/src/ci_stats_reporter/README.md new file mode 100644 index 0000000000000..6133f9871699f --- /dev/null +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/README.md @@ -0,0 +1,23 @@ +# Kibana CI Stats reporter + +We're working on building a new service, the Kibana CI Stats service, which will collect information about CI runs and metrics produced while testing Kibana, and then provide tools for reporting on those metrics in specific PRs and overall as a way to spot trends. + +### `CiStatsReporter` + +This class integrates with the `ciStats.trackBuild {}` Jenkins Pipeline function, consuming the `KIBANA_CI_STATS_CONFIG` variable produced by that wrapper, and then allowing test code to report stats to the service. + +To create an instance of the reporter, import the class and call `CiStatsReporter.fromEnv(log)` (passing it a tooling log). + +#### `CiStatsReporter#metric(name: string, subName: string, value: number)` + +Use this method to record metrics in the Kibana CI Stats service. + +Example: + +```ts +import { CiStatsReporter, ToolingLog } from '@kbn/dev-utils'; + +const log = new ToolingLog(...); +const reporter = CiStatsReporter.fromEnv(log) +reporter.metric('Build speed', specificBuildName, timeToRunBuild) +``` \ No newline at end of file diff --git a/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts new file mode 100644 index 0000000000000..5fe1844a85563 --- /dev/null +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/ci_stats_reporter.ts @@ -0,0 +1,153 @@ +/* + * 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 { inspect } from 'util'; + +import Axios from 'axios'; + +import { ToolingLog } from '../tooling_log'; + +interface Config { + apiUrl: string; + apiToken: string; + buildId: string; +} + +function parseConfig(log: ToolingLog) { + const configJson = process.env.KIBANA_CI_STATS_CONFIG; + if (!configJson) { + log.debug('KIBANA_CI_STATS_CONFIG environment variable not found, disabling CiStatsReporter'); + return; + } + + let config: unknown; + try { + config = JSON.parse(configJson); + } catch (_) { + // handled below + } + + if (typeof config === 'object' && config !== null) { + return validateConfig(log, config as { [k in keyof Config]: unknown }); + } + + log.warning('KIBANA_CI_STATS_CONFIG is invalid, stats will not be reported'); + return; +} + +function validateConfig(log: ToolingLog, config: { [k in keyof Config]: unknown }) { + const validApiUrl = typeof config.apiUrl === 'string' && config.apiUrl.length !== 0; + if (!validApiUrl) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid api url, stats will not be reported'); + return; + } + + const validApiToken = typeof config.apiToken === 'string' && config.apiToken.length !== 0; + if (!validApiToken) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid api token, stats will not be reported'); + return; + } + + const validId = typeof config.buildId === 'string' && config.buildId.length !== 0; + if (!validId) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid build id, stats will not be reported'); + return; + } + + return config as Config; +} + +export class CiStatsReporter { + static fromEnv(log: ToolingLog) { + return new CiStatsReporter(parseConfig(log), log); + } + + constructor(private config: Config | undefined, private log: ToolingLog) {} + + isEnabled() { + return !!this.config; + } + + async metric(name: string, subName: string, value: number) { + if (!this.config) { + return; + } + + let attempt = 0; + const maxAttempts = 5; + + while (true) { + attempt += 1; + + try { + await Axios.request({ + method: 'POST', + url: '/metric', + baseURL: this.config.apiUrl, + params: { + buildId: this.config.buildId, + }, + headers: { + Authorization: `token ${this.config.apiToken}`, + }, + data: { + name, + subName, + value, + }, + }); + + return; + } catch (error) { + if (!error?.request) { + // not an axios error, must be a usage error that we should notify user about + throw error; + } + + if (error?.response && error.response.status !== 502) { + // error response from service was received so warn the user and move on + this.log.warning( + `error recording metric [status=${error.response.status}] [resp=${inspect( + error.response.data + )}] [${name}/${subName}=${value}]` + ); + return; + } + + if (attempt === maxAttempts) { + this.log.warning( + `failed to reach kibana-ci-stats service too many times, unable to record metric [${name}/${subName}=${value}]` + ); + return; + } + + // we failed to reach the backend and we have remaining attempts, lets retry after a short delay + const reason = error?.response?.status + ? `${error.response.status} response` + : 'no response'; + + this.log.warning( + `failed to reach kibana-ci-stats service [reason=${reason}], retrying in ${attempt} seconds` + ); + + await new Promise(resolve => setTimeout(resolve, attempt * 1000)); + } + } + } +} diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.js b/packages/kbn-dev-utils/src/ci_stats_reporter/index.ts similarity index 94% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.js rename to packages/kbn-dev-utils/src/ci_stats_reporter/index.ts index 506002df4fd07..3487de08f034d 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.js +++ b/packages/kbn-dev-utils/src/ci_stats_reporter/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { DefaultFormatEditor } from './default'; +export * from './ci_stats_reporter'; diff --git a/packages/kbn-dev-utils/src/index.ts b/packages/kbn-dev-utils/src/index.ts index 305e29a0e41df..40ee72d94729f 100644 --- a/packages/kbn-dev-utils/src/index.ts +++ b/packages/kbn-dev-utils/src/index.ts @@ -37,3 +37,4 @@ export { run, createFailError, createFlagError, combineErrors, isFailError, Flag export { REPO_ROOT } from './repo_root'; export { KbnClient } from './kbn_client'; export * from './axios'; +export * from './ci_stats_reporter'; diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index c0bb408d60d8f..e46075eff63a7 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -21,10 +21,11 @@ import 'source-map-support/register'; import Path from 'path'; -import { run, REPO_ROOT, createFlagError } from '@kbn/dev-utils'; +import { run, REPO_ROOT, createFlagError, createFailError, CiStatsReporter } from '@kbn/dev-utils'; import { logOptimizerState } from './log_optimizer_state'; import { OptimizerConfig } from './optimizer'; +import { reportOptimizerStats } from './report_optimizer_stats'; import { runOptimizer } from './run_optimizer'; run( @@ -81,6 +82,11 @@ run( throw createFlagError('expected --scan-dir to be a string'); } + const reportStatsName = flags['report-stats']; + if (reportStatsName !== undefined && typeof reportStatsName !== 'string') { + throw createFlagError('expected --report-stats to be a string'); + } + const config = OptimizerConfig.create({ repoRoot: REPO_ROOT, watch, @@ -95,14 +101,24 @@ run( includeCoreBundle, }); - await runOptimizer(config) - .pipe(logOptimizerState(log, config)) - .toPromise(); + let update$ = runOptimizer(config); + + if (reportStatsName) { + const reporter = CiStatsReporter.fromEnv(log); + + if (!reporter.isEnabled()) { + throw createFailError('Unable to initialize CiStatsReporter from env'); + } + + update$ = update$.pipe(reportOptimizerStats(reporter, reportStatsName)); + } + + await update$.pipe(logOptimizerState(log, config)).toPromise(); }, { flags: { boolean: ['core', 'watch', 'oss', 'examples', 'dist', 'cache', 'profile', 'inspect-workers'], - string: ['workers', 'scan-dir'], + string: ['workers', 'scan-dir', 'report-stats'], default: { core: true, examples: true, @@ -120,6 +136,7 @@ run( --dist create bundles that are suitable for inclusion in the Kibana distributable --scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary) --no-inspect-workers when inspecting the parent process, don't inspect the workers + --report-stats=[name] attempt to report stats about this execution of the build to the kibana-ci-stats service using this name `, }, } diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index 8026cf39db73d..29922944e8817 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -21,3 +21,4 @@ export { OptimizerConfig } from './optimizer'; export * from './run_optimizer'; export * from './log_optimizer_state'; export * from './common/disallowed_syntax_plugin'; +export * from './report_optimizer_stats'; diff --git a/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts index 5dd500cd7a9e4..b4b02649259a2 100644 --- a/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts +++ b/packages/kbn-optimizer/src/optimizer/handle_optimizer_completion.ts @@ -17,20 +17,20 @@ * under the License. */ -import * as Rx from 'rxjs'; import { tap } from 'rxjs/operators'; import { createFailError } from '@kbn/dev-utils'; -import { pipeClosure, Update } from '../common'; +import { pipeClosure } from '../common'; +import { OptimizerUpdate$ } from '../run_optimizer'; import { OptimizerState } from './optimizer_state'; import { OptimizerConfig } from './optimizer_config'; export function handleOptimizerCompletion(config: OptimizerConfig) { - return pipeClosure((source$: Rx.Observable>) => { + return pipeClosure((update$: OptimizerUpdate$) => { let prevState: OptimizerState | undefined; - return source$.pipe( + return update$.pipe( tap({ next: update => { prevState = update.state; diff --git a/packages/kbn-optimizer/src/report_optimizer_stats.ts b/packages/kbn-optimizer/src/report_optimizer_stats.ts new file mode 100644 index 0000000000000..375978b9b7944 --- /dev/null +++ b/packages/kbn-optimizer/src/report_optimizer_stats.ts @@ -0,0 +1,46 @@ +/* + * 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 { materialize, mergeMap, dematerialize } from 'rxjs/operators'; +import { CiStatsReporter } from '@kbn/dev-utils'; + +import { OptimizerUpdate$ } from './run_optimizer'; +import { OptimizerState } from './optimizer'; +import { pipeClosure } from './common'; + +export function reportOptimizerStats(reporter: CiStatsReporter, name: string) { + return pipeClosure((update$: OptimizerUpdate$) => { + let lastState: OptimizerState | undefined; + return update$.pipe( + materialize(), + mergeMap(async n => { + if (n.kind === 'N' && n.value?.state) { + lastState = n.value?.state; + } + + if (n.kind === 'C' && lastState) { + await reporter.metric('@kbn/optimizer build time', name, lastState.durSec); + } + + return n; + }), + dematerialize() + ); + }); +} diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index b921956642728..5b53bf60f91c4 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,21 +94,21 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(703); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(705); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(500); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(502); /* 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__(515); +/* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(517); /* 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__(576); +/* harmony import */ var _utils_workspaces__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(578); /* 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__(577); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(579); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -152,7 +152,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(687); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(689); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(34); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -2506,9 +2506,9 @@ module.exports = require("path"); __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); -/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(584); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(684); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(685); +/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(586); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(686); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(687); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -2549,10 +2549,10 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _utils_link_project_executables__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(19); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(499); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(500); -/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(578); -/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(583); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(501); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(502); +/* harmony import */ var _utils_project_checksums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(580); +/* harmony import */ var _utils_bootstrap_cache_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(585); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -4517,6 +4517,7 @@ exports.REPO_ROOT = repo_root_1.REPO_ROOT; var kbn_client_1 = __webpack_require__(449); exports.KbnClient = kbn_client_1.KbnClient; tslib_1.__exportStar(__webpack_require__(492), exports); +tslib_1.__exportStar(__webpack_require__(499), exports); /***/ }), @@ -40169,9 +40170,9 @@ module.exports = __webpack_require__(454); var utils = __webpack_require__(455); var bind = __webpack_require__(456); -var Axios = __webpack_require__(458); +var Axios = __webpack_require__(457); var mergeConfig = __webpack_require__(488); -var defaults = __webpack_require__(464); +var defaults = __webpack_require__(463); /** * Create an instance of Axios @@ -40206,7 +40207,7 @@ axios.create = function create(instanceConfig) { // Expose Cancel & CancelToken axios.Cancel = __webpack_require__(489); axios.CancelToken = __webpack_require__(490); -axios.isCancel = __webpack_require__(463); +axios.isCancel = __webpack_require__(462); // Expose all/spread axios.all = function all(promises) { @@ -40228,7 +40229,6 @@ module.exports.default = axios; var bind = __webpack_require__(456); -var isBuffer = __webpack_require__(457); /*global toString:true*/ @@ -40246,6 +40246,27 @@ function isArray(val) { return toString.call(val) === '[object Array]'; } +/** + * Determine if a value is undefined + * + * @param {Object} val The value to test + * @returns {boolean} True if the value is undefined, otherwise false + */ +function isUndefined(val) { + return typeof val === 'undefined'; +} + +/** + * Determine if a value is a Buffer + * + * @param {Object} val The value to test + * @returns {boolean} True if value is a Buffer, otherwise false + */ +function isBuffer(val) { + return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) + && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val); +} + /** * Determine if a value is an ArrayBuffer * @@ -40302,16 +40323,6 @@ function isNumber(val) { return typeof val === 'number'; } -/** - * Determine if a value is undefined - * - * @param {Object} val The value to test - * @returns {boolean} True if the value is undefined, otherwise false - */ -function isUndefined(val) { - return typeof val === 'undefined'; -} - /** * Determine if a value is an Object * @@ -40581,32 +40592,15 @@ module.exports = function bind(fn, thisArg) { /***/ }), /* 457 */ -/***/ (function(module, exports) { - -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -module.exports = function isBuffer (obj) { - return obj != null && obj.constructor != null && - typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - - -/***/ }), -/* 458 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var utils = __webpack_require__(455); -var buildURL = __webpack_require__(459); -var InterceptorManager = __webpack_require__(460); -var dispatchRequest = __webpack_require__(461); +var buildURL = __webpack_require__(458); +var InterceptorManager = __webpack_require__(459); +var dispatchRequest = __webpack_require__(460); var mergeConfig = __webpack_require__(488); /** @@ -40638,7 +40632,15 @@ Axios.prototype.request = function request(config) { } config = mergeConfig(this.defaults, config); - config.method = config.method ? config.method.toLowerCase() : 'get'; + + // Set config.method + if (config.method) { + config.method = config.method.toLowerCase(); + } else if (this.defaults.method) { + config.method = this.defaults.method.toLowerCase(); + } else { + config.method = 'get'; + } // Hook up interceptors middleware var chain = [dispatchRequest, undefined]; @@ -40690,7 +40692,7 @@ module.exports = Axios; /***/ }), -/* 459 */ +/* 458 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40768,7 +40770,7 @@ module.exports = function buildURL(url, params, paramsSerializer) { /***/ }), -/* 460 */ +/* 459 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40827,18 +40829,16 @@ module.exports = InterceptorManager; /***/ }), -/* 461 */ +/* 460 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var utils = __webpack_require__(455); -var transformData = __webpack_require__(462); -var isCancel = __webpack_require__(463); -var defaults = __webpack_require__(464); -var isAbsoluteURL = __webpack_require__(486); -var combineURLs = __webpack_require__(487); +var transformData = __webpack_require__(461); +var isCancel = __webpack_require__(462); +var defaults = __webpack_require__(463); /** * Throws a `Cancel` if cancellation has been requested. @@ -40858,11 +40858,6 @@ function throwIfCancellationRequested(config) { module.exports = function dispatchRequest(config) { throwIfCancellationRequested(config); - // Support baseURL config - if (config.baseURL && !isAbsoluteURL(config.url)) { - config.url = combineURLs(config.baseURL, config.url); - } - // Ensure headers exist config.headers = config.headers || {}; @@ -40877,7 +40872,7 @@ module.exports = function dispatchRequest(config) { config.headers = utils.merge( config.headers.common || {}, config.headers[config.method] || {}, - config.headers || {} + config.headers ); utils.forEach( @@ -40920,7 +40915,7 @@ module.exports = function dispatchRequest(config) { /***/ }), -/* 462 */ +/* 461 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40947,7 +40942,7 @@ module.exports = function transformData(data, headers, fns) { /***/ }), -/* 463 */ +/* 462 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40959,14 +40954,14 @@ module.exports = function isCancel(value) { /***/ }), -/* 464 */ +/* 463 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var utils = __webpack_require__(455); -var normalizeHeaderName = __webpack_require__(465); +var normalizeHeaderName = __webpack_require__(464); var DEFAULT_CONTENT_TYPE = { 'Content-Type': 'application/x-www-form-urlencoded' @@ -40980,13 +40975,12 @@ function setContentTypeIfUnset(headers, value) { function getDefaultAdapter() { var adapter; - // Only Node.JS has a process variable that is of [[Class]] process - if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { - // For node use HTTP adapter - adapter = __webpack_require__(466); - } else if (typeof XMLHttpRequest !== 'undefined') { + if (typeof XMLHttpRequest !== 'undefined') { // For browsers use XHR adapter - adapter = __webpack_require__(482); + adapter = __webpack_require__(465); + } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { + // For node use HTTP adapter + adapter = __webpack_require__(475); } return adapter; } @@ -41064,7 +41058,7 @@ module.exports = defaults; /***/ }), -/* 465 */ +/* 464 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41083,295 +41077,200 @@ module.exports = function normalizeHeaderName(headers, normalizedName) { /***/ }), -/* 466 */ +/* 465 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var utils = __webpack_require__(455); -var settle = __webpack_require__(467); -var buildURL = __webpack_require__(459); -var http = __webpack_require__(470); -var https = __webpack_require__(471); -var httpFollow = __webpack_require__(472).http; -var httpsFollow = __webpack_require__(472).https; -var url = __webpack_require__(452); -var zlib = __webpack_require__(480); -var pkg = __webpack_require__(481); -var createError = __webpack_require__(468); -var enhanceError = __webpack_require__(469); - -var isHttps = /https:?/; +var settle = __webpack_require__(466); +var buildURL = __webpack_require__(458); +var buildFullPath = __webpack_require__(469); +var parseHeaders = __webpack_require__(472); +var isURLSameOrigin = __webpack_require__(473); +var createError = __webpack_require__(467); -/*eslint consistent-return:0*/ -module.exports = function httpAdapter(config) { - return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) { - var timer; - var resolve = function resolve(value) { - clearTimeout(timer); - resolvePromise(value); - }; - var reject = function reject(value) { - clearTimeout(timer); - rejectPromise(value); - }; - var data = config.data; - var headers = config.headers; +module.exports = function xhrAdapter(config) { + return new Promise(function dispatchXhrRequest(resolve, reject) { + var requestData = config.data; + var requestHeaders = config.headers; - // Set User-Agent (required by some servers) - // Only set header if it hasn't been set in config - // See https://github.com/axios/axios/issues/69 - if (!headers['User-Agent'] && !headers['user-agent']) { - headers['User-Agent'] = 'axios/' + pkg.version; + if (utils.isFormData(requestData)) { + delete requestHeaders['Content-Type']; // Let the browser set it } - if (data && !utils.isStream(data)) { - if (Buffer.isBuffer(data)) { - // Nothing to do... - } else if (utils.isArrayBuffer(data)) { - data = Buffer.from(new Uint8Array(data)); - } else if (utils.isString(data)) { - data = Buffer.from(data, 'utf-8'); - } else { - return reject(createError( - 'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream', - config - )); - } - - // Add Content-Length header if data exists - headers['Content-Length'] = data.length; - } + var request = new XMLHttpRequest(); // HTTP basic authentication - var auth = undefined; if (config.auth) { var username = config.auth.username || ''; var password = config.auth.password || ''; - auth = username + ':' + password; + requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); } - // Parse url - var parsed = url.parse(config.url); - var protocol = parsed.protocol || 'http:'; + var fullPath = buildFullPath(config.baseURL, config.url); + request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); - if (!auth && parsed.auth) { - var urlAuth = parsed.auth.split(':'); - var urlUsername = urlAuth[0] || ''; - var urlPassword = urlAuth[1] || ''; - auth = urlUsername + ':' + urlPassword; - } + // Set the request timeout in MS + request.timeout = config.timeout; - if (auth) { - delete headers.Authorization; - } + // Listen for ready state + request.onreadystatechange = function handleLoad() { + if (!request || request.readyState !== 4) { + return; + } - var isHttpsRequest = isHttps.test(protocol); - var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent; + // The request errored out and we didn't get a response, this will be + // handled by onerror instead + // With one exception: request that using file: protocol, most browsers + // will return status as 0 even though it's a successful request + if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) { + return; + } - var options = { - path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''), - method: config.method.toUpperCase(), - headers: headers, - agent: agent, - auth: auth - }; + // Prepare the response + var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null; + var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response; + var response = { + data: responseData, + status: request.status, + statusText: request.statusText, + headers: responseHeaders, + config: config, + request: request + }; - if (config.socketPath) { - options.socketPath = config.socketPath; - } else { - options.hostname = parsed.hostname; - options.port = parsed.port; - } + settle(resolve, reject, response); - var proxy = config.proxy; - if (!proxy && proxy !== false) { - var proxyEnv = protocol.slice(0, -1) + '_proxy'; - var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()]; - if (proxyUrl) { - var parsedProxyUrl = url.parse(proxyUrl); - var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; - var shouldProxy = true; + // Clean up request + request = null; + }; - if (noProxyEnv) { - var noProxy = noProxyEnv.split(',').map(function trim(s) { - return s.trim(); - }); + // Handle browser request cancellation (as opposed to a manual cancellation) + request.onabort = function handleAbort() { + if (!request) { + return; + } - shouldProxy = !noProxy.some(function proxyMatch(proxyElement) { - if (!proxyElement) { - return false; - } - if (proxyElement === '*') { - return true; - } - if (proxyElement[0] === '.' && - parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement && - proxyElement.match(/\./g).length === parsed.hostname.match(/\./g).length) { - return true; - } + reject(createError('Request aborted', config, 'ECONNABORTED', request)); - return parsed.hostname === proxyElement; - }); - } + // Clean up request + request = null; + }; + // Handle low level network errors + request.onerror = function handleError() { + // Real errors are hidden from us by the browser + // onerror should only fire if it's a network error + reject(createError('Network Error', config, null, request)); - if (shouldProxy) { - proxy = { - host: parsedProxyUrl.hostname, - port: parsedProxyUrl.port - }; + // Clean up request + request = null; + }; - if (parsedProxyUrl.auth) { - var proxyUrlAuth = parsedProxyUrl.auth.split(':'); - proxy.auth = { - username: proxyUrlAuth[0], - password: proxyUrlAuth[1] - }; - } - } + // Handle timeout + request.ontimeout = function handleTimeout() { + var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded'; + if (config.timeoutErrorMessage) { + timeoutErrorMessage = config.timeoutErrorMessage; } - } + reject(createError(timeoutErrorMessage, config, 'ECONNABORTED', + request)); - if (proxy) { - options.hostname = proxy.host; - options.host = proxy.host; - options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : ''); - options.port = proxy.port; - options.path = protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path; + // Clean up request + request = null; + }; - // Basic proxy authorization - if (proxy.auth) { - var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64'); - options.headers['Proxy-Authorization'] = 'Basic ' + base64; - } - } + // Add xsrf header + // This is only done if running in a standard browser environment. + // Specifically not if we're in a web worker, or react-native. + if (utils.isStandardBrowserEnv()) { + var cookies = __webpack_require__(474); - var transport; - var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true); - if (config.transport) { - transport = config.transport; - } else if (config.maxRedirects === 0) { - transport = isHttpsProxy ? https : http; - } else { - if (config.maxRedirects) { - options.maxRedirects = config.maxRedirects; + // Add xsrf header + var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? + cookies.read(config.xsrfCookieName) : + undefined; + + if (xsrfValue) { + requestHeaders[config.xsrfHeaderName] = xsrfValue; } - transport = isHttpsProxy ? httpsFollow : httpFollow; } - if (config.maxContentLength && config.maxContentLength > -1) { - options.maxBodyLength = config.maxContentLength; + // Add headers to the request + if ('setRequestHeader' in request) { + utils.forEach(requestHeaders, function setRequestHeader(val, key) { + if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') { + // Remove Content-Type if data is undefined + delete requestHeaders[key]; + } else { + // Otherwise add header to the request + request.setRequestHeader(key, val); + } + }); } - // Create the request - var req = transport.request(options, function handleResponse(res) { - if (req.aborted) return; - - // uncompress the response body transparently if required - var stream = res; - switch (res.headers['content-encoding']) { - /*eslint default-case:0*/ - case 'gzip': - case 'compress': - case 'deflate': - // add the unzipper to the body stream processing pipeline - stream = (res.statusCode === 204) ? stream : stream.pipe(zlib.createUnzip()); - - // remove the content-encoding in order to not confuse downstream operations - delete res.headers['content-encoding']; - break; - } - - // return the last request in case of redirects - var lastRequest = res.req || req; - - var response = { - status: res.statusCode, - statusText: res.statusMessage, - headers: res.headers, - config: config, - request: lastRequest - }; - - if (config.responseType === 'stream') { - response.data = stream; - settle(resolve, reject, response); - } else { - var responseBuffer = []; - stream.on('data', function handleStreamData(chunk) { - responseBuffer.push(chunk); - - // make sure the content length is not over the maxContentLength if specified - if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) { - stream.destroy(); - reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded', - config, null, lastRequest)); - } - }); - - stream.on('error', function handleStreamError(err) { - if (req.aborted) return; - reject(enhanceError(err, config, null, lastRequest)); - }); - - stream.on('end', function handleStreamEnd() { - var responseData = Buffer.concat(responseBuffer); - if (config.responseType !== 'arraybuffer') { - responseData = responseData.toString(config.responseEncoding); - } + // Add withCredentials to request if needed + if (!utils.isUndefined(config.withCredentials)) { + request.withCredentials = !!config.withCredentials; + } - response.data = responseData; - settle(resolve, reject, response); - }); + // Add responseType to request if needed + if (config.responseType) { + try { + request.responseType = config.responseType; + } catch (e) { + // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2. + // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function. + if (config.responseType !== 'json') { + throw e; + } } - }); + } - // Handle errors - req.on('error', function handleRequestError(err) { - if (req.aborted) return; - reject(enhanceError(err, config, null, req)); - }); + // Handle progress if needed + if (typeof config.onDownloadProgress === 'function') { + request.addEventListener('progress', config.onDownloadProgress); + } - // Handle request timeout - if (config.timeout) { - timer = setTimeout(function handleRequestTimeout() { - req.abort(); - reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req)); - }, config.timeout); + // Not all browsers support upload events + if (typeof config.onUploadProgress === 'function' && request.upload) { + request.upload.addEventListener('progress', config.onUploadProgress); } if (config.cancelToken) { // Handle cancellation config.cancelToken.promise.then(function onCanceled(cancel) { - if (req.aborted) return; + if (!request) { + return; + } - req.abort(); + request.abort(); reject(cancel); + // Clean up request + request = null; }); } - // Send the request - if (utils.isStream(data)) { - data.on('error', function handleStreamError(err) { - reject(enhanceError(err, config, null, req)); - }).pipe(req); - } else { - req.end(data); + if (requestData === undefined) { + requestData = null; } + + // Send the request + request.send(requestData); }); }; /***/ }), -/* 467 */ +/* 466 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var createError = __webpack_require__(468); +var createError = __webpack_require__(467); /** * Resolve or reject a Promise based on response status. @@ -41397,13 +41296,13 @@ module.exports = function settle(resolve, reject, response) { /***/ }), -/* 468 */ +/* 467 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var enhanceError = __webpack_require__(469); +var enhanceError = __webpack_require__(468); /** * Create an Error with the specified message, config, error code, request and response. @@ -41422,7 +41321,7 @@ module.exports = function createError(message, config, code, request, response) /***/ }), -/* 469 */ +/* 468 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -41470,28 +41369,578 @@ module.exports = function enhanceError(error, config, code, request, response) { }; +/***/ }), +/* 469 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isAbsoluteURL = __webpack_require__(470); +var combineURLs = __webpack_require__(471); + +/** + * Creates a new URL by combining the baseURL with the requestedURL, + * only when the requestedURL is not already an absolute URL. + * If the requestURL is absolute, this function returns the requestedURL untouched. + * + * @param {string} baseURL The base URL + * @param {string} requestedURL Absolute or relative URL to combine + * @returns {string} The combined full path + */ +module.exports = function buildFullPath(baseURL, requestedURL) { + if (baseURL && !isAbsoluteURL(requestedURL)) { + return combineURLs(baseURL, requestedURL); + } + return requestedURL; +}; + + /***/ }), /* 470 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Determines whether the specified URL is absolute + * + * @param {string} url The URL to test + * @returns {boolean} True if the specified URL is absolute, otherwise false + */ +module.exports = function isAbsoluteURL(url) { + // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). + // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed + // by any combination of letters, digits, plus, period, or hyphen. + return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); +}; + + +/***/ }), +/* 471 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Creates a new URL by combining the specified URLs + * + * @param {string} baseURL The base URL + * @param {string} relativeURL The relative URL + * @returns {string} The combined URL + */ +module.exports = function combineURLs(baseURL, relativeURL) { + return relativeURL + ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') + : baseURL; +}; + + +/***/ }), +/* 472 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = __webpack_require__(455); + +// Headers whose duplicates are ignored by node +// c.f. https://nodejs.org/api/http.html#http_message_headers +var ignoreDuplicateOf = [ + 'age', 'authorization', 'content-length', 'content-type', 'etag', + 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', + 'last-modified', 'location', 'max-forwards', 'proxy-authorization', + 'referer', 'retry-after', 'user-agent' +]; + +/** + * Parse headers into an object + * + * ``` + * Date: Wed, 27 Aug 2014 08:58:49 GMT + * Content-Type: application/json + * Connection: keep-alive + * Transfer-Encoding: chunked + * ``` + * + * @param {String} headers Headers needing to be parsed + * @returns {Object} Headers parsed into an object + */ +module.exports = function parseHeaders(headers) { + var parsed = {}; + var key; + var val; + var i; + + if (!headers) { return parsed; } + + utils.forEach(headers.split('\n'), function parser(line) { + i = line.indexOf(':'); + key = utils.trim(line.substr(0, i)).toLowerCase(); + val = utils.trim(line.substr(i + 1)); + + if (key) { + if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) { + return; + } + if (key === 'set-cookie') { + parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]); + } else { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + } + }); + + return parsed; +}; + + +/***/ }), +/* 473 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = __webpack_require__(455); + +module.exports = ( + utils.isStandardBrowserEnv() ? + + // Standard browser envs have full support of the APIs needed to test + // whether the request URL is of the same origin as current location. + (function standardBrowserEnv() { + var msie = /(msie|trident)/i.test(navigator.userAgent); + var urlParsingNode = document.createElement('a'); + var originURL; + + /** + * Parse a URL to discover it's components + * + * @param {String} url The URL to be parsed + * @returns {Object} + */ + function resolveURL(url) { + var href = url; + + if (msie) { + // IE needs attribute set twice to normalize properties + urlParsingNode.setAttribute('href', href); + href = urlParsingNode.href; + } + + urlParsingNode.setAttribute('href', href); + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: (urlParsingNode.pathname.charAt(0) === '/') ? + urlParsingNode.pathname : + '/' + urlParsingNode.pathname + }; + } + + originURL = resolveURL(window.location.href); + + /** + * Determine if a URL shares the same origin as the current location + * + * @param {String} requestURL The URL to test + * @returns {boolean} True if URL shares the same origin, otherwise false + */ + return function isURLSameOrigin(requestURL) { + var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL; + return (parsed.protocol === originURL.protocol && + parsed.host === originURL.host); + }; + })() : + + // Non standard browser envs (web workers, react-native) lack needed support. + (function nonStandardBrowserEnv() { + return function isURLSameOrigin() { + return true; + }; + })() +); + + +/***/ }), +/* 474 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = __webpack_require__(455); + +module.exports = ( + utils.isStandardBrowserEnv() ? + + // Standard browser envs support document.cookie + (function standardBrowserEnv() { + return { + write: function write(name, value, expires, path, domain, secure) { + var cookie = []; + cookie.push(name + '=' + encodeURIComponent(value)); + + if (utils.isNumber(expires)) { + cookie.push('expires=' + new Date(expires).toGMTString()); + } + + if (utils.isString(path)) { + cookie.push('path=' + path); + } + + if (utils.isString(domain)) { + cookie.push('domain=' + domain); + } + + if (secure === true) { + cookie.push('secure'); + } + + document.cookie = cookie.join('; '); + }, + + read: function read(name) { + var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); + return (match ? decodeURIComponent(match[3]) : null); + }, + + remove: function remove(name) { + this.write(name, '', Date.now() - 86400000); + } + }; + })() : + + // Non standard browser env (web workers, react-native) lack needed support. + (function nonStandardBrowserEnv() { + return { + write: function write() {}, + read: function read() { return null; }, + remove: function remove() {} + }; + })() +); + + +/***/ }), +/* 475 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = __webpack_require__(455); +var settle = __webpack_require__(466); +var buildFullPath = __webpack_require__(469); +var buildURL = __webpack_require__(458); +var http = __webpack_require__(476); +var https = __webpack_require__(477); +var httpFollow = __webpack_require__(478).http; +var httpsFollow = __webpack_require__(478).https; +var url = __webpack_require__(452); +var zlib = __webpack_require__(486); +var pkg = __webpack_require__(487); +var createError = __webpack_require__(467); +var enhanceError = __webpack_require__(468); + +var isHttps = /https:?/; + +/*eslint consistent-return:0*/ +module.exports = function httpAdapter(config) { + return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) { + var resolve = function resolve(value) { + resolvePromise(value); + }; + var reject = function reject(value) { + rejectPromise(value); + }; + var data = config.data; + var headers = config.headers; + + // Set User-Agent (required by some servers) + // Only set header if it hasn't been set in config + // See https://github.com/axios/axios/issues/69 + if (!headers['User-Agent'] && !headers['user-agent']) { + headers['User-Agent'] = 'axios/' + pkg.version; + } + + if (data && !utils.isStream(data)) { + if (Buffer.isBuffer(data)) { + // Nothing to do... + } else if (utils.isArrayBuffer(data)) { + data = Buffer.from(new Uint8Array(data)); + } else if (utils.isString(data)) { + data = Buffer.from(data, 'utf-8'); + } else { + return reject(createError( + 'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream', + config + )); + } + + // Add Content-Length header if data exists + headers['Content-Length'] = data.length; + } + + // HTTP basic authentication + var auth = undefined; + if (config.auth) { + var username = config.auth.username || ''; + var password = config.auth.password || ''; + auth = username + ':' + password; + } + + // Parse url + var fullPath = buildFullPath(config.baseURL, config.url); + var parsed = url.parse(fullPath); + var protocol = parsed.protocol || 'http:'; + + if (!auth && parsed.auth) { + var urlAuth = parsed.auth.split(':'); + var urlUsername = urlAuth[0] || ''; + var urlPassword = urlAuth[1] || ''; + auth = urlUsername + ':' + urlPassword; + } + + if (auth) { + delete headers.Authorization; + } + + var isHttpsRequest = isHttps.test(protocol); + var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent; + + var options = { + path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''), + method: config.method.toUpperCase(), + headers: headers, + agent: agent, + agents: { http: config.httpAgent, https: config.httpsAgent }, + auth: auth + }; + + if (config.socketPath) { + options.socketPath = config.socketPath; + } else { + options.hostname = parsed.hostname; + options.port = parsed.port; + } + + var proxy = config.proxy; + if (!proxy && proxy !== false) { + var proxyEnv = protocol.slice(0, -1) + '_proxy'; + var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()]; + if (proxyUrl) { + var parsedProxyUrl = url.parse(proxyUrl); + var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; + var shouldProxy = true; + + if (noProxyEnv) { + var noProxy = noProxyEnv.split(',').map(function trim(s) { + return s.trim(); + }); + + shouldProxy = !noProxy.some(function proxyMatch(proxyElement) { + if (!proxyElement) { + return false; + } + if (proxyElement === '*') { + return true; + } + if (proxyElement[0] === '.' && + parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement) { + return true; + } + + return parsed.hostname === proxyElement; + }); + } + + + if (shouldProxy) { + proxy = { + host: parsedProxyUrl.hostname, + port: parsedProxyUrl.port + }; + + if (parsedProxyUrl.auth) { + var proxyUrlAuth = parsedProxyUrl.auth.split(':'); + proxy.auth = { + username: proxyUrlAuth[0], + password: proxyUrlAuth[1] + }; + } + } + } + } + + if (proxy) { + options.hostname = proxy.host; + options.host = proxy.host; + options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : ''); + options.port = proxy.port; + options.path = protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path; + + // Basic proxy authorization + if (proxy.auth) { + var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64'); + options.headers['Proxy-Authorization'] = 'Basic ' + base64; + } + } + + var transport; + var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true); + if (config.transport) { + transport = config.transport; + } else if (config.maxRedirects === 0) { + transport = isHttpsProxy ? https : http; + } else { + if (config.maxRedirects) { + options.maxRedirects = config.maxRedirects; + } + transport = isHttpsProxy ? httpsFollow : httpFollow; + } + + if (config.maxContentLength && config.maxContentLength > -1) { + options.maxBodyLength = config.maxContentLength; + } + + // Create the request + var req = transport.request(options, function handleResponse(res) { + if (req.aborted) return; + + // uncompress the response body transparently if required + var stream = res; + switch (res.headers['content-encoding']) { + /*eslint default-case:0*/ + case 'gzip': + case 'compress': + case 'deflate': + // add the unzipper to the body stream processing pipeline + stream = (res.statusCode === 204) ? stream : stream.pipe(zlib.createUnzip()); + + // remove the content-encoding in order to not confuse downstream operations + delete res.headers['content-encoding']; + break; + } + + // return the last request in case of redirects + var lastRequest = res.req || req; + + var response = { + status: res.statusCode, + statusText: res.statusMessage, + headers: res.headers, + config: config, + request: lastRequest + }; + + if (config.responseType === 'stream') { + response.data = stream; + settle(resolve, reject, response); + } else { + var responseBuffer = []; + stream.on('data', function handleStreamData(chunk) { + responseBuffer.push(chunk); + + // make sure the content length is not over the maxContentLength if specified + if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) { + stream.destroy(); + reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded', + config, null, lastRequest)); + } + }); + + stream.on('error', function handleStreamError(err) { + if (req.aborted) return; + reject(enhanceError(err, config, null, lastRequest)); + }); + + stream.on('end', function handleStreamEnd() { + var responseData = Buffer.concat(responseBuffer); + if (config.responseType !== 'arraybuffer') { + responseData = responseData.toString(config.responseEncoding); + } + + response.data = responseData; + settle(resolve, reject, response); + }); + } + }); + + // Handle errors + req.on('error', function handleRequestError(err) { + if (req.aborted) return; + reject(enhanceError(err, config, null, req)); + }); + + // Handle request timeout + if (config.timeout) { + // Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system. + // And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET. + // At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up. + // And then these socket which be hang up will devoring CPU little by little. + // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect. + req.setTimeout(config.timeout, function handleRequestTimeout() { + req.abort(); + reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req)); + }); + } + + if (config.cancelToken) { + // Handle cancellation + config.cancelToken.promise.then(function onCanceled(cancel) { + if (req.aborted) return; + + req.abort(); + reject(cancel); + }); + } + + // Send the request + if (utils.isStream(data)) { + data.on('error', function handleStreamError(err) { + reject(enhanceError(err, config, null, req)); + }).pipe(req); + } else { + req.end(data); + } + }); +}; + + +/***/ }), +/* 476 */ /***/ (function(module, exports) { module.exports = require("http"); /***/ }), -/* 471 */ +/* 477 */ /***/ (function(module, exports) { module.exports = require("https"); /***/ }), -/* 472 */ +/* 478 */ /***/ (function(module, exports, __webpack_require__) { var url = __webpack_require__(452); -var http = __webpack_require__(470); -var https = __webpack_require__(471); +var http = __webpack_require__(476); +var https = __webpack_require__(477); var assert = __webpack_require__(30); var Writable = __webpack_require__(27).Writable; -var debug = __webpack_require__(473)("follow-redirects"); +var debug = __webpack_require__(479)("follow-redirects"); // RFC7231§4.2.1: Of the request methods defined by this specification, // the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe. @@ -41811,7 +42260,7 @@ module.exports.wrap = wrap; /***/ }), -/* 473 */ +/* 479 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -41820,14 +42269,14 @@ module.exports.wrap = wrap; */ if (typeof process === 'undefined' || process.type === 'renderer') { - module.exports = __webpack_require__(474); + module.exports = __webpack_require__(480); } else { - module.exports = __webpack_require__(477); + module.exports = __webpack_require__(483); } /***/ }), -/* 474 */ +/* 480 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -41836,7 +42285,7 @@ if (typeof process === 'undefined' || process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(475); +exports = module.exports = __webpack_require__(481); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -42028,7 +42477,7 @@ function localstorage() { /***/ }), -/* 475 */ +/* 481 */ /***/ (function(module, exports, __webpack_require__) { @@ -42044,7 +42493,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(476); +exports.humanize = __webpack_require__(482); /** * Active `debug` instances. @@ -42259,7 +42708,7 @@ function coerce(val) { /***/ }), -/* 476 */ +/* 482 */ /***/ (function(module, exports) { /** @@ -42417,14 +42866,14 @@ function plural(ms, n, name) { /***/ }), -/* 477 */ +/* 483 */ /***/ (function(module, exports, __webpack_require__) { /** * Module dependencies. */ -var tty = __webpack_require__(478); +var tty = __webpack_require__(484); var util = __webpack_require__(29); /** @@ -42433,7 +42882,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(475); +exports = module.exports = __webpack_require__(481); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -42448,7 +42897,7 @@ exports.useColors = useColors; exports.colors = [ 6, 2, 3, 4, 5, 1 ]; try { - var supportsColor = __webpack_require__(479); + var supportsColor = __webpack_require__(485); if (supportsColor && supportsColor.level >= 2) { exports.colors = [ 20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62, 63, 68, @@ -42587,600 +43036,182 @@ function load() { /** * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 478 */ -/***/ (function(module, exports) { - -module.exports = require("tty"); - -/***/ }), -/* 479 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const os = __webpack_require__(11); -const hasFlag = __webpack_require__(12); - -const env = process.env; - -let forceColor; -if (hasFlag('no-color') || - hasFlag('no-colors') || - hasFlag('color=false')) { - forceColor = false; -} else if (hasFlag('color') || - hasFlag('colors') || - hasFlag('color=true') || - hasFlag('color=always')) { - forceColor = true; -} -if ('FORCE_COLOR' in env) { - forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; -} - -function translateLevel(level) { - if (level === 0) { - return false; - } - - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; -} - -function supportsColor(stream) { - if (forceColor === false) { - return 0; - } - - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; - } - - if (hasFlag('color=256')) { - return 2; - } - - if (stream && !stream.isTTY && forceColor !== true) { - return 0; - } - - const min = forceColor ? 1 : 0; - - if (process.platform === 'win32') { - // Node.js 7.5.0 is the first version of Node.js to include a patch to - // libuv that enables 256 color output on Windows. Anything earlier and it - // won't work. However, here we target Node.js 8 at minimum as it is an LTS - // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows - // release that supports 256 colors. Windows 10 build 14931 is the first release - // that supports 16m/TrueColor. - const osRelease = os.release().split('.'); - if ( - Number(process.versions.node.split('.')[0]) >= 8 && - Number(osRelease[0]) >= 10 && - Number(osRelease[2]) >= 10586 - ) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; - } - - return 1; - } - - if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { - return 1; - } - - return min; - } - - if ('TEAMCITY_VERSION' in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; - } - - if (env.COLORTERM === 'truecolor') { - return 3; - } - - if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); - - switch (env.TERM_PROGRAM) { - case 'iTerm.app': - return version >= 3 ? 3 : 2; - case 'Apple_Terminal': - return 2; - // No default - } - } - - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } - - if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { - return 1; - } - - if ('COLORTERM' in env) { - return 1; - } - - if (env.TERM === 'dumb') { - return min; - } - - return min; -} - -function getSupportLevel(stream) { - const level = supportsColor(stream); - return translateLevel(level); -} - -module.exports = { - supportsColor: getSupportLevel, - stdout: getSupportLevel(process.stdout), - stderr: getSupportLevel(process.stderr) -}; - - -/***/ }), -/* 480 */ -/***/ (function(module, exports) { - -module.exports = require("zlib"); - -/***/ }), -/* 481 */ -/***/ (function(module) { - -module.exports = JSON.parse("{\"name\":\"axios\",\"version\":\"0.19.0\",\"description\":\"Promise based HTTP client for the browser and node.js\",\"main\":\"index.js\",\"scripts\":{\"test\":\"grunt test && bundlesize\",\"start\":\"node ./sandbox/server.js\",\"build\":\"NODE_ENV=production grunt build\",\"preversion\":\"npm test\",\"version\":\"npm run build && grunt version && git add -A dist && git add CHANGELOG.md bower.json package.json\",\"postversion\":\"git push && git push --tags\",\"examples\":\"node ./examples/server.js\",\"coveralls\":\"cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\",\"fix\":\"eslint --fix lib/**/*.js\"},\"repository\":{\"type\":\"git\",\"url\":\"https://github.com/axios/axios.git\"},\"keywords\":[\"xhr\",\"http\",\"ajax\",\"promise\",\"node\"],\"author\":\"Matt Zabriskie\",\"license\":\"MIT\",\"bugs\":{\"url\":\"https://github.com/axios/axios/issues\"},\"homepage\":\"https://github.com/axios/axios\",\"devDependencies\":{\"bundlesize\":\"^0.17.0\",\"coveralls\":\"^3.0.0\",\"es6-promise\":\"^4.2.4\",\"grunt\":\"^1.0.2\",\"grunt-banner\":\"^0.6.0\",\"grunt-cli\":\"^1.2.0\",\"grunt-contrib-clean\":\"^1.1.0\",\"grunt-contrib-watch\":\"^1.0.0\",\"grunt-eslint\":\"^20.1.0\",\"grunt-karma\":\"^2.0.0\",\"grunt-mocha-test\":\"^0.13.3\",\"grunt-ts\":\"^6.0.0-beta.19\",\"grunt-webpack\":\"^1.0.18\",\"istanbul-instrumenter-loader\":\"^1.0.0\",\"jasmine-core\":\"^2.4.1\",\"karma\":\"^1.3.0\",\"karma-chrome-launcher\":\"^2.2.0\",\"karma-coverage\":\"^1.1.1\",\"karma-firefox-launcher\":\"^1.1.0\",\"karma-jasmine\":\"^1.1.1\",\"karma-jasmine-ajax\":\"^0.1.13\",\"karma-opera-launcher\":\"^1.0.0\",\"karma-safari-launcher\":\"^1.0.0\",\"karma-sauce-launcher\":\"^1.2.0\",\"karma-sinon\":\"^1.0.5\",\"karma-sourcemap-loader\":\"^0.3.7\",\"karma-webpack\":\"^1.7.0\",\"load-grunt-tasks\":\"^3.5.2\",\"minimist\":\"^1.2.0\",\"mocha\":\"^5.2.0\",\"sinon\":\"^4.5.0\",\"typescript\":\"^2.8.1\",\"url-search-params\":\"^0.10.0\",\"webpack\":\"^1.13.1\",\"webpack-dev-server\":\"^1.14.1\"},\"browser\":{\"./lib/adapters/http.js\":\"./lib/adapters/xhr.js\"},\"typings\":\"./index.d.ts\",\"dependencies\":{\"follow-redirects\":\"1.5.10\",\"is-buffer\":\"^2.0.2\"},\"bundlesize\":[{\"path\":\"./dist/axios.min.js\",\"threshold\":\"5kB\"}]}"); - -/***/ }), -/* 482 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(455); -var settle = __webpack_require__(467); -var buildURL = __webpack_require__(459); -var parseHeaders = __webpack_require__(483); -var isURLSameOrigin = __webpack_require__(484); -var createError = __webpack_require__(468); - -module.exports = function xhrAdapter(config) { - return new Promise(function dispatchXhrRequest(resolve, reject) { - var requestData = config.data; - var requestHeaders = config.headers; - - if (utils.isFormData(requestData)) { - delete requestHeaders['Content-Type']; // Let the browser set it - } - - var request = new XMLHttpRequest(); - - // HTTP basic authentication - if (config.auth) { - var username = config.auth.username || ''; - var password = config.auth.password || ''; - requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password); - } - - request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true); - - // Set the request timeout in MS - request.timeout = config.timeout; - - // Listen for ready state - request.onreadystatechange = function handleLoad() { - if (!request || request.readyState !== 4) { - return; - } - - // The request errored out and we didn't get a response, this will be - // handled by onerror instead - // With one exception: request that using file: protocol, most browsers - // will return status as 0 even though it's a successful request - if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) { - return; - } - - // Prepare the response - var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null; - var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response; - var response = { - data: responseData, - status: request.status, - statusText: request.statusText, - headers: responseHeaders, - config: config, - request: request - }; - - settle(resolve, reject, response); - - // Clean up request - request = null; - }; - - // Handle browser request cancellation (as opposed to a manual cancellation) - request.onabort = function handleAbort() { - if (!request) { - return; - } - - reject(createError('Request aborted', config, 'ECONNABORTED', request)); - - // Clean up request - request = null; - }; - - // Handle low level network errors - request.onerror = function handleError() { - // Real errors are hidden from us by the browser - // onerror should only fire if it's a network error - reject(createError('Network Error', config, null, request)); - - // Clean up request - request = null; - }; - - // Handle timeout - request.ontimeout = function handleTimeout() { - reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', - request)); - - // Clean up request - request = null; - }; - - // Add xsrf header - // This is only done if running in a standard browser environment. - // Specifically not if we're in a web worker, or react-native. - if (utils.isStandardBrowserEnv()) { - var cookies = __webpack_require__(485); - - // Add xsrf header - var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ? - cookies.read(config.xsrfCookieName) : - undefined; - - if (xsrfValue) { - requestHeaders[config.xsrfHeaderName] = xsrfValue; - } - } - - // Add headers to the request - if ('setRequestHeader' in request) { - utils.forEach(requestHeaders, function setRequestHeader(val, key) { - if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') { - // Remove Content-Type if data is undefined - delete requestHeaders[key]; - } else { - // Otherwise add header to the request - request.setRequestHeader(key, val); - } - }); - } - - // Add withCredentials to request if needed - if (config.withCredentials) { - request.withCredentials = true; - } - - // Add responseType to request if needed - if (config.responseType) { - try { - request.responseType = config.responseType; - } catch (e) { - // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2. - // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function. - if (config.responseType !== 'json') { - throw e; - } - } - } - - // Handle progress if needed - if (typeof config.onDownloadProgress === 'function') { - request.addEventListener('progress', config.onDownloadProgress); - } - - // Not all browsers support upload events - if (typeof config.onUploadProgress === 'function' && request.upload) { - request.upload.addEventListener('progress', config.onUploadProgress); - } - - if (config.cancelToken) { - // Handle cancellation - config.cancelToken.promise.then(function onCanceled(cancel) { - if (!request) { - return; - } - - request.abort(); - reject(cancel); - // Clean up request - request = null; - }); - } - - if (requestData === undefined) { - requestData = null; - } - - // Send the request - request.send(requestData); - }); -}; - - -/***/ }), -/* 483 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(455); - -// Headers whose duplicates are ignored by node -// c.f. https://nodejs.org/api/http.html#http_message_headers -var ignoreDuplicateOf = [ - 'age', 'authorization', 'content-length', 'content-type', 'etag', - 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', - 'last-modified', 'location', 'max-forwards', 'proxy-authorization', - 'referer', 'retry-after', 'user-agent' -]; - -/** - * Parse headers into an object - * - * ``` - * Date: Wed, 27 Aug 2014 08:58:49 GMT - * Content-Type: application/json - * Connection: keep-alive - * Transfer-Encoding: chunked - * ``` - * - * @param {String} headers Headers needing to be parsed - * @returns {Object} Headers parsed into an object + * + * Create a new `inspectOpts` object in case `useColors` is set + * differently for a particular `debug` instance. */ -module.exports = function parseHeaders(headers) { - var parsed = {}; - var key; - var val; - var i; - if (!headers) { return parsed; } +function init (debug) { + debug.inspectOpts = {}; - utils.forEach(headers.split('\n'), function parser(line) { - i = line.indexOf(':'); - key = utils.trim(line.substr(0, i)).toLowerCase(); - val = utils.trim(line.substr(i + 1)); + var keys = Object.keys(exports.inspectOpts); + for (var i = 0; i < keys.length; i++) { + debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; + } +} - if (key) { - if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) { - return; - } - if (key === 'set-cookie') { - parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]); - } else { - parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; - } - } - }); +/** + * Enable namespaces listed in `process.env.DEBUG` initially. + */ - return parsed; -}; +exports.enable(load()); /***/ }), /* 484 */ +/***/ (function(module, exports) { + +module.exports = require("tty"); + +/***/ }), +/* 485 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const os = __webpack_require__(11); +const hasFlag = __webpack_require__(12); -var utils = __webpack_require__(455); - -module.exports = ( - utils.isStandardBrowserEnv() ? +const env = process.env; - // Standard browser envs have full support of the APIs needed to test - // whether the request URL is of the same origin as current location. - (function standardBrowserEnv() { - var msie = /(msie|trident)/i.test(navigator.userAgent); - var urlParsingNode = document.createElement('a'); - var originURL; +let forceColor; +if (hasFlag('no-color') || + hasFlag('no-colors') || + hasFlag('color=false')) { + forceColor = false; +} else if (hasFlag('color') || + hasFlag('colors') || + hasFlag('color=true') || + hasFlag('color=always')) { + forceColor = true; +} +if ('FORCE_COLOR' in env) { + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; +} - /** - * Parse a URL to discover it's components - * - * @param {String} url The URL to be parsed - * @returns {Object} - */ - function resolveURL(url) { - var href = url; +function translateLevel(level) { + if (level === 0) { + return false; + } - if (msie) { - // IE needs attribute set twice to normalize properties - urlParsingNode.setAttribute('href', href); - href = urlParsingNode.href; - } + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; +} - urlParsingNode.setAttribute('href', href); +function supportsColor(stream) { + if (forceColor === false) { + return 0; + } - // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils - return { - href: urlParsingNode.href, - protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', - host: urlParsingNode.host, - search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', - hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', - hostname: urlParsingNode.hostname, - port: urlParsingNode.port, - pathname: (urlParsingNode.pathname.charAt(0) === '/') ? - urlParsingNode.pathname : - '/' + urlParsingNode.pathname - }; - } + if (hasFlag('color=16m') || + hasFlag('color=full') || + hasFlag('color=truecolor')) { + return 3; + } - originURL = resolveURL(window.location.href); + if (hasFlag('color=256')) { + return 2; + } - /** - * Determine if a URL shares the same origin as the current location - * - * @param {String} requestURL The URL to test - * @returns {boolean} True if URL shares the same origin, otherwise false - */ - return function isURLSameOrigin(requestURL) { - var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL; - return (parsed.protocol === originURL.protocol && - parsed.host === originURL.host); - }; - })() : + if (stream && !stream.isTTY && forceColor !== true) { + return 0; + } - // Non standard browser envs (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return function isURLSameOrigin() { - return true; - }; - })() -); + const min = forceColor ? 1 : 0; + if (process.platform === 'win32') { + // Node.js 7.5.0 is the first version of Node.js to include a patch to + // libuv that enables 256 color output on Windows. Anything earlier and it + // won't work. However, here we target Node.js 8 at minimum as it is an LTS + // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows + // release that supports 256 colors. Windows 10 build 14931 is the first release + // that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(process.versions.node.split('.')[0]) >= 8 && + Number(osRelease[0]) >= 10 && + Number(osRelease[2]) >= 10586 + ) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; + } -/***/ }), -/* 485 */ -/***/ (function(module, exports, __webpack_require__) { + return 1; + } -"use strict"; + if ('CI' in env) { + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } + return min; + } -var utils = __webpack_require__(455); + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } -module.exports = ( - utils.isStandardBrowserEnv() ? + if (env.COLORTERM === 'truecolor') { + return 3; + } - // Standard browser envs support document.cookie - (function standardBrowserEnv() { - return { - write: function write(name, value, expires, path, domain, secure) { - var cookie = []; - cookie.push(name + '=' + encodeURIComponent(value)); + if ('TERM_PROGRAM' in env) { + const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); - if (utils.isNumber(expires)) { - cookie.push('expires=' + new Date(expires).toGMTString()); - } + switch (env.TERM_PROGRAM) { + case 'iTerm.app': + return version >= 3 ? 3 : 2; + case 'Apple_Terminal': + return 2; + // No default + } + } - if (utils.isString(path)) { - cookie.push('path=' + path); - } + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } - if (utils.isString(domain)) { - cookie.push('domain=' + domain); - } + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } - if (secure === true) { - cookie.push('secure'); - } + if ('COLORTERM' in env) { + return 1; + } - document.cookie = cookie.join('; '); - }, + if (env.TERM === 'dumb') { + return min; + } - read: function read(name) { - var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); - return (match ? decodeURIComponent(match[3]) : null); - }, + return min; +} - remove: function remove(name) { - this.write(name, '', Date.now() - 86400000); - } - }; - })() : +function getSupportLevel(stream) { + const level = supportsColor(stream); + return translateLevel(level); +} - // Non standard browser env (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return { - write: function write() {}, - read: function read() { return null; }, - remove: function remove() {} - }; - })() -); +module.exports = { + supportsColor: getSupportLevel, + stdout: getSupportLevel(process.stdout), + stderr: getSupportLevel(process.stderr) +}; /***/ }), /* 486 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Determines whether the specified URL is absolute - * - * @param {string} url The URL to test - * @returns {boolean} True if the specified URL is absolute, otherwise false - */ -module.exports = function isAbsoluteURL(url) { - // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). - // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed - // by any combination of letters, digits, plus, period, or hyphen. - return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); -}; +/***/ (function(module, exports) { +module.exports = require("zlib"); /***/ }), /* 487 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Creates a new URL by combining the specified URLs - * - * @param {string} baseURL The base URL - * @param {string} relativeURL The relative URL - * @returns {string} The combined URL - */ -module.exports = function combineURLs(baseURL, relativeURL) { - return relativeURL - ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') - : baseURL; -}; +/***/ (function(module) { +module.exports = JSON.parse("{\"name\":\"axios\",\"version\":\"0.19.2\",\"description\":\"Promise based HTTP client for the browser and node.js\",\"main\":\"index.js\",\"scripts\":{\"test\":\"grunt test && bundlesize\",\"start\":\"node ./sandbox/server.js\",\"build\":\"NODE_ENV=production grunt build\",\"preversion\":\"npm test\",\"version\":\"npm run build && grunt version && git add -A dist && git add CHANGELOG.md bower.json package.json\",\"postversion\":\"git push && git push --tags\",\"examples\":\"node ./examples/server.js\",\"coveralls\":\"cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\",\"fix\":\"eslint --fix lib/**/*.js\"},\"repository\":{\"type\":\"git\",\"url\":\"https://github.com/axios/axios.git\"},\"keywords\":[\"xhr\",\"http\",\"ajax\",\"promise\",\"node\"],\"author\":\"Matt Zabriskie\",\"license\":\"MIT\",\"bugs\":{\"url\":\"https://github.com/axios/axios/issues\"},\"homepage\":\"https://github.com/axios/axios\",\"devDependencies\":{\"bundlesize\":\"^0.17.0\",\"coveralls\":\"^3.0.0\",\"es6-promise\":\"^4.2.4\",\"grunt\":\"^1.0.2\",\"grunt-banner\":\"^0.6.0\",\"grunt-cli\":\"^1.2.0\",\"grunt-contrib-clean\":\"^1.1.0\",\"grunt-contrib-watch\":\"^1.0.0\",\"grunt-eslint\":\"^20.1.0\",\"grunt-karma\":\"^2.0.0\",\"grunt-mocha-test\":\"^0.13.3\",\"grunt-ts\":\"^6.0.0-beta.19\",\"grunt-webpack\":\"^1.0.18\",\"istanbul-instrumenter-loader\":\"^1.0.0\",\"jasmine-core\":\"^2.4.1\",\"karma\":\"^1.3.0\",\"karma-chrome-launcher\":\"^2.2.0\",\"karma-coverage\":\"^1.1.1\",\"karma-firefox-launcher\":\"^1.1.0\",\"karma-jasmine\":\"^1.1.1\",\"karma-jasmine-ajax\":\"^0.1.13\",\"karma-opera-launcher\":\"^1.0.0\",\"karma-safari-launcher\":\"^1.0.0\",\"karma-sauce-launcher\":\"^1.2.0\",\"karma-sinon\":\"^1.0.5\",\"karma-sourcemap-loader\":\"^0.3.7\",\"karma-webpack\":\"^1.7.0\",\"load-grunt-tasks\":\"^3.5.2\",\"minimist\":\"^1.2.0\",\"mocha\":\"^5.2.0\",\"sinon\":\"^4.5.0\",\"typescript\":\"^2.8.1\",\"url-search-params\":\"^0.10.0\",\"webpack\":\"^1.13.1\",\"webpack-dev-server\":\"^1.14.1\"},\"browser\":{\"./lib/adapters/http.js\":\"./lib/adapters/xhr.js\"},\"typings\":\"./index.d.ts\",\"dependencies\":{\"follow-redirects\":\"1.5.10\"},\"bundlesize\":[{\"path\":\"./dist/axios.min.js\",\"threshold\":\"5kB\"}]}"); /***/ }), /* 488 */ @@ -43204,13 +43235,23 @@ module.exports = function mergeConfig(config1, config2) { config2 = config2 || {}; var config = {}; - utils.forEach(['url', 'method', 'params', 'data'], function valueFromConfig2(prop) { + var valueFromConfig2Keys = ['url', 'method', 'params', 'data']; + var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy']; + var defaultToConfig2Keys = [ + 'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer', + 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', + 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', + 'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent', + 'httpsAgent', 'cancelToken', 'socketPath' + ]; + + utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) { if (typeof config2[prop] !== 'undefined') { config[prop] = config2[prop]; } }); - utils.forEach(['headers', 'auth', 'proxy'], function mergeDeepProperties(prop) { + utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop) { if (utils.isObject(config2[prop])) { config[prop] = utils.deepMerge(config1[prop], config2[prop]); } else if (typeof config2[prop] !== 'undefined') { @@ -43222,13 +43263,25 @@ module.exports = function mergeConfig(config1, config2) { } }); - utils.forEach([ - 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', - 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', - 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', - 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken', - 'socketPath' - ], function defaultToConfig2(prop) { + utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) { + if (typeof config2[prop] !== 'undefined') { + config[prop] = config2[prop]; + } else if (typeof config1[prop] !== 'undefined') { + config[prop] = config1[prop]; + } + }); + + var axiosKeys = valueFromConfig2Keys + .concat(mergeDeepPropertiesKeys) + .concat(defaultToConfig2Keys); + + var otherKeys = Object + .keys(config2) + .filter(function filterAxiosKeys(key) { + return axiosKeys.indexOf(key) === -1; + }); + + utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) { if (typeof config2[prop] !== 'undefined') { config[prop] = config2[prop]; } else if (typeof config1[prop] !== 'undefined') { @@ -43591,92 +43644,221 @@ exports.KbnClientVersion = KbnClientVersion; * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -const kbn_client_requester_1 = __webpack_require__(451); -class KbnClientSavedObjects { - constructor(log, requester) { - this.log = log; - this.requester = requester; - } - /** - * Run the saved objects migration - */ - async migrate() { - this.log.debug('Migrating saved objects'); - return await this.requester.request({ - description: 'migrate saved objects', - path: kbn_client_requester_1.uriencode `/internal/saved_objects/_migrate`, - method: 'POST', - body: {}, - }); - } - /** - * Get an object - */ - async get(options) { - this.log.debug('Gettings saved object: %j', options); - return await this.requester.request({ - description: 'get saved object', - path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, - method: 'GET', - }); - } - /** - * Create a saved object - */ - async create(options) { - this.log.debug('Creating saved object: %j', options); - return await this.requester.request({ - description: 'update saved object', - path: options.id - ? kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}` - : kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}`, - query: { - overwrite: options.overwrite, - }, - method: 'POST', - body: { - attributes: options.attributes, - migrationVersion: options.migrationVersion, - references: options.references, - }, - }); - } - /** - * Update a saved object - */ - async update(options) { - this.log.debug('Updating saved object: %j', options); - return await this.requester.request({ - description: 'update saved object', - path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, - query: { - overwrite: options.overwrite, - }, - method: 'PUT', - body: { - attributes: options.attributes, - migrationVersion: options.migrationVersion, - references: options.references, - }, - }); - } - /** - * Delete an object - */ - async delete(options) { - this.log.debug('Deleting saved object %s/%s', options); - return await this.requester.request({ - description: 'delete saved object', - path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, - method: 'DELETE', - }); - } -} -exports.KbnClientSavedObjects = KbnClientSavedObjects; +const kbn_client_requester_1 = __webpack_require__(451); +class KbnClientSavedObjects { + constructor(log, requester) { + this.log = log; + this.requester = requester; + } + /** + * Run the saved objects migration + */ + async migrate() { + this.log.debug('Migrating saved objects'); + return await this.requester.request({ + description: 'migrate saved objects', + path: kbn_client_requester_1.uriencode `/internal/saved_objects/_migrate`, + method: 'POST', + body: {}, + }); + } + /** + * Get an object + */ + async get(options) { + this.log.debug('Gettings saved object: %j', options); + return await this.requester.request({ + description: 'get saved object', + path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, + method: 'GET', + }); + } + /** + * Create a saved object + */ + async create(options) { + this.log.debug('Creating saved object: %j', options); + return await this.requester.request({ + description: 'update saved object', + path: options.id + ? kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}` + : kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}`, + query: { + overwrite: options.overwrite, + }, + method: 'POST', + body: { + attributes: options.attributes, + migrationVersion: options.migrationVersion, + references: options.references, + }, + }); + } + /** + * Update a saved object + */ + async update(options) { + this.log.debug('Updating saved object: %j', options); + return await this.requester.request({ + description: 'update saved object', + path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, + query: { + overwrite: options.overwrite, + }, + method: 'PUT', + body: { + attributes: options.attributes, + migrationVersion: options.migrationVersion, + references: options.references, + }, + }); + } + /** + * Delete an object + */ + async delete(options) { + this.log.debug('Deleting saved object %s/%s', options); + return await this.requester.request({ + description: 'delete saved object', + path: kbn_client_requester_1.uriencode `/api/saved_objects/${options.type}/${options.id}`, + method: 'DELETE', + }); + } +} +exports.KbnClientSavedObjects = KbnClientSavedObjects; + + +/***/ }), +/* 498 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const kbn_client_requester_1 = __webpack_require__(451); +class KbnClientUiSettings { + constructor(log, requester, defaults) { + this.log = log; + this.requester = requester; + this.defaults = defaults; + } + async get(setting) { + var _a; + const all = await this.getAll(); + const value = (_a = all[setting]) === null || _a === void 0 ? void 0 : _a.userValue; + this.log.verbose('uiSettings.value: %j', value); + return value; + } + /** + * Gets defaultIndex from the config doc. + */ + async getDefaultIndex() { + return await this.get('defaultIndex'); + } + /** + * Unset a uiSetting + */ + async unset(setting) { + return await this.requester.request({ + path: kbn_client_requester_1.uriencode `/api/kibana/settings/${setting}`, + method: 'DELETE', + }); + } + /** + * Replace all uiSettings with the `doc` values, `doc` is merged + * with some defaults + */ + async replace(doc, { retries = 5 } = {}) { + this.log.debug('replacing kibana config doc: %j', doc); + const changes = { + ...this.defaults, + ...doc, + }; + for (const [name, { isOverridden }] of Object.entries(await this.getAll())) { + if (!isOverridden && !changes.hasOwnProperty(name)) { + changes[name] = null; + } + } + await this.requester.request({ + method: 'POST', + path: '/api/kibana/settings', + body: { changes }, + retries, + }); + } + /** + * Add fields to the config doc (like setting timezone and defaultIndex) + */ + async update(updates) { + this.log.debug('applying update to kibana config: %j', updates); + await this.requester.request({ + path: '/api/kibana/settings', + method: 'POST', + body: { + changes: updates, + }, + }); + } + async getAll() { + const resp = await this.requester.request({ + path: '/api/kibana/settings', + method: 'GET', + }); + return resp.settings; + } +} +exports.KbnClientUiSettings = KbnClientUiSettings; + + +/***/ }), +/* 499 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = __webpack_require__(36); +tslib_1.__exportStar(__webpack_require__(500), exports); /***/ }), -/* 498 */ +/* 500 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43700,83 +43882,113 @@ exports.KbnClientSavedObjects = KbnClientSavedObjects; * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -const kbn_client_requester_1 = __webpack_require__(451); -class KbnClientUiSettings { - constructor(log, requester, defaults) { - this.log = log; - this.requester = requester; - this.defaults = defaults; +const tslib_1 = __webpack_require__(36); +const util_1 = __webpack_require__(29); +const axios_1 = tslib_1.__importDefault(__webpack_require__(453)); +function parseConfig(log) { + const configJson = process.env.KIBANA_CI_STATS_CONFIG; + if (!configJson) { + log.debug('KIBANA_CI_STATS_CONFIG environment variable not found, disabling CiStatsReporter'); + return; } - async get(setting) { - var _a; - const all = await this.getAll(); - const value = (_a = all[setting]) === null || _a === void 0 ? void 0 : _a.userValue; - this.log.verbose('uiSettings.value: %j', value); - return value; + let config; + try { + config = JSON.parse(configJson); } - /** - * Gets defaultIndex from the config doc. - */ - async getDefaultIndex() { - return await this.get('defaultIndex'); + catch (_) { + // handled below } - /** - * Unset a uiSetting - */ - async unset(setting) { - return await this.requester.request({ - path: kbn_client_requester_1.uriencode `/api/kibana/settings/${setting}`, - method: 'DELETE', - }); + if (typeof config === 'object' && config !== null) { + return validateConfig(log, config); } - /** - * Replace all uiSettings with the `doc` values, `doc` is merged - * with some defaults - */ - async replace(doc, { retries = 5 } = {}) { - this.log.debug('replacing kibana config doc: %j', doc); - const changes = { - ...this.defaults, - ...doc, - }; - for (const [name, { isOverridden }] of Object.entries(await this.getAll())) { - if (!isOverridden && !changes.hasOwnProperty(name)) { - changes[name] = null; - } - } - await this.requester.request({ - method: 'POST', - path: '/api/kibana/settings', - body: { changes }, - retries, - }); + log.warning('KIBANA_CI_STATS_CONFIG is invalid, stats will not be reported'); + return; +} +function validateConfig(log, config) { + const validApiUrl = typeof config.apiUrl === 'string' && config.apiUrl.length !== 0; + if (!validApiUrl) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid api url, stats will not be reported'); + return; } - /** - * Add fields to the config doc (like setting timezone and defaultIndex) - */ - async update(updates) { - this.log.debug('applying update to kibana config: %j', updates); - await this.requester.request({ - path: '/api/kibana/settings', - method: 'POST', - body: { - changes: updates, - }, - }); + const validApiToken = typeof config.apiToken === 'string' && config.apiToken.length !== 0; + if (!validApiToken) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid api token, stats will not be reported'); + return; } - async getAll() { - const resp = await this.requester.request({ - path: '/api/kibana/settings', - method: 'GET', - }); - return resp.settings; + const validId = typeof config.buildId === 'string' && config.buildId.length !== 0; + if (!validId) { + log.warning('KIBANA_CI_STATS_CONFIG is missing a valid build id, stats will not be reported'); + return; } + return config; } -exports.KbnClientUiSettings = KbnClientUiSettings; +class CiStatsReporter { + constructor(config, log) { + this.config = config; + this.log = log; + } + static fromEnv(log) { + return new CiStatsReporter(parseConfig(log), log); + } + isEnabled() { + return !!this.config; + } + async metric(name, subName, value) { + var _a, _b, _c, _d; + if (!this.config) { + return; + } + let attempt = 0; + const maxAttempts = 5; + while (true) { + attempt += 1; + try { + await axios_1.default.request({ + method: 'POST', + url: '/metric', + baseURL: this.config.apiUrl, + params: { + buildId: this.config.buildId, + }, + headers: { + Authorization: `token ${this.config.apiToken}`, + }, + data: { + name, + subName, + value, + }, + }); + return; + } + catch (error) { + if (!((_a = error) === null || _a === void 0 ? void 0 : _a.request)) { + // not an axios error, must be a usage error that we should notify user about + throw error; + } + if (((_b = error) === null || _b === void 0 ? void 0 : _b.response) && error.response.status !== 502) { + // error response from service was received so warn the user and move on + this.log.warning(`error recording metric [status=${error.response.status}] [resp=${util_1.inspect(error.response.data)}] [${name}/${subName}=${value}]`); + return; + } + if (attempt === maxAttempts) { + this.log.warning(`failed to reach kibana-ci-stats service too many times, unable to record metric [${name}/${subName}=${value}]`); + return; + } + // we failed to reach the backend and we have remaining attempts, lets retry after a short delay + const reason = ((_d = (_c = error) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.status) ? `${error.response.status} response` + : 'no response'; + this.log.warning(`failed to reach kibana-ci-stats service [reason=${reason}], retrying in ${attempt} seconds`); + await new Promise(resolve => setTimeout(resolve, attempt * 1000)); + } + } + } +} +exports.CiStatsReporter = CiStatsReporter; /***/ }), -/* 499 */ +/* 501 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -43842,7 +44054,7 @@ async function parallelize(items, fn, concurrency = 4) { } /***/ }), -/* 500 */ +/* 502 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -43851,15 +44063,15 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProjectGraph", function() { return buildProjectGraph; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "topologicallyBatchProjects", function() { return topologicallyBatchProjects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "includeTransitiveProjects", function() { return includeTransitiveProjects; }); -/* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(501); +/* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(503); /* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(glob__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__(514); -/* harmony import */ var _project__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(515); -/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(576); +/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(516); +/* harmony import */ var _project__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(517); +/* harmony import */ var _workspaces__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(578); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -44058,7 +44270,7 @@ function includeTransitiveProjects(subsetOfProjects, allProjects, { } /***/ }), -/* 501 */ +/* 503 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -44104,21 +44316,21 @@ function includeTransitiveProjects(subsetOfProjects, allProjects, { module.exports = glob var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(508) +var inherits = __webpack_require__(510) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var globSync = __webpack_require__(511) -var common = __webpack_require__(512) +var isAbsolute = __webpack_require__(512) +var globSync = __webpack_require__(513) +var common = __webpack_require__(514) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts var ownProp = common.ownProp -var inflight = __webpack_require__(513) +var inflight = __webpack_require__(515) var util = __webpack_require__(29) var childrenIgnored = common.childrenIgnored var isIgnored = common.isIgnored @@ -44854,7 +45066,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 502 */ +/* 504 */ /***/ (function(module, exports, __webpack_require__) { module.exports = realpath @@ -44870,7 +45082,7 @@ var origRealpathSync = fs.realpathSync var version = process.version var ok = /^v[0-5]\./.test(version) -var old = __webpack_require__(503) +var old = __webpack_require__(505) function newError (er) { return er && er.syscall === 'realpath' && ( @@ -44926,7 +45138,7 @@ function unmonkeypatch () { /***/ }), -/* 503 */ +/* 505 */ /***/ (function(module, exports, __webpack_require__) { // Copyright Joyent, Inc. and other Node contributors. @@ -45235,7 +45447,7 @@ exports.realpath = function realpath(p, cache, cb) { /***/ }), -/* 504 */ +/* 506 */ /***/ (function(module, exports, __webpack_require__) { module.exports = minimatch @@ -45247,7 +45459,7 @@ try { } catch (er) {} var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} -var expand = __webpack_require__(505) +var expand = __webpack_require__(507) var plTypes = { '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, @@ -46164,11 +46376,11 @@ function regExpEscape (s) { /***/ }), -/* 505 */ +/* 507 */ /***/ (function(module, exports, __webpack_require__) { -var concatMap = __webpack_require__(506); -var balanced = __webpack_require__(507); +var concatMap = __webpack_require__(508); +var balanced = __webpack_require__(509); module.exports = expandTop; @@ -46371,7 +46583,7 @@ function expand(str, isTop) { /***/ }), -/* 506 */ +/* 508 */ /***/ (function(module, exports) { module.exports = function (xs, fn) { @@ -46390,7 +46602,7 @@ var isArray = Array.isArray || function (xs) { /***/ }), -/* 507 */ +/* 509 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46456,7 +46668,7 @@ function range(a, b, str) { /***/ }), -/* 508 */ +/* 510 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -46466,12 +46678,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(509); + module.exports = __webpack_require__(511); } /***/ }), -/* 509 */ +/* 511 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -46504,7 +46716,7 @@ if (typeof Object.create === 'function') { /***/ }), -/* 510 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -46531,22 +46743,22 @@ module.exports.win32 = win32; /***/ }), -/* 511 */ +/* 513 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync globSync.GlobSync = GlobSync var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(501).Glob +var Glob = __webpack_require__(503).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var common = __webpack_require__(512) +var isAbsolute = __webpack_require__(512) +var common = __webpack_require__(514) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -47023,7 +47235,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 512 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { exports.alphasort = alphasort @@ -47041,8 +47253,8 @@ function ownProp (obj, field) { } var path = __webpack_require__(16) -var minimatch = __webpack_require__(504) -var isAbsolute = __webpack_require__(510) +var minimatch = __webpack_require__(506) +var isAbsolute = __webpack_require__(512) var Minimatch = minimatch.Minimatch function alphasorti (a, b) { @@ -47269,7 +47481,7 @@ function childrenIgnored (self, path) { /***/ }), -/* 513 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { var wrappy = __webpack_require__(385) @@ -47329,7 +47541,7 @@ function slice (args) { /***/ }), -/* 514 */ +/* 516 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -47362,7 +47574,7 @@ class CliError extends Error { } /***/ }), -/* 515 */ +/* 517 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -47376,10 +47588,10 @@ __webpack_require__.r(__webpack_exports__); /* 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__(514); +/* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(516); /* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); -/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(516); -/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(561); +/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(518); +/* harmony import */ var _scripts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(563); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -47610,7 +47822,7 @@ function normalizePath(path) { } /***/ }), -/* 516 */ +/* 518 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -47618,9 +47830,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readPackageJson", function() { return readPackageJson; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "writePackageJson", function() { return writePackageJson; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isLinkDependency", function() { return isLinkDependency; }); -/* harmony import */ var read_pkg__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(517); +/* harmony import */ var read_pkg__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(519); /* harmony import */ var read_pkg__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(read_pkg__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var write_pkg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(543); +/* harmony import */ var write_pkg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(545); /* harmony import */ var write_pkg__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(write_pkg__WEBPACK_IMPORTED_MODULE_1__); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -47654,7 +47866,7 @@ function writePackageJson(path, json) { const isLinkDependency = depVersion => depVersion.startsWith('link:'); /***/ }), -/* 517 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47662,7 +47874,7 @@ const isLinkDependency = depVersion => depVersion.startsWith('link:'); const {promisify} = __webpack_require__(29); const fs = __webpack_require__(23); const path = __webpack_require__(16); -const parseJson = __webpack_require__(518); +const parseJson = __webpack_require__(520); const readFileAsync = promisify(fs.readFile); @@ -47677,7 +47889,7 @@ module.exports = async options => { const json = parseJson(await readFileAsync(filePath, 'utf8')); if (options.normalize) { - __webpack_require__(519)(json); + __webpack_require__(521)(json); } return json; @@ -47694,7 +47906,7 @@ module.exports.sync = options => { const json = parseJson(fs.readFileSync(filePath, 'utf8')); if (options.normalize) { - __webpack_require__(519)(json); + __webpack_require__(521)(json); } return json; @@ -47702,7 +47914,7 @@ module.exports.sync = options => { /***/ }), -/* 518 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -47759,15 +47971,15 @@ module.exports = (string, reviver, filename) => { /***/ }), -/* 519 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { module.exports = normalize -var fixer = __webpack_require__(520) +var fixer = __webpack_require__(522) normalize.fixer = fixer -var makeWarning = __webpack_require__(541) +var makeWarning = __webpack_require__(543) var fieldsToFix = ['name','version','description','repository','modules','scripts' ,'files','bin','man','bugs','keywords','readme','homepage','license'] @@ -47804,17 +48016,17 @@ function ucFirst (string) { /***/ }), -/* 520 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { -var semver = __webpack_require__(521) -var validateLicense = __webpack_require__(522); -var hostedGitInfo = __webpack_require__(527) -var isBuiltinModule = __webpack_require__(530).isCore +var semver = __webpack_require__(523) +var validateLicense = __webpack_require__(524); +var hostedGitInfo = __webpack_require__(529) +var isBuiltinModule = __webpack_require__(532).isCore var depTypes = ["dependencies","devDependencies","optionalDependencies"] -var extractDescription = __webpack_require__(539) +var extractDescription = __webpack_require__(541) var url = __webpack_require__(452) -var typos = __webpack_require__(540) +var typos = __webpack_require__(542) var fixer = module.exports = { // default warning function @@ -48228,7 +48440,7 @@ function bugsTypos(bugs, warn) { /***/ }), -/* 521 */ +/* 523 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -49717,11 +49929,11 @@ function coerce (version) { /***/ }), -/* 522 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(523); -var correct = __webpack_require__(525); +var parse = __webpack_require__(525); +var correct = __webpack_require__(527); var genericWarning = ( 'license should be ' + @@ -49807,10 +50019,10 @@ module.exports = function(argument) { /***/ }), -/* 523 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { -var parser = __webpack_require__(524).parser +var parser = __webpack_require__(526).parser module.exports = function (argument) { return parser.parse(argument) @@ -49818,7 +50030,7 @@ module.exports = function (argument) { /***/ }), -/* 524 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(module) {/* parser generated by jison 0.4.17 */ @@ -51182,10 +51394,10 @@ if ( true && __webpack_require__.c[__webpack_require__.s] === module) { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 525 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { -var licenseIDs = __webpack_require__(526); +var licenseIDs = __webpack_require__(528); function valid(string) { return licenseIDs.indexOf(string) > -1; @@ -51425,20 +51637,20 @@ module.exports = function(identifier) { /***/ }), -/* 526 */ +/* 528 */ /***/ (function(module) { module.exports = JSON.parse("[\"Glide\",\"Abstyles\",\"AFL-1.1\",\"AFL-1.2\",\"AFL-2.0\",\"AFL-2.1\",\"AFL-3.0\",\"AMPAS\",\"APL-1.0\",\"Adobe-Glyph\",\"APAFML\",\"Adobe-2006\",\"AGPL-1.0\",\"Afmparse\",\"Aladdin\",\"ADSL\",\"AMDPLPA\",\"ANTLR-PD\",\"Apache-1.0\",\"Apache-1.1\",\"Apache-2.0\",\"AML\",\"APSL-1.0\",\"APSL-1.1\",\"APSL-1.2\",\"APSL-2.0\",\"Artistic-1.0\",\"Artistic-1.0-Perl\",\"Artistic-1.0-cl8\",\"Artistic-2.0\",\"AAL\",\"Bahyph\",\"Barr\",\"Beerware\",\"BitTorrent-1.0\",\"BitTorrent-1.1\",\"BSL-1.0\",\"Borceux\",\"BSD-2-Clause\",\"BSD-2-Clause-FreeBSD\",\"BSD-2-Clause-NetBSD\",\"BSD-3-Clause\",\"BSD-3-Clause-Clear\",\"BSD-4-Clause\",\"BSD-Protection\",\"BSD-Source-Code\",\"BSD-3-Clause-Attribution\",\"0BSD\",\"BSD-4-Clause-UC\",\"bzip2-1.0.5\",\"bzip2-1.0.6\",\"Caldera\",\"CECILL-1.0\",\"CECILL-1.1\",\"CECILL-2.0\",\"CECILL-2.1\",\"CECILL-B\",\"CECILL-C\",\"ClArtistic\",\"MIT-CMU\",\"CNRI-Jython\",\"CNRI-Python\",\"CNRI-Python-GPL-Compatible\",\"CPOL-1.02\",\"CDDL-1.0\",\"CDDL-1.1\",\"CPAL-1.0\",\"CPL-1.0\",\"CATOSL-1.1\",\"Condor-1.1\",\"CC-BY-1.0\",\"CC-BY-2.0\",\"CC-BY-2.5\",\"CC-BY-3.0\",\"CC-BY-4.0\",\"CC-BY-ND-1.0\",\"CC-BY-ND-2.0\",\"CC-BY-ND-2.5\",\"CC-BY-ND-3.0\",\"CC-BY-ND-4.0\",\"CC-BY-NC-1.0\",\"CC-BY-NC-2.0\",\"CC-BY-NC-2.5\",\"CC-BY-NC-3.0\",\"CC-BY-NC-4.0\",\"CC-BY-NC-ND-1.0\",\"CC-BY-NC-ND-2.0\",\"CC-BY-NC-ND-2.5\",\"CC-BY-NC-ND-3.0\",\"CC-BY-NC-ND-4.0\",\"CC-BY-NC-SA-1.0\",\"CC-BY-NC-SA-2.0\",\"CC-BY-NC-SA-2.5\",\"CC-BY-NC-SA-3.0\",\"CC-BY-NC-SA-4.0\",\"CC-BY-SA-1.0\",\"CC-BY-SA-2.0\",\"CC-BY-SA-2.5\",\"CC-BY-SA-3.0\",\"CC-BY-SA-4.0\",\"CC0-1.0\",\"Crossword\",\"CrystalStacker\",\"CUA-OPL-1.0\",\"Cube\",\"curl\",\"D-FSL-1.0\",\"diffmark\",\"WTFPL\",\"DOC\",\"Dotseqn\",\"DSDP\",\"dvipdfm\",\"EPL-1.0\",\"ECL-1.0\",\"ECL-2.0\",\"eGenix\",\"EFL-1.0\",\"EFL-2.0\",\"MIT-advertising\",\"MIT-enna\",\"Entessa\",\"ErlPL-1.1\",\"EUDatagrid\",\"EUPL-1.0\",\"EUPL-1.1\",\"Eurosym\",\"Fair\",\"MIT-feh\",\"Frameworx-1.0\",\"FreeImage\",\"FTL\",\"FSFAP\",\"FSFUL\",\"FSFULLR\",\"Giftware\",\"GL2PS\",\"Glulxe\",\"AGPL-3.0\",\"GFDL-1.1\",\"GFDL-1.2\",\"GFDL-1.3\",\"GPL-1.0\",\"GPL-2.0\",\"GPL-3.0\",\"LGPL-2.1\",\"LGPL-3.0\",\"LGPL-2.0\",\"gnuplot\",\"gSOAP-1.3b\",\"HaskellReport\",\"HPND\",\"IBM-pibs\",\"IPL-1.0\",\"ICU\",\"ImageMagick\",\"iMatix\",\"Imlib2\",\"IJG\",\"Info-ZIP\",\"Intel-ACPI\",\"Intel\",\"Interbase-1.0\",\"IPA\",\"ISC\",\"JasPer-2.0\",\"JSON\",\"LPPL-1.0\",\"LPPL-1.1\",\"LPPL-1.2\",\"LPPL-1.3a\",\"LPPL-1.3c\",\"Latex2e\",\"BSD-3-Clause-LBNL\",\"Leptonica\",\"LGPLLR\",\"Libpng\",\"libtiff\",\"LAL-1.2\",\"LAL-1.3\",\"LiLiQ-P-1.1\",\"LiLiQ-Rplus-1.1\",\"LiLiQ-R-1.1\",\"LPL-1.02\",\"LPL-1.0\",\"MakeIndex\",\"MTLL\",\"MS-PL\",\"MS-RL\",\"MirOS\",\"MITNFA\",\"MIT\",\"Motosoto\",\"MPL-1.0\",\"MPL-1.1\",\"MPL-2.0\",\"MPL-2.0-no-copyleft-exception\",\"mpich2\",\"Multics\",\"Mup\",\"NASA-1.3\",\"Naumen\",\"NBPL-1.0\",\"NetCDF\",\"NGPL\",\"NOSL\",\"NPL-1.0\",\"NPL-1.1\",\"Newsletr\",\"NLPL\",\"Nokia\",\"NPOSL-3.0\",\"NLOD-1.0\",\"Noweb\",\"NRL\",\"NTP\",\"Nunit\",\"OCLC-2.0\",\"ODbL-1.0\",\"PDDL-1.0\",\"OCCT-PL\",\"OGTSL\",\"OLDAP-2.2.2\",\"OLDAP-1.1\",\"OLDAP-1.2\",\"OLDAP-1.3\",\"OLDAP-1.4\",\"OLDAP-2.0\",\"OLDAP-2.0.1\",\"OLDAP-2.1\",\"OLDAP-2.2\",\"OLDAP-2.2.1\",\"OLDAP-2.3\",\"OLDAP-2.4\",\"OLDAP-2.5\",\"OLDAP-2.6\",\"OLDAP-2.7\",\"OLDAP-2.8\",\"OML\",\"OPL-1.0\",\"OSL-1.0\",\"OSL-1.1\",\"OSL-2.0\",\"OSL-2.1\",\"OSL-3.0\",\"OpenSSL\",\"OSET-PL-2.1\",\"PHP-3.0\",\"PHP-3.01\",\"Plexus\",\"PostgreSQL\",\"psfrag\",\"psutils\",\"Python-2.0\",\"QPL-1.0\",\"Qhull\",\"Rdisc\",\"RPSL-1.0\",\"RPL-1.1\",\"RPL-1.5\",\"RHeCos-1.1\",\"RSCPL\",\"RSA-MD\",\"Ruby\",\"SAX-PD\",\"Saxpath\",\"SCEA\",\"SWL\",\"SMPPL\",\"Sendmail\",\"SGI-B-1.0\",\"SGI-B-1.1\",\"SGI-B-2.0\",\"OFL-1.0\",\"OFL-1.1\",\"SimPL-2.0\",\"Sleepycat\",\"SNIA\",\"Spencer-86\",\"Spencer-94\",\"Spencer-99\",\"SMLNJ\",\"SugarCRM-1.1.3\",\"SISSL\",\"SISSL-1.2\",\"SPL-1.0\",\"Watcom-1.0\",\"TCL\",\"Unlicense\",\"TMate\",\"TORQUE-1.1\",\"TOSL\",\"Unicode-TOU\",\"UPL-1.0\",\"NCSA\",\"Vim\",\"VOSTROM\",\"VSL-1.0\",\"W3C-19980720\",\"W3C\",\"Wsuipa\",\"Xnet\",\"X11\",\"Xerox\",\"XFree86-1.1\",\"xinetd\",\"xpp\",\"XSkat\",\"YPL-1.0\",\"YPL-1.1\",\"Zed\",\"Zend-2.0\",\"Zimbra-1.3\",\"Zimbra-1.4\",\"Zlib\",\"zlib-acknowledgement\",\"ZPL-1.1\",\"ZPL-2.0\",\"ZPL-2.1\",\"BSD-3-Clause-No-Nuclear-License\",\"BSD-3-Clause-No-Nuclear-Warranty\",\"BSD-3-Clause-No-Nuclear-License-2014\",\"eCos-2.0\",\"GPL-2.0-with-autoconf-exception\",\"GPL-2.0-with-bison-exception\",\"GPL-2.0-with-classpath-exception\",\"GPL-2.0-with-font-exception\",\"GPL-2.0-with-GCC-exception\",\"GPL-3.0-with-autoconf-exception\",\"GPL-3.0-with-GCC-exception\",\"StandardML-NJ\",\"WXwindows\"]"); /***/ }), -/* 527 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var url = __webpack_require__(452) -var gitHosts = __webpack_require__(528) -var GitHost = module.exports = __webpack_require__(529) +var gitHosts = __webpack_require__(530) +var GitHost = module.exports = __webpack_require__(531) var protocolToRepresentationMap = { 'git+ssh': 'sshurl', @@ -51559,7 +51771,7 @@ function parseGitUrl (giturl) { /***/ }), -/* 528 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -51634,12 +51846,12 @@ Object.keys(gitHosts).forEach(function (name) { /***/ }), -/* 529 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var gitHosts = __webpack_require__(528) +var gitHosts = __webpack_require__(530) var extend = Object.assign || __webpack_require__(29)._extend var GitHost = module.exports = function (type, user, auth, project, committish, defaultRepresentation, opts) { @@ -51755,21 +51967,21 @@ GitHost.prototype.toString = function (opts) { /***/ }), -/* 530 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { -var core = __webpack_require__(531); -var async = __webpack_require__(533); +var core = __webpack_require__(533); +var async = __webpack_require__(535); async.core = core; async.isCore = function isCore(x) { return core[x]; }; -async.sync = __webpack_require__(538); +async.sync = __webpack_require__(540); exports = async; module.exports = async; /***/ }), -/* 531 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { var current = (process.versions && process.versions.node && process.versions.node.split('.')) || []; @@ -51816,7 +52028,7 @@ function versionIncluded(specifierValue) { return matchesRange(specifierValue); } -var data = __webpack_require__(532); +var data = __webpack_require__(534); var core = {}; for (var mod in data) { // eslint-disable-line no-restricted-syntax @@ -51828,21 +52040,21 @@ module.exports = core; /***/ }), -/* 532 */ +/* 534 */ /***/ (function(module) { module.exports = JSON.parse("{\"assert\":true,\"async_hooks\":\">= 8\",\"buffer_ieee754\":\"< 0.9.7\",\"buffer\":true,\"child_process\":true,\"cluster\":true,\"console\":true,\"constants\":true,\"crypto\":true,\"_debugger\":\"< 8\",\"dgram\":true,\"dns\":true,\"domain\":true,\"events\":true,\"freelist\":\"< 6\",\"fs\":true,\"fs/promises\":\">= 10 && < 10.1\",\"_http_agent\":\">= 0.11.1\",\"_http_client\":\">= 0.11.1\",\"_http_common\":\">= 0.11.1\",\"_http_incoming\":\">= 0.11.1\",\"_http_outgoing\":\">= 0.11.1\",\"_http_server\":\">= 0.11.1\",\"http\":true,\"http2\":\">= 8.8\",\"https\":true,\"inspector\":\">= 8.0.0\",\"_linklist\":\"< 8\",\"module\":true,\"net\":true,\"node-inspect/lib/_inspect\":\">= 7.6.0\",\"node-inspect/lib/internal/inspect_client\":\">= 7.6.0\",\"node-inspect/lib/internal/inspect_repl\":\">= 7.6.0\",\"os\":true,\"path\":true,\"perf_hooks\":\">= 8.5\",\"process\":\">= 1\",\"punycode\":true,\"querystring\":true,\"readline\":true,\"repl\":true,\"smalloc\":\">= 0.11.5 && < 3\",\"_stream_duplex\":\">= 0.9.4\",\"_stream_transform\":\">= 0.9.4\",\"_stream_wrap\":\">= 1.4.1\",\"_stream_passthrough\":\">= 0.9.4\",\"_stream_readable\":\">= 0.9.4\",\"_stream_writable\":\">= 0.9.4\",\"stream\":true,\"string_decoder\":true,\"sys\":true,\"timers\":true,\"_tls_common\":\">= 0.11.13\",\"_tls_legacy\":\">= 0.11.3 && < 10\",\"_tls_wrap\":\">= 0.11.3\",\"tls\":true,\"trace_events\":\">= 10\",\"tty\":true,\"url\":true,\"util\":true,\"v8/tools/arguments\":\">= 10\",\"v8/tools/codemap\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8/tools/consarray\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8/tools/csvparser\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8/tools/logreader\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8/tools/profile_view\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8/tools/splaytree\":[\">= 4.4.0 && < 5\",\">= 5.2.0\"],\"v8\":\">= 1\",\"vm\":true,\"worker_threads\":\">= 11.7\",\"zlib\":true}"); /***/ }), -/* 533 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { -var core = __webpack_require__(531); +var core = __webpack_require__(533); var fs = __webpack_require__(23); var path = __webpack_require__(16); -var caller = __webpack_require__(534); -var nodeModulesPaths = __webpack_require__(535); -var normalizeOptions = __webpack_require__(537); +var caller = __webpack_require__(536); +var nodeModulesPaths = __webpack_require__(537); +var normalizeOptions = __webpack_require__(539); var defaultIsFile = function isFile(file, cb) { fs.stat(file, function (err, stat) { @@ -52069,7 +52281,7 @@ module.exports = function resolve(x, options, callback) { /***/ }), -/* 534 */ +/* 536 */ /***/ (function(module, exports) { module.exports = function () { @@ -52083,11 +52295,11 @@ module.exports = function () { /***/ }), -/* 535 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { var path = __webpack_require__(16); -var parse = path.parse || __webpack_require__(536); +var parse = path.parse || __webpack_require__(538); var getNodeModulesDirs = function getNodeModulesDirs(absoluteStart, modules) { var prefix = '/'; @@ -52131,7 +52343,7 @@ module.exports = function nodeModulesPaths(start, opts, request) { /***/ }), -/* 536 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -52231,7 +52443,7 @@ module.exports.win32 = win32.parse; /***/ }), -/* 537 */ +/* 539 */ /***/ (function(module, exports) { module.exports = function (x, opts) { @@ -52247,15 +52459,15 @@ module.exports = function (x, opts) { /***/ }), -/* 538 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { -var core = __webpack_require__(531); +var core = __webpack_require__(533); var fs = __webpack_require__(23); var path = __webpack_require__(16); -var caller = __webpack_require__(534); -var nodeModulesPaths = __webpack_require__(535); -var normalizeOptions = __webpack_require__(537); +var caller = __webpack_require__(536); +var nodeModulesPaths = __webpack_require__(537); +var normalizeOptions = __webpack_require__(539); var defaultIsFile = function isFile(file) { try { @@ -52407,7 +52619,7 @@ module.exports = function (x, options) { /***/ }), -/* 539 */ +/* 541 */ /***/ (function(module, exports) { module.exports = extractDescription @@ -52427,17 +52639,17 @@ function extractDescription (d) { /***/ }), -/* 540 */ +/* 542 */ /***/ (function(module) { module.exports = JSON.parse("{\"topLevel\":{\"dependancies\":\"dependencies\",\"dependecies\":\"dependencies\",\"depdenencies\":\"dependencies\",\"devEependencies\":\"devDependencies\",\"depends\":\"dependencies\",\"dev-dependencies\":\"devDependencies\",\"devDependences\":\"devDependencies\",\"devDepenencies\":\"devDependencies\",\"devdependencies\":\"devDependencies\",\"repostitory\":\"repository\",\"repo\":\"repository\",\"prefereGlobal\":\"preferGlobal\",\"hompage\":\"homepage\",\"hampage\":\"homepage\",\"autohr\":\"author\",\"autor\":\"author\",\"contributers\":\"contributors\",\"publicationConfig\":\"publishConfig\",\"script\":\"scripts\"},\"bugs\":{\"web\":\"url\",\"name\":\"url\"},\"script\":{\"server\":\"start\",\"tests\":\"test\"}}"); /***/ }), -/* 541 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { var util = __webpack_require__(29) -var messages = __webpack_require__(542) +var messages = __webpack_require__(544) module.exports = function() { var args = Array.prototype.slice.call(arguments, 0) @@ -52462,20 +52674,20 @@ function makeTypoWarning (providedName, probableName, field) { /***/ }), -/* 542 */ +/* 544 */ /***/ (function(module) { module.exports = JSON.parse("{\"repositories\":\"'repositories' (plural) Not supported. Please pick one as the 'repository' field\",\"missingRepository\":\"No repository field.\",\"brokenGitUrl\":\"Probably broken git url: %s\",\"nonObjectScripts\":\"scripts must be an object\",\"nonStringScript\":\"script values must be string commands\",\"nonArrayFiles\":\"Invalid 'files' member\",\"invalidFilename\":\"Invalid filename in 'files' list: %s\",\"nonArrayBundleDependencies\":\"Invalid 'bundleDependencies' list. Must be array of package names\",\"nonStringBundleDependency\":\"Invalid bundleDependencies member: %s\",\"nonDependencyBundleDependency\":\"Non-dependency in bundleDependencies: %s\",\"nonObjectDependencies\":\"%s field must be an object\",\"nonStringDependency\":\"Invalid dependency: %s %s\",\"deprecatedArrayDependencies\":\"specifying %s as array is deprecated\",\"deprecatedModules\":\"modules field is deprecated\",\"nonArrayKeywords\":\"keywords should be an array of strings\",\"nonStringKeyword\":\"keywords should be an array of strings\",\"conflictingName\":\"%s is also the name of a node core module.\",\"nonStringDescription\":\"'description' field should be a string\",\"missingDescription\":\"No description\",\"missingReadme\":\"No README data\",\"missingLicense\":\"No license field.\",\"nonEmailUrlBugsString\":\"Bug string field must be url, email, or {email,url}\",\"nonUrlBugsUrlField\":\"bugs.url field must be a string url. Deleted.\",\"nonEmailBugsEmailField\":\"bugs.email field must be a string email. Deleted.\",\"emptyNormalizedBugs\":\"Normalized value of bugs field is an empty object. Deleted.\",\"nonUrlHomepage\":\"homepage field must be a string url. Deleted.\",\"invalidLicense\":\"license should be a valid SPDX license expression\",\"typo\":\"%s should probably be %s.\"}"); /***/ }), -/* 543 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const writeJsonFile = __webpack_require__(544); -const sortKeys = __webpack_require__(556); +const writeJsonFile = __webpack_require__(546); +const sortKeys = __webpack_require__(558); const dependencyKeys = new Set([ 'dependencies', @@ -52540,18 +52752,18 @@ module.exports.sync = (filePath, data, options) => { /***/ }), -/* 544 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const fs = __webpack_require__(545); -const writeFileAtomic = __webpack_require__(549); -const sortKeys = __webpack_require__(556); -const makeDir = __webpack_require__(558); -const pify = __webpack_require__(559); -const detectIndent = __webpack_require__(560); +const fs = __webpack_require__(547); +const writeFileAtomic = __webpack_require__(551); +const sortKeys = __webpack_require__(558); +const makeDir = __webpack_require__(560); +const pify = __webpack_require__(561); +const detectIndent = __webpack_require__(562); const init = (fn, filePath, data, options) => { if (!filePath) { @@ -52623,13 +52835,13 @@ module.exports.sync = (filePath, data, options) => { /***/ }), -/* 545 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(23) -var polyfills = __webpack_require__(546) -var legacy = __webpack_require__(547) -var clone = __webpack_require__(548) +var polyfills = __webpack_require__(548) +var legacy = __webpack_require__(549) +var clone = __webpack_require__(550) var queue = [] @@ -52908,7 +53120,7 @@ function retry () { /***/ }), -/* 546 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { var constants = __webpack_require__(25) @@ -53243,7 +53455,7 @@ function patch (fs) { /***/ }), -/* 547 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27).Stream @@ -53367,7 +53579,7 @@ function legacy (fs) { /***/ }), -/* 548 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53393,7 +53605,7 @@ function clone (obj) { /***/ }), -/* 549 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -53403,8 +53615,8 @@ module.exports.sync = writeFileSync module.exports._getTmpname = getTmpname // for testing module.exports._cleanupOnExit = cleanupOnExit -var fs = __webpack_require__(550) -var MurmurHash3 = __webpack_require__(554) +var fs = __webpack_require__(552) +var MurmurHash3 = __webpack_require__(556) var onExit = __webpack_require__(377) var path = __webpack_require__(16) var activeFiles = {} @@ -53413,7 +53625,7 @@ var activeFiles = {} /* istanbul ignore next */ var threadId = (function getId () { try { - var workerThreads = __webpack_require__(555) + var workerThreads = __webpack_require__(557) /// if we are in main thread, this is set to `0` return workerThreads.threadId @@ -53638,12 +53850,12 @@ function writeFileSync (filename, data, options) { /***/ }), -/* 550 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { var fs = __webpack_require__(23) -var polyfills = __webpack_require__(551) -var legacy = __webpack_require__(553) +var polyfills = __webpack_require__(553) +var legacy = __webpack_require__(555) var queue = [] var util = __webpack_require__(29) @@ -53667,7 +53879,7 @@ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { }) } -module.exports = patch(__webpack_require__(552)) +module.exports = patch(__webpack_require__(554)) if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { module.exports = patch(fs) } @@ -53906,10 +54118,10 @@ function retry () { /***/ }), -/* 551 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { -var fs = __webpack_require__(552) +var fs = __webpack_require__(554) var constants = __webpack_require__(25) var origCwd = process.cwd @@ -54242,7 +54454,7 @@ function chownErOk (er) { /***/ }), -/* 552 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -54270,7 +54482,7 @@ function clone (obj) { /***/ }), -/* 553 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27).Stream @@ -54394,7 +54606,7 @@ function legacy (fs) { /***/ }), -/* 554 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -54536,18 +54748,18 @@ function legacy (fs) { /***/ }), -/* 555 */ +/* 557 */ /***/ (function(module, exports) { module.exports = require(undefined); /***/ }), -/* 556 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const isPlainObj = __webpack_require__(557); +const isPlainObj = __webpack_require__(559); module.exports = (obj, opts) => { if (!isPlainObj(obj)) { @@ -54604,7 +54816,7 @@ module.exports = (obj, opts) => { /***/ }), -/* 557 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -54618,15 +54830,15 @@ module.exports = function (x) { /***/ }), -/* 558 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const pify = __webpack_require__(559); -const semver = __webpack_require__(521); +const pify = __webpack_require__(561); +const semver = __webpack_require__(523); const defaults = { mode: 0o777 & (~process.umask()), @@ -54764,7 +54976,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 559 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -54839,7 +55051,7 @@ module.exports = (input, options) => { /***/ }), -/* 560 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -54968,7 +55180,7 @@ module.exports = str => { /***/ }), -/* 561 */ +/* 563 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -54977,7 +55189,7 @@ __webpack_require__.r(__webpack_exports__); /* 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__(562); +/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(564); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -55047,7 +55259,7 @@ async function yarnWorkspacesInfo(directory) { } /***/ }), -/* 562 */ +/* 564 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -55058,9 +55270,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(351); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(563); +/* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(565); /* harmony import */ var log_symbols__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(log_symbols__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(568); +/* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(570); /* harmony import */ var strong_log_transformer__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(strong_log_transformer__WEBPACK_IMPORTED_MODULE_3__); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } @@ -55126,12 +55338,12 @@ function spawnStreaming(command, args, opts, { } /***/ }), -/* 563 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(564); +const chalk = __webpack_require__(566); const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; @@ -55153,16 +55365,16 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 564 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(565); -const stdoutColor = __webpack_require__(566).stdout; +const ansiStyles = __webpack_require__(567); +const stdoutColor = __webpack_require__(568).stdout; -const template = __webpack_require__(567); +const template = __webpack_require__(569); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -55388,7 +55600,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 565 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55561,7 +55773,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 566 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55703,7 +55915,7 @@ module.exports = { /***/ }), -/* 567 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55838,7 +56050,7 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 568 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { // Copyright IBM Corp. 2014,2018. All Rights Reserved. @@ -55846,12 +56058,12 @@ module.exports = (chalk, tmp) => { // This file is licensed under the Apache License 2.0. // License text available at https://opensource.org/licenses/Apache-2.0 -module.exports = __webpack_require__(569); -module.exports.cli = __webpack_require__(573); +module.exports = __webpack_require__(571); +module.exports.cli = __webpack_require__(575); /***/ }), -/* 569 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -55866,9 +56078,9 @@ var stream = __webpack_require__(27); var util = __webpack_require__(29); var fs = __webpack_require__(23); -var through = __webpack_require__(570); -var duplexer = __webpack_require__(571); -var StringDecoder = __webpack_require__(572).StringDecoder; +var through = __webpack_require__(572); +var duplexer = __webpack_require__(573); +var StringDecoder = __webpack_require__(574).StringDecoder; module.exports = Logger; @@ -56057,7 +56269,7 @@ function lineMerger(host) { /***/ }), -/* 570 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27) @@ -56171,7 +56383,7 @@ function through (write, end, opts) { /***/ }), -/* 571 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27) @@ -56264,13 +56476,13 @@ function duplex(writer, reader) { /***/ }), -/* 572 */ +/* 574 */ /***/ (function(module, exports) { module.exports = require("string_decoder"); /***/ }), -/* 573 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -56281,11 +56493,11 @@ module.exports = require("string_decoder"); -var minimist = __webpack_require__(574); +var minimist = __webpack_require__(576); var path = __webpack_require__(16); -var Logger = __webpack_require__(569); -var pkg = __webpack_require__(575); +var Logger = __webpack_require__(571); +var pkg = __webpack_require__(577); module.exports = cli; @@ -56339,7 +56551,7 @@ function usage($0, p) { /***/ }), -/* 574 */ +/* 576 */ /***/ (function(module, exports) { module.exports = function (args, opts) { @@ -56581,29 +56793,29 @@ function isNumber (x) { /***/ }), -/* 575 */ +/* 577 */ /***/ (function(module) { module.exports = JSON.parse("{\"name\":\"strong-log-transformer\",\"version\":\"2.1.0\",\"description\":\"Stream transformer that prefixes lines with timestamps and other things.\",\"author\":\"Ryan Graham \",\"license\":\"Apache-2.0\",\"repository\":{\"type\":\"git\",\"url\":\"git://github.com/strongloop/strong-log-transformer\"},\"keywords\":[\"logging\",\"streams\"],\"bugs\":{\"url\":\"https://github.com/strongloop/strong-log-transformer/issues\"},\"homepage\":\"https://github.com/strongloop/strong-log-transformer\",\"directories\":{\"test\":\"test\"},\"bin\":{\"sl-log-transformer\":\"bin/sl-log-transformer.js\"},\"main\":\"index.js\",\"scripts\":{\"test\":\"tap --100 test/test-*\"},\"dependencies\":{\"duplexer\":\"^0.1.1\",\"minimist\":\"^1.2.0\",\"through\":\"^2.3.4\"},\"devDependencies\":{\"tap\":\"^12.0.1\"},\"engines\":{\"node\":\">=4\"}}"); /***/ }), -/* 576 */ +/* 578 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "workspacePackagePaths", function() { return workspacePackagePaths; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copyWorkspacePackages", function() { return copyWorkspacePackages; }); -/* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(501); +/* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(503); /* harmony import */ var glob__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(glob__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 _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(577); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); -/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(516); -/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(500); +/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(518); +/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(502); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -56695,7 +56907,7 @@ function packagesFromGlobPattern({ } /***/ }), -/* 577 */ +/* 579 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56765,7 +56977,7 @@ function getProjectPaths({ } /***/ }), -/* 578 */ +/* 580 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -56773,13 +56985,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getAllChecksums", function() { return getAllChecksums; }); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(579); +/* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(581); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(crypto__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 execa__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(351); /* harmony import */ var execa__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(execa__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(580); +/* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(582); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -57005,19 +57217,19 @@ async function getAllChecksums(kbn, log) { } /***/ }), -/* 579 */ +/* 581 */ /***/ (function(module, exports) { module.exports = require("crypto"); /***/ }), -/* 580 */ +/* 582 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readYarnLock", function() { return readYarnLock; }); -/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(581); +/* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(583); /* harmony import */ var _yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_yarnpkg_lockfile__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(20); /* @@ -57061,7 +57273,7 @@ async function readYarnLock(kbn) { } /***/ }), -/* 581 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { module.exports = @@ -58620,7 +58832,7 @@ module.exports = invariant; /* 9 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(579); +module.exports = __webpack_require__(581); /***/ }), /* 10 */, @@ -60944,7 +61156,7 @@ function onceStrict (fn) { /* 63 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(582); +module.exports = __webpack_require__(584); /***/ }), /* 64 */, @@ -61882,7 +62094,7 @@ module.exports.win32 = win32; /* 79 */ /***/ (function(module, exports) { -module.exports = __webpack_require__(478); +module.exports = __webpack_require__(484); /***/ }), /* 80 */, @@ -67339,13 +67551,13 @@ module.exports = process && support(supportLevel); /******/ ]); /***/ }), -/* 582 */ +/* 584 */ /***/ (function(module, exports) { module.exports = require("buffer"); /***/ }), -/* 583 */ +/* 585 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -67442,7 +67654,7 @@ class BootstrapCacheFile { } /***/ }), -/* 584 */ +/* 586 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -67450,9 +67662,9 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CleanCommand", function() { return CleanCommand; }); /* 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 del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(585); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(673); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(675); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -67551,21 +67763,21 @@ const CleanCommand = { }; /***/ }), -/* 585 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const path = __webpack_require__(16); -const globby = __webpack_require__(586); -const isGlob = __webpack_require__(603); -const slash = __webpack_require__(664); +const globby = __webpack_require__(588); +const isGlob = __webpack_require__(605); +const slash = __webpack_require__(666); const gracefulFs = __webpack_require__(22); -const isPathCwd = __webpack_require__(666); -const isPathInside = __webpack_require__(667); -const rimraf = __webpack_require__(668); -const pMap = __webpack_require__(669); +const isPathCwd = __webpack_require__(668); +const isPathInside = __webpack_require__(669); +const rimraf = __webpack_require__(670); +const pMap = __webpack_require__(671); const rimrafP = promisify(rimraf); @@ -67679,19 +67891,19 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options /***/ }), -/* 586 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(587); -const merge2 = __webpack_require__(588); -const glob = __webpack_require__(589); -const fastGlob = __webpack_require__(594); -const dirGlob = __webpack_require__(660); -const gitignore = __webpack_require__(662); -const {FilterStream, UniqueStream} = __webpack_require__(665); +const arrayUnion = __webpack_require__(589); +const merge2 = __webpack_require__(590); +const glob = __webpack_require__(591); +const fastGlob = __webpack_require__(596); +const dirGlob = __webpack_require__(662); +const gitignore = __webpack_require__(664); +const {FilterStream, UniqueStream} = __webpack_require__(667); const DEFAULT_FILTER = () => false; @@ -67864,7 +68076,7 @@ module.exports.gitignore = gitignore; /***/ }), -/* 587 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67876,7 +68088,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 588 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67990,7 +68202,7 @@ function pauseStreams (streams, options) { /***/ }), -/* 589 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -68036,21 +68248,21 @@ function pauseStreams (streams, options) { module.exports = glob var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(590) +var inherits = __webpack_require__(592) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var globSync = __webpack_require__(592) -var common = __webpack_require__(593) +var isAbsolute = __webpack_require__(512) +var globSync = __webpack_require__(594) +var common = __webpack_require__(595) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts var ownProp = common.ownProp -var inflight = __webpack_require__(513) +var inflight = __webpack_require__(515) var util = __webpack_require__(29) var childrenIgnored = common.childrenIgnored var isIgnored = common.isIgnored @@ -68786,7 +68998,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 590 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -68796,12 +69008,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(591); + module.exports = __webpack_require__(593); } /***/ }), -/* 591 */ +/* 593 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -68834,22 +69046,22 @@ if (typeof Object.create === 'function') { /***/ }), -/* 592 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync globSync.GlobSync = GlobSync var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(589).Glob +var Glob = __webpack_require__(591).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var common = __webpack_require__(593) +var isAbsolute = __webpack_require__(512) +var common = __webpack_require__(595) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -69326,7 +69538,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 593 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { exports.alphasort = alphasort @@ -69344,8 +69556,8 @@ function ownProp (obj, field) { } var path = __webpack_require__(16) -var minimatch = __webpack_require__(504) -var isAbsolute = __webpack_require__(510) +var minimatch = __webpack_require__(506) +var isAbsolute = __webpack_require__(512) var Minimatch = minimatch.Minimatch function alphasorti (a, b) { @@ -69572,17 +69784,17 @@ function childrenIgnored (self, path) { /***/ }), -/* 594 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(595); -const async_1 = __webpack_require__(623); -const stream_1 = __webpack_require__(656); -const sync_1 = __webpack_require__(657); -const settings_1 = __webpack_require__(659); -const utils = __webpack_require__(596); +const taskManager = __webpack_require__(597); +const async_1 = __webpack_require__(625); +const stream_1 = __webpack_require__(658); +const sync_1 = __webpack_require__(659); +const settings_1 = __webpack_require__(661); +const utils = __webpack_require__(598); function FastGlob(source, options) { try { assertPatternsInput(source); @@ -69640,13 +69852,13 @@ module.exports = FastGlob; /***/ }), -/* 595 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(596); +const utils = __webpack_require__(598); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -69714,28 +69926,28 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 596 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const array = __webpack_require__(597); +const array = __webpack_require__(599); exports.array = array; -const errno = __webpack_require__(598); +const errno = __webpack_require__(600); exports.errno = errno; -const fs = __webpack_require__(599); +const fs = __webpack_require__(601); exports.fs = fs; -const path = __webpack_require__(600); +const path = __webpack_require__(602); exports.path = path; -const pattern = __webpack_require__(601); +const pattern = __webpack_require__(603); exports.pattern = pattern; -const stream = __webpack_require__(622); +const stream = __webpack_require__(624); exports.stream = stream; /***/ }), -/* 597 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69748,7 +69960,7 @@ exports.flatten = flatten; /***/ }), -/* 598 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69761,7 +69973,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 599 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69786,7 +69998,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 600 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69807,16 +70019,16 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 601 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const globParent = __webpack_require__(602); -const isGlob = __webpack_require__(603); -const micromatch = __webpack_require__(605); +const globParent = __webpack_require__(604); +const isGlob = __webpack_require__(605); +const micromatch = __webpack_require__(607); const GLOBSTAR = '**'; function isStaticPattern(pattern) { return !isDynamicPattern(pattern); @@ -69905,13 +70117,13 @@ exports.matchAny = matchAny; /***/ }), -/* 602 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isGlob = __webpack_require__(603); +var isGlob = __webpack_require__(605); var pathPosixDirname = __webpack_require__(16).posix.dirname; var isWin32 = __webpack_require__(11).platform() === 'win32'; @@ -69946,7 +70158,7 @@ module.exports = function globParent(str) { /***/ }), -/* 603 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -69956,7 +70168,7 @@ module.exports = function globParent(str) { * Released under the MIT License. */ -var isExtglob = __webpack_require__(604); +var isExtglob = __webpack_require__(606); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -70000,7 +70212,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 604 */ +/* 606 */ /***/ (function(module, exports) { /*! @@ -70026,16 +70238,16 @@ module.exports = function isExtglob(str) { /***/ }), -/* 605 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const util = __webpack_require__(29); -const braces = __webpack_require__(606); -const picomatch = __webpack_require__(616); -const utils = __webpack_require__(619); +const braces = __webpack_require__(608); +const picomatch = __webpack_require__(618); +const utils = __webpack_require__(621); const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); /** @@ -70500,16 +70712,16 @@ module.exports = micromatch; /***/ }), -/* 606 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(607); -const compile = __webpack_require__(609); -const expand = __webpack_require__(613); -const parse = __webpack_require__(614); +const stringify = __webpack_require__(609); +const compile = __webpack_require__(611); +const expand = __webpack_require__(615); +const parse = __webpack_require__(616); /** * Expand the given pattern or create a regex-compatible string. @@ -70677,13 +70889,13 @@ module.exports = braces; /***/ }), -/* 607 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(608); +const utils = __webpack_require__(610); module.exports = (ast, options = {}) => { let stringify = (node, parent = {}) => { @@ -70716,7 +70928,7 @@ module.exports = (ast, options = {}) => { /***/ }), -/* 608 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70835,14 +71047,14 @@ exports.flatten = (...args) => { /***/ }), -/* 609 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(610); -const utils = __webpack_require__(608); +const fill = __webpack_require__(612); +const utils = __webpack_require__(610); const compile = (ast, options = {}) => { let walk = (node, parent = {}) => { @@ -70899,7 +71111,7 @@ module.exports = compile; /***/ }), -/* 610 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70913,7 +71125,7 @@ module.exports = compile; const util = __webpack_require__(29); -const toRegexRange = __webpack_require__(611); +const toRegexRange = __webpack_require__(613); const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); @@ -71155,7 +71367,7 @@ module.exports = fill; /***/ }), -/* 611 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71168,7 +71380,7 @@ module.exports = fill; -const isNumber = __webpack_require__(612); +const isNumber = __webpack_require__(614); const toRegexRange = (min, max, options) => { if (isNumber(min) === false) { @@ -71450,7 +71662,7 @@ module.exports = toRegexRange; /***/ }), -/* 612 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71475,15 +71687,15 @@ module.exports = function(num) { /***/ }), -/* 613 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(610); -const stringify = __webpack_require__(607); -const utils = __webpack_require__(608); +const fill = __webpack_require__(612); +const stringify = __webpack_require__(609); +const utils = __webpack_require__(610); const append = (queue = '', stash = '', enclose = false) => { let result = []; @@ -71595,13 +71807,13 @@ module.exports = expand; /***/ }), -/* 614 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(607); +const stringify = __webpack_require__(609); /** * Constants @@ -71623,7 +71835,7 @@ const { CHAR_SINGLE_QUOTE, /* ' */ CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(615); +} = __webpack_require__(617); /** * parse @@ -71935,7 +72147,7 @@ module.exports = parse; /***/ }), -/* 615 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71999,26 +72211,26 @@ module.exports = { /***/ }), -/* 616 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(617); +module.exports = __webpack_require__(619); /***/ }), -/* 617 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const scan = __webpack_require__(618); -const parse = __webpack_require__(621); -const utils = __webpack_require__(619); +const scan = __webpack_require__(620); +const parse = __webpack_require__(623); +const utils = __webpack_require__(621); /** * Creates a matcher function from one or more glob patterns. The @@ -72321,7 +72533,7 @@ picomatch.toRegex = (source, options) => { * @return {Object} */ -picomatch.constants = __webpack_require__(620); +picomatch.constants = __webpack_require__(622); /** * Expose "picomatch" @@ -72331,13 +72543,13 @@ module.exports = picomatch; /***/ }), -/* 618 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(619); +const utils = __webpack_require__(621); const { CHAR_ASTERISK, /* * */ @@ -72355,7 +72567,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(620); +} = __webpack_require__(622); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -72557,7 +72769,7 @@ module.exports = (input, options) => { /***/ }), -/* 619 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72569,7 +72781,7 @@ const { REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL, REGEX_REMOVE_BACKSLASH -} = __webpack_require__(620); +} = __webpack_require__(622); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -72607,7 +72819,7 @@ exports.escapeLast = (input, char, lastIdx) => { /***/ }), -/* 620 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72793,14 +73005,14 @@ module.exports = { /***/ }), -/* 621 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(619); -const constants = __webpack_require__(620); +const utils = __webpack_require__(621); +const constants = __webpack_require__(622); /** * Constants @@ -73811,13 +74023,13 @@ module.exports = parse; /***/ }), -/* 622 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(588); +const merge2 = __webpack_require__(590); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { @@ -73829,14 +74041,14 @@ exports.merge = merge; /***/ }), -/* 623 */ +/* 625 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(624); -const provider_1 = __webpack_require__(651); +const stream_1 = __webpack_require__(626); +const provider_1 = __webpack_require__(653); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -73864,16 +74076,16 @@ exports.default = ProviderAsync; /***/ }), -/* 624 */ +/* 626 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const fsStat = __webpack_require__(625); -const fsWalk = __webpack_require__(630); -const reader_1 = __webpack_require__(650); +const fsStat = __webpack_require__(627); +const fsWalk = __webpack_require__(632); +const reader_1 = __webpack_require__(652); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -73926,15 +74138,15 @@ exports.default = ReaderStream; /***/ }), -/* 625 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(626); -const sync = __webpack_require__(627); -const settings_1 = __webpack_require__(628); +const async = __webpack_require__(628); +const sync = __webpack_require__(629); +const settings_1 = __webpack_require__(630); exports.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -73957,7 +74169,7 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 626 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73995,7 +74207,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 627 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74024,13 +74236,13 @@ exports.read = read; /***/ }), -/* 628 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(629); +const fs = __webpack_require__(631); class Settings { constructor(_options = {}) { this._options = _options; @@ -74047,7 +74259,7 @@ exports.default = Settings; /***/ }), -/* 629 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74070,16 +74282,16 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 630 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(631); -const stream_1 = __webpack_require__(646); -const sync_1 = __webpack_require__(647); -const settings_1 = __webpack_require__(649); +const async_1 = __webpack_require__(633); +const stream_1 = __webpack_require__(648); +const sync_1 = __webpack_require__(649); +const settings_1 = __webpack_require__(651); exports.Settings = settings_1.default; function walk(dir, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -74109,13 +74321,13 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 631 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(632); +const async_1 = __webpack_require__(634); class AsyncProvider { constructor(_root, _settings) { this._root = _root; @@ -74146,17 +74358,17 @@ function callSuccessCallback(callback, entries) { /***/ }), -/* 632 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __webpack_require__(379); -const fsScandir = __webpack_require__(633); -const fastq = __webpack_require__(642); -const common = __webpack_require__(644); -const reader_1 = __webpack_require__(645); +const fsScandir = __webpack_require__(635); +const fastq = __webpack_require__(644); +const common = __webpack_require__(646); +const reader_1 = __webpack_require__(647); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); @@ -74246,15 +74458,15 @@ exports.default = AsyncReader; /***/ }), -/* 633 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(634); -const sync = __webpack_require__(639); -const settings_1 = __webpack_require__(640); +const async = __webpack_require__(636); +const sync = __webpack_require__(641); +const settings_1 = __webpack_require__(642); exports.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { @@ -74277,16 +74489,16 @@ function getSettings(settingsOrOptions = {}) { /***/ }), -/* 634 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(625); -const rpl = __webpack_require__(635); -const constants_1 = __webpack_require__(636); -const utils = __webpack_require__(637); +const fsStat = __webpack_require__(627); +const rpl = __webpack_require__(637); +const constants_1 = __webpack_require__(638); +const utils = __webpack_require__(639); function read(dir, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(dir, settings, callback); @@ -74375,7 +74587,7 @@ function callSuccessCallback(callback, result) { /***/ }), -/* 635 */ +/* 637 */ /***/ (function(module, exports) { module.exports = runParallel @@ -74429,7 +74641,7 @@ function runParallel (tasks, cb) { /***/ }), -/* 636 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74445,18 +74657,18 @@ exports.IS_SUPPORT_READDIR_WITH_FILE_TYPES = MAJOR_VERSION > 10 || (MAJOR_VERSIO /***/ }), -/* 637 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(638); +const fs = __webpack_require__(640); exports.fs = fs; /***/ }), -/* 638 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74481,15 +74693,15 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 639 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(625); -const constants_1 = __webpack_require__(636); -const utils = __webpack_require__(637); +const fsStat = __webpack_require__(627); +const constants_1 = __webpack_require__(638); +const utils = __webpack_require__(639); function read(dir, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(dir, settings); @@ -74540,15 +74752,15 @@ exports.readdir = readdir; /***/ }), -/* 640 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(625); -const fs = __webpack_require__(641); +const fsStat = __webpack_require__(627); +const fs = __webpack_require__(643); class Settings { constructor(_options = {}) { this._options = _options; @@ -74571,7 +74783,7 @@ exports.default = Settings; /***/ }), -/* 641 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74596,13 +74808,13 @@ exports.createFileSystemAdapter = createFileSystemAdapter; /***/ }), -/* 642 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var reusify = __webpack_require__(643) +var reusify = __webpack_require__(645) function fastqueue (context, worker, concurrency) { if (typeof context === 'function') { @@ -74776,7 +74988,7 @@ module.exports = fastqueue /***/ }), -/* 643 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74816,7 +75028,7 @@ module.exports = reusify /***/ }), -/* 644 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74847,13 +75059,13 @@ exports.joinPathSegments = joinPathSegments; /***/ }), -/* 645 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(644); +const common = __webpack_require__(646); class Reader { constructor(_root, _settings) { this._root = _root; @@ -74865,14 +75077,14 @@ exports.default = Reader; /***/ }), -/* 646 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const async_1 = __webpack_require__(632); +const async_1 = __webpack_require__(634); class StreamProvider { constructor(_root, _settings) { this._root = _root; @@ -74902,13 +75114,13 @@ exports.default = StreamProvider; /***/ }), -/* 647 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(648); +const sync_1 = __webpack_require__(650); class SyncProvider { constructor(_root, _settings) { this._root = _root; @@ -74923,15 +75135,15 @@ exports.default = SyncProvider; /***/ }), -/* 648 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(633); -const common = __webpack_require__(644); -const reader_1 = __webpack_require__(645); +const fsScandir = __webpack_require__(635); +const common = __webpack_require__(646); +const reader_1 = __webpack_require__(647); class SyncReader extends reader_1.default { constructor() { super(...arguments); @@ -74989,14 +75201,14 @@ exports.default = SyncReader; /***/ }), -/* 649 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsScandir = __webpack_require__(633); +const fsScandir = __webpack_require__(635); class Settings { constructor(_options = {}) { this._options = _options; @@ -75022,15 +75234,15 @@ exports.default = Settings; /***/ }), -/* 650 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const fsStat = __webpack_require__(625); -const utils = __webpack_require__(596); +const fsStat = __webpack_require__(627); +const utils = __webpack_require__(598); class Reader { constructor(_settings) { this._settings = _settings; @@ -75062,17 +75274,17 @@ exports.default = Reader; /***/ }), -/* 651 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(16); -const deep_1 = __webpack_require__(652); -const entry_1 = __webpack_require__(653); -const error_1 = __webpack_require__(654); -const entry_2 = __webpack_require__(655); +const deep_1 = __webpack_require__(654); +const entry_1 = __webpack_require__(655); +const error_1 = __webpack_require__(656); +const entry_2 = __webpack_require__(657); class Provider { constructor(_settings) { this._settings = _settings; @@ -75117,13 +75329,13 @@ exports.default = Provider; /***/ }), -/* 652 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(596); +const utils = __webpack_require__(598); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -75183,13 +75395,13 @@ exports.default = DeepFilter; /***/ }), -/* 653 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(596); +const utils = __webpack_require__(598); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -75244,13 +75456,13 @@ exports.default = EntryFilter; /***/ }), -/* 654 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(596); +const utils = __webpack_require__(598); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -75266,13 +75478,13 @@ exports.default = ErrorFilter; /***/ }), -/* 655 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(596); +const utils = __webpack_require__(598); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -75299,15 +75511,15 @@ exports.default = EntryTransformer; /***/ }), -/* 656 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(27); -const stream_2 = __webpack_require__(624); -const provider_1 = __webpack_require__(651); +const stream_2 = __webpack_require__(626); +const provider_1 = __webpack_require__(653); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -75335,14 +75547,14 @@ exports.default = ProviderStream; /***/ }), -/* 657 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(658); -const provider_1 = __webpack_require__(651); +const sync_1 = __webpack_require__(660); +const provider_1 = __webpack_require__(653); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -75365,15 +75577,15 @@ exports.default = ProviderSync; /***/ }), -/* 658 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(625); -const fsWalk = __webpack_require__(630); -const reader_1 = __webpack_require__(650); +const fsStat = __webpack_require__(627); +const fsWalk = __webpack_require__(632); +const reader_1 = __webpack_require__(652); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -75415,7 +75627,7 @@ exports.default = ReaderSync; /***/ }), -/* 659 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75475,13 +75687,13 @@ exports.default = Settings; /***/ }), -/* 660 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(661); +const pathType = __webpack_require__(663); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -75557,7 +75769,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 661 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75607,7 +75819,7 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 662 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75615,9 +75827,9 @@ exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); const {promisify} = __webpack_require__(29); const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(594); -const gitIgnore = __webpack_require__(663); -const slash = __webpack_require__(664); +const fastGlob = __webpack_require__(596); +const gitIgnore = __webpack_require__(665); +const slash = __webpack_require__(666); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -75731,7 +75943,7 @@ module.exports.sync = options => { /***/ }), -/* 663 */ +/* 665 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -76322,7 +76534,7 @@ if ( /***/ }), -/* 664 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76340,7 +76552,7 @@ module.exports = path => { /***/ }), -/* 665 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76393,7 +76605,7 @@ module.exports = { /***/ }), -/* 666 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76415,7 +76627,7 @@ module.exports = path_ => { /***/ }), -/* 667 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76443,7 +76655,7 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 668 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { const assert = __webpack_require__(30) @@ -76451,7 +76663,7 @@ const path = __webpack_require__(16) const fs = __webpack_require__(23) let glob = undefined try { - glob = __webpack_require__(589) + glob = __webpack_require__(591) } catch (_err) { // treat glob as optional. } @@ -76817,12 +77029,12 @@ rimraf.sync = rimrafSync /***/ }), -/* 669 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(670); +const AggregateError = __webpack_require__(672); module.exports = async ( iterable, @@ -76905,13 +77117,13 @@ module.exports = async ( /***/ }), -/* 670 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(671); -const cleanStack = __webpack_require__(672); +const indentString = __webpack_require__(673); +const cleanStack = __webpack_require__(674); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -76959,7 +77171,7 @@ module.exports = AggregateError; /***/ }), -/* 671 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77001,7 +77213,7 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 672 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77048,15 +77260,15 @@ module.exports = (stack, options) => { /***/ }), -/* 673 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(674); -const cliCursor = __webpack_require__(678); -const cliSpinners = __webpack_require__(682); -const logSymbols = __webpack_require__(563); +const chalk = __webpack_require__(676); +const cliCursor = __webpack_require__(680); +const cliSpinners = __webpack_require__(684); +const logSymbols = __webpack_require__(565); class Ora { constructor(options) { @@ -77203,16 +77415,16 @@ module.exports.promise = (action, options) => { /***/ }), -/* 674 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(675); -const stdoutColor = __webpack_require__(676).stdout; +const ansiStyles = __webpack_require__(677); +const stdoutColor = __webpack_require__(678).stdout; -const template = __webpack_require__(677); +const template = __webpack_require__(679); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -77438,7 +77650,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 675 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77611,7 +77823,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 676 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77753,7 +77965,7 @@ module.exports = { /***/ }), -/* 677 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77888,12 +78100,12 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 678 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(679); +const restoreCursor = __webpack_require__(681); let hidden = false; @@ -77934,12 +78146,12 @@ exports.toggle = (force, stream) => { /***/ }), -/* 679 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(680); +const onetime = __webpack_require__(682); const signalExit = __webpack_require__(377); module.exports = onetime(() => { @@ -77950,12 +78162,12 @@ module.exports = onetime(() => { /***/ }), -/* 680 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(681); +const mimicFn = __webpack_require__(683); module.exports = (fn, opts) => { // TODO: Remove this in v3 @@ -77996,7 +78208,7 @@ module.exports = (fn, opts) => { /***/ }), -/* 681 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78012,22 +78224,22 @@ module.exports = (to, from) => { /***/ }), -/* 682 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(683); +module.exports = __webpack_require__(685); /***/ }), -/* 683 */ +/* 685 */ /***/ (function(module) { module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 684 */ +/* 686 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78036,8 +78248,8 @@ __webpack_require__.r(__webpack_exports__); /* 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 _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(499); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(502); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -78087,7 +78299,7 @@ const RunCommand = { }; /***/ }), -/* 685 */ +/* 687 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78096,9 +78308,9 @@ __webpack_require__.r(__webpack_exports__); /* 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 _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(34); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(499); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(686); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(501); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(502); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(688); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -78182,7 +78394,7 @@ const WatchCommand = { }; /***/ }), -/* 686 */ +/* 688 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78256,7 +78468,7 @@ function waitUntilWatchIsReady(stream, opts = {}) { } /***/ }), -/* 687 */ +/* 689 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78264,15 +78476,15 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); /* 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 indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(688); +/* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(690); /* harmony import */ var indent_string__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(indent_string__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(689); +/* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(691); /* harmony import */ var wrap_ansi__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(wrap_ansi__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(514); +/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(516); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(34); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(500); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(696); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(697); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(502); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(698); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(699); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -78360,7 +78572,7 @@ function toArray(value) { } /***/ }), -/* 688 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78394,13 +78606,13 @@ module.exports = (str, count, opts) => { /***/ }), -/* 689 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringWidth = __webpack_require__(690); -const stripAnsi = __webpack_require__(694); +const stringWidth = __webpack_require__(692); +const stripAnsi = __webpack_require__(696); const ESCAPES = new Set([ '\u001B', @@ -78594,13 +78806,13 @@ module.exports = (str, cols, opts) => { /***/ }), -/* 690 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stripAnsi = __webpack_require__(691); -const isFullwidthCodePoint = __webpack_require__(693); +const stripAnsi = __webpack_require__(693); +const isFullwidthCodePoint = __webpack_require__(695); module.exports = str => { if (typeof str !== 'string' || str.length === 0) { @@ -78637,18 +78849,18 @@ module.exports = str => { /***/ }), -/* 691 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(692); +const ansiRegex = __webpack_require__(694); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 692 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78665,7 +78877,7 @@ module.exports = () => { /***/ }), -/* 693 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78718,18 +78930,18 @@ module.exports = x => { /***/ }), -/* 694 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(695); +const ansiRegex = __webpack_require__(697); module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 695 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78746,7 +78958,7 @@ module.exports = () => { /***/ }), -/* 696 */ +/* 698 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78899,7 +79111,7 @@ function addProjectToTree(tree, pathParts, project) { } /***/ }), -/* 697 */ +/* 699 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -78907,12 +79119,12 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Kibana", function() { return Kibana; }); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(16); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(698); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(700); /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(702); +/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(704); /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(500); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(577); +/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(502); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(579); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -79053,15 +79265,15 @@ class Kibana { } /***/ }), -/* 698 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const minimatch = __webpack_require__(504); -const arrayUnion = __webpack_require__(699); -const arrayDiffer = __webpack_require__(700); -const arrify = __webpack_require__(701); +const minimatch = __webpack_require__(506); +const arrayUnion = __webpack_require__(701); +const arrayDiffer = __webpack_require__(702); +const arrify = __webpack_require__(703); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -79085,7 +79297,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 699 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79097,7 +79309,7 @@ module.exports = (...arguments_) => { /***/ }), -/* 700 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79112,7 +79324,7 @@ module.exports = arrayDiffer; /***/ }), -/* 701 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79142,7 +79354,7 @@ module.exports = arrify; /***/ }), -/* 702 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79170,15 +79382,15 @@ module.exports = (childPath, parentPath) => { /***/ }), -/* 703 */ +/* 705 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(704); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(706); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(939); +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(941); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); /* @@ -79203,23 +79415,23 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 704 */ +/* 706 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(705); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(707); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(585); +/* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(587); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__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 _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(577); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(579); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(20); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(34); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(516); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(500); +/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(518); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(502); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -79351,7 +79563,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { } /***/ }), -/* 705 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79359,13 +79571,13 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(379); const path = __webpack_require__(16); const os = __webpack_require__(11); -const pAll = __webpack_require__(706); -const arrify = __webpack_require__(708); -const globby = __webpack_require__(709); -const isGlob = __webpack_require__(603); -const cpFile = __webpack_require__(924); -const junk = __webpack_require__(936); -const CpyError = __webpack_require__(937); +const pAll = __webpack_require__(708); +const arrify = __webpack_require__(710); +const globby = __webpack_require__(711); +const isGlob = __webpack_require__(605); +const cpFile = __webpack_require__(926); +const junk = __webpack_require__(938); +const CpyError = __webpack_require__(939); const defaultOptions = { ignoreJunk: true @@ -79484,12 +79696,12 @@ module.exports = (source, destination, { /***/ }), -/* 706 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(707); +const pMap = __webpack_require__(709); module.exports = (iterable, options) => pMap(iterable, element => element(), options); // TODO: Remove this for the next major release @@ -79497,7 +79709,7 @@ module.exports.default = module.exports; /***/ }), -/* 707 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79576,7 +79788,7 @@ module.exports.default = pMap; /***/ }), -/* 708 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79606,17 +79818,17 @@ module.exports = arrify; /***/ }), -/* 709 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(710); -const glob = __webpack_require__(712); -const fastGlob = __webpack_require__(717); -const dirGlob = __webpack_require__(917); -const gitignore = __webpack_require__(920); +const arrayUnion = __webpack_require__(712); +const glob = __webpack_require__(714); +const fastGlob = __webpack_require__(719); +const dirGlob = __webpack_require__(919); +const gitignore = __webpack_require__(922); const DEFAULT_FILTER = () => false; @@ -79761,12 +79973,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 710 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(711); +var arrayUniq = __webpack_require__(713); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -79774,7 +79986,7 @@ module.exports = function () { /***/ }), -/* 711 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79843,7 +80055,7 @@ if ('Set' in global) { /***/ }), -/* 712 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { // Approach: @@ -79889,21 +80101,21 @@ if ('Set' in global) { module.exports = glob var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(713) +var inherits = __webpack_require__(715) var EE = __webpack_require__(379).EventEmitter var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var globSync = __webpack_require__(715) -var common = __webpack_require__(716) +var isAbsolute = __webpack_require__(512) +var globSync = __webpack_require__(717) +var common = __webpack_require__(718) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts var ownProp = common.ownProp -var inflight = __webpack_require__(513) +var inflight = __webpack_require__(515) var util = __webpack_require__(29) var childrenIgnored = common.childrenIgnored var isIgnored = common.isIgnored @@ -80639,7 +80851,7 @@ Glob.prototype._stat2 = function (f, abs, er, stat, cb) { /***/ }), -/* 713 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -80649,12 +80861,12 @@ try { module.exports = util.inherits; } catch (e) { /* istanbul ignore next */ - module.exports = __webpack_require__(714); + module.exports = __webpack_require__(716); } /***/ }), -/* 714 */ +/* 716 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -80687,22 +80899,22 @@ if (typeof Object.create === 'function') { /***/ }), -/* 715 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { module.exports = globSync globSync.GlobSync = GlobSync var fs = __webpack_require__(23) -var rp = __webpack_require__(502) -var minimatch = __webpack_require__(504) +var rp = __webpack_require__(504) +var minimatch = __webpack_require__(506) var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(712).Glob +var Glob = __webpack_require__(714).Glob var util = __webpack_require__(29) var path = __webpack_require__(16) var assert = __webpack_require__(30) -var isAbsolute = __webpack_require__(510) -var common = __webpack_require__(716) +var isAbsolute = __webpack_require__(512) +var common = __webpack_require__(718) var alphasort = common.alphasort var alphasorti = common.alphasorti var setopts = common.setopts @@ -81179,7 +81391,7 @@ GlobSync.prototype._makeAbs = function (f) { /***/ }), -/* 716 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { exports.alphasort = alphasort @@ -81197,8 +81409,8 @@ function ownProp (obj, field) { } var path = __webpack_require__(16) -var minimatch = __webpack_require__(504) -var isAbsolute = __webpack_require__(510) +var minimatch = __webpack_require__(506) +var isAbsolute = __webpack_require__(512) var Minimatch = minimatch.Minimatch function alphasorti (a, b) { @@ -81425,10 +81637,10 @@ function childrenIgnored (self, path) { /***/ }), -/* 717 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(718); +const pkg = __webpack_require__(720); module.exports = pkg.async; module.exports.default = pkg.async; @@ -81441,19 +81653,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 718 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(719); -var taskManager = __webpack_require__(720); -var reader_async_1 = __webpack_require__(888); -var reader_stream_1 = __webpack_require__(912); -var reader_sync_1 = __webpack_require__(913); -var arrayUtils = __webpack_require__(915); -var streamUtils = __webpack_require__(916); +var optionsManager = __webpack_require__(721); +var taskManager = __webpack_require__(722); +var reader_async_1 = __webpack_require__(890); +var reader_stream_1 = __webpack_require__(914); +var reader_sync_1 = __webpack_require__(915); +var arrayUtils = __webpack_require__(917); +var streamUtils = __webpack_require__(918); /** * Synchronous API. */ @@ -81519,7 +81731,7 @@ function isString(source) { /***/ }), -/* 719 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81557,13 +81769,13 @@ exports.prepare = prepare; /***/ }), -/* 720 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(721); +var patternUtils = __webpack_require__(723); /** * Generate tasks based on parent directory of each pattern. */ @@ -81654,16 +81866,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 721 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var globParent = __webpack_require__(722); -var isGlob = __webpack_require__(725); -var micromatch = __webpack_require__(726); +var globParent = __webpack_require__(724); +var isGlob = __webpack_require__(727); +var micromatch = __webpack_require__(728); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -81809,15 +82021,15 @@ exports.matchAny = matchAny; /***/ }), -/* 722 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(723); -var pathDirname = __webpack_require__(724); +var isglob = __webpack_require__(725); +var pathDirname = __webpack_require__(726); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -81840,7 +82052,7 @@ module.exports = function globParent(str) { /***/ }), -/* 723 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -81850,7 +82062,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(604); +var isExtglob = __webpack_require__(606); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -81871,7 +82083,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 724 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82021,7 +82233,7 @@ module.exports.win32 = win32; /***/ }), -/* 725 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -82031,7 +82243,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(604); +var isExtglob = __webpack_require__(606); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -82073,7 +82285,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 726 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82084,18 +82296,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(29); -var braces = __webpack_require__(727); -var toRegex = __webpack_require__(840); -var extend = __webpack_require__(848); +var braces = __webpack_require__(729); +var toRegex = __webpack_require__(842); +var extend = __webpack_require__(850); /** * Local dependencies */ -var compilers = __webpack_require__(851); -var parsers = __webpack_require__(884); -var cache = __webpack_require__(885); -var utils = __webpack_require__(886); +var compilers = __webpack_require__(853); +var parsers = __webpack_require__(886); +var cache = __webpack_require__(887); +var utils = __webpack_require__(888); var MAX_LENGTH = 1024 * 64; /** @@ -82957,7 +83169,7 @@ module.exports = micromatch; /***/ }), -/* 727 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82967,18 +83179,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(728); -var unique = __webpack_require__(742); -var extend = __webpack_require__(737); +var toRegex = __webpack_require__(730); +var unique = __webpack_require__(744); +var extend = __webpack_require__(739); /** * Local dependencies */ -var compilers = __webpack_require__(743); -var parsers = __webpack_require__(760); -var Braces = __webpack_require__(770); -var utils = __webpack_require__(744); +var compilers = __webpack_require__(745); +var parsers = __webpack_require__(762); +var Braces = __webpack_require__(772); +var utils = __webpack_require__(746); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -83282,15 +83494,15 @@ module.exports = braces; /***/ }), -/* 728 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(729); -var extend = __webpack_require__(737); -var not = __webpack_require__(739); +var define = __webpack_require__(731); +var extend = __webpack_require__(739); +var not = __webpack_require__(741); var MAX_LENGTH = 1024 * 64; /** @@ -83437,7 +83649,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 729 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83450,7 +83662,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(730); +var isDescriptor = __webpack_require__(732); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -83475,7 +83687,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 730 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83488,9 +83700,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(731); -var isAccessor = __webpack_require__(732); -var isData = __webpack_require__(735); +var typeOf = __webpack_require__(733); +var isAccessor = __webpack_require__(734); +var isData = __webpack_require__(737); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -83504,7 +83716,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 731 */ +/* 733 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -83657,7 +83869,7 @@ function isBuffer(val) { /***/ }), -/* 732 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83670,7 +83882,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(733); +var typeOf = __webpack_require__(735); // accessor descriptor properties var accessor = { @@ -83733,10 +83945,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 733 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -83855,7 +84067,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 734 */ +/* 736 */ /***/ (function(module, exports) { /*! @@ -83882,7 +84094,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 735 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83895,7 +84107,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(736); +var typeOf = __webpack_require__(738); // data descriptor properties var data = { @@ -83944,10 +84156,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 736 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -84066,13 +84278,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 737 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(738); +var isObject = __webpack_require__(740); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -84106,7 +84318,7 @@ function hasOwn(obj, key) { /***/ }), -/* 738 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84126,13 +84338,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 739 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(740); +var extend = __webpack_require__(742); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -84199,13 +84411,13 @@ module.exports = toRegex; /***/ }), -/* 740 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(741); +var isObject = __webpack_require__(743); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -84239,7 +84451,7 @@ function hasOwn(obj, key) { /***/ }), -/* 741 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84259,7 +84471,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 742 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84309,13 +84521,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 743 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(744); +var utils = __webpack_require__(746); module.exports = function(braces, options) { braces.compiler @@ -84598,25 +84810,25 @@ function hasQueue(node) { /***/ }), -/* 744 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(745); +var splitString = __webpack_require__(747); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(737); -utils.flatten = __webpack_require__(751); -utils.isObject = __webpack_require__(749); -utils.fillRange = __webpack_require__(752); -utils.repeat = __webpack_require__(759); -utils.unique = __webpack_require__(742); +utils.extend = __webpack_require__(739); +utils.flatten = __webpack_require__(753); +utils.isObject = __webpack_require__(751); +utils.fillRange = __webpack_require__(754); +utils.repeat = __webpack_require__(761); +utils.unique = __webpack_require__(744); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -84948,7 +85160,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 745 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84961,7 +85173,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(746); +var extend = __webpack_require__(748); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -85126,14 +85338,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 746 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(747); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(749); +var assignSymbols = __webpack_require__(752); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -85193,7 +85405,7 @@ function isEnum(obj, key) { /***/ }), -/* 747 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85206,7 +85418,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(750); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -85214,7 +85426,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 748 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85227,7 +85439,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(751); function isObjectObject(o) { return isObject(o) === true @@ -85258,7 +85470,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 749 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85277,7 +85489,7 @@ module.exports = function isObject(val) { /***/ }), -/* 750 */ +/* 752 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85324,7 +85536,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 751 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85353,7 +85565,7 @@ function flat(arr, res) { /***/ }), -/* 752 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85367,10 +85579,10 @@ function flat(arr, res) { var util = __webpack_require__(29); -var isNumber = __webpack_require__(753); -var extend = __webpack_require__(755); -var repeat = __webpack_require__(757); -var toRegex = __webpack_require__(758); +var isNumber = __webpack_require__(755); +var extend = __webpack_require__(757); +var repeat = __webpack_require__(759); +var toRegex = __webpack_require__(760); /** * Return a range of numbers or letters. @@ -85568,7 +85780,7 @@ module.exports = fillRange; /***/ }), -/* 753 */ +/* 755 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85581,7 +85793,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(756); module.exports = function isNumber(num) { var type = typeOf(num); @@ -85597,10 +85809,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 754 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -85719,13 +85931,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 755 */ +/* 757 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(756); +var isObject = __webpack_require__(758); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -85759,7 +85971,7 @@ function hasOwn(obj, key) { /***/ }), -/* 756 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85779,7 +85991,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 757 */ +/* 759 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85856,7 +86068,7 @@ function repeat(str, num) { /***/ }), -/* 758 */ +/* 760 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85869,8 +86081,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(757); -var isNumber = __webpack_require__(753); +var repeat = __webpack_require__(759); +var isNumber = __webpack_require__(755); var cache = {}; function toRegexRange(min, max, options) { @@ -86157,7 +86369,7 @@ module.exports = toRegexRange; /***/ }), -/* 759 */ +/* 761 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86182,14 +86394,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 760 */ +/* 762 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(761); -var utils = __webpack_require__(744); +var Node = __webpack_require__(763); +var utils = __webpack_require__(746); /** * Braces parsers @@ -86549,15 +86761,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 761 */ +/* 763 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(749); -var define = __webpack_require__(762); -var utils = __webpack_require__(769); +var isObject = __webpack_require__(751); +var define = __webpack_require__(764); +var utils = __webpack_require__(771); var ownNames; /** @@ -87048,7 +87260,7 @@ exports = module.exports = Node; /***/ }), -/* 762 */ +/* 764 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87061,7 +87273,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(763); +var isDescriptor = __webpack_require__(765); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -87086,7 +87298,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 763 */ +/* 765 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87099,9 +87311,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(764); -var isAccessor = __webpack_require__(765); -var isData = __webpack_require__(767); +var typeOf = __webpack_require__(766); +var isAccessor = __webpack_require__(767); +var isData = __webpack_require__(769); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -87115,7 +87327,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 764 */ +/* 766 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -87250,7 +87462,7 @@ function isBuffer(val) { /***/ }), -/* 765 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87263,7 +87475,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(766); +var typeOf = __webpack_require__(768); // accessor descriptor properties var accessor = { @@ -87326,7 +87538,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 766 */ +/* 768 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -87461,7 +87673,7 @@ function isBuffer(val) { /***/ }), -/* 767 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87474,7 +87686,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(768); +var typeOf = __webpack_require__(770); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -87517,7 +87729,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 768 */ +/* 770 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -87652,13 +87864,13 @@ function isBuffer(val) { /***/ }), -/* 769 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(756); var utils = module.exports; /** @@ -88678,17 +88890,17 @@ function assert(val, message) { /***/ }), -/* 770 */ +/* 772 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(737); -var Snapdragon = __webpack_require__(771); -var compilers = __webpack_require__(743); -var parsers = __webpack_require__(760); -var utils = __webpack_require__(744); +var extend = __webpack_require__(739); +var Snapdragon = __webpack_require__(773); +var compilers = __webpack_require__(745); +var parsers = __webpack_require__(762); +var utils = __webpack_require__(746); /** * Customize Snapdragon parser and renderer @@ -88789,17 +89001,17 @@ module.exports = Braces; /***/ }), -/* 771 */ +/* 773 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(772); -var define = __webpack_require__(798); -var Compiler = __webpack_require__(808); -var Parser = __webpack_require__(837); -var utils = __webpack_require__(817); +var Base = __webpack_require__(774); +var define = __webpack_require__(800); +var Compiler = __webpack_require__(810); +var Parser = __webpack_require__(839); +var utils = __webpack_require__(819); var regexCache = {}; var cache = {}; @@ -88970,20 +89182,20 @@ module.exports.Parser = Parser; /***/ }), -/* 772 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var define = __webpack_require__(773); -var CacheBase = __webpack_require__(774); -var Emitter = __webpack_require__(775); -var isObject = __webpack_require__(749); -var merge = __webpack_require__(792); -var pascal = __webpack_require__(795); -var cu = __webpack_require__(796); +var define = __webpack_require__(775); +var CacheBase = __webpack_require__(776); +var Emitter = __webpack_require__(777); +var isObject = __webpack_require__(751); +var merge = __webpack_require__(794); +var pascal = __webpack_require__(797); +var cu = __webpack_require__(798); /** * Optionally define a custom `cache` namespace to use. @@ -89412,7 +89624,7 @@ module.exports.namespace = namespace; /***/ }), -/* 773 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89425,7 +89637,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(763); +var isDescriptor = __webpack_require__(765); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -89450,21 +89662,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 774 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(749); -var Emitter = __webpack_require__(775); -var visit = __webpack_require__(776); -var toPath = __webpack_require__(779); -var union = __webpack_require__(780); -var del = __webpack_require__(784); -var get = __webpack_require__(782); -var has = __webpack_require__(789); -var set = __webpack_require__(783); +var isObject = __webpack_require__(751); +var Emitter = __webpack_require__(777); +var visit = __webpack_require__(778); +var toPath = __webpack_require__(781); +var union = __webpack_require__(782); +var del = __webpack_require__(786); +var get = __webpack_require__(784); +var has = __webpack_require__(791); +var set = __webpack_require__(785); /** * Create a `Cache` constructor that when instantiated will @@ -89718,7 +89930,7 @@ module.exports.namespace = namespace; /***/ }), -/* 775 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { @@ -89887,7 +90099,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 776 */ +/* 778 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89900,8 +90112,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(777); -var mapVisit = __webpack_require__(778); +var visit = __webpack_require__(779); +var mapVisit = __webpack_require__(780); module.exports = function(collection, method, val) { var result; @@ -89924,7 +90136,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 777 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89937,7 +90149,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(751); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -89964,14 +90176,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 778 */ +/* 780 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var visit = __webpack_require__(777); +var visit = __webpack_require__(779); /** * Map `visit` over an array of objects. @@ -90008,7 +90220,7 @@ function isObject(val) { /***/ }), -/* 779 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90021,7 +90233,7 @@ function isObject(val) { -var typeOf = __webpack_require__(754); +var typeOf = __webpack_require__(756); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -90048,16 +90260,16 @@ function filter(arr) { /***/ }), -/* 780 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(741); -var union = __webpack_require__(781); -var get = __webpack_require__(782); -var set = __webpack_require__(783); +var isObject = __webpack_require__(743); +var union = __webpack_require__(783); +var get = __webpack_require__(784); +var set = __webpack_require__(785); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -90085,7 +90297,7 @@ function arrayify(val) { /***/ }), -/* 781 */ +/* 783 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90121,7 +90333,7 @@ module.exports = function union(init) { /***/ }), -/* 782 */ +/* 784 */ /***/ (function(module, exports) { /*! @@ -90177,7 +90389,7 @@ function toString(val) { /***/ }), -/* 783 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90190,10 +90402,10 @@ function toString(val) { -var split = __webpack_require__(745); -var extend = __webpack_require__(740); -var isPlainObject = __webpack_require__(748); -var isObject = __webpack_require__(741); +var split = __webpack_require__(747); +var extend = __webpack_require__(742); +var isPlainObject = __webpack_require__(750); +var isObject = __webpack_require__(743); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -90239,7 +90451,7 @@ function isValidKey(key) { /***/ }), -/* 784 */ +/* 786 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90252,8 +90464,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(749); -var has = __webpack_require__(785); +var isObject = __webpack_require__(751); +var has = __webpack_require__(787); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -90278,7 +90490,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 785 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90291,9 +90503,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(786); -var hasValues = __webpack_require__(788); -var get = __webpack_require__(782); +var isObject = __webpack_require__(788); +var hasValues = __webpack_require__(790); +var get = __webpack_require__(784); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -90304,7 +90516,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 786 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90317,7 +90529,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(787); +var isArray = __webpack_require__(789); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -90325,7 +90537,7 @@ module.exports = function isObject(val) { /***/ }), -/* 787 */ +/* 789 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -90336,7 +90548,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 788 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90379,7 +90591,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 789 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90392,9 +90604,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(749); -var hasValues = __webpack_require__(790); -var get = __webpack_require__(782); +var isObject = __webpack_require__(751); +var hasValues = __webpack_require__(792); +var get = __webpack_require__(784); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -90402,7 +90614,7 @@ module.exports = function(val, prop) { /***/ }), -/* 790 */ +/* 792 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90415,8 +90627,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(791); -var isNumber = __webpack_require__(753); +var typeOf = __webpack_require__(793); +var isNumber = __webpack_require__(755); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -90469,10 +90681,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 791 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -90594,14 +90806,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 792 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(793); -var forIn = __webpack_require__(794); +var isExtendable = __webpack_require__(795); +var forIn = __webpack_require__(796); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -90665,7 +90877,7 @@ module.exports = mixinDeep; /***/ }), -/* 793 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90678,7 +90890,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(750); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -90686,7 +90898,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 794 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90709,7 +90921,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 795 */ +/* 797 */ /***/ (function(module, exports) { /*! @@ -90736,14 +90948,14 @@ module.exports = pascalcase; /***/ }), -/* 796 */ +/* 798 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var utils = __webpack_require__(797); +var utils = __webpack_require__(799); /** * Expose class utils @@ -91108,7 +91320,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 797 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91122,10 +91334,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(781); -utils.define = __webpack_require__(798); -utils.isObj = __webpack_require__(749); -utils.staticExtend = __webpack_require__(805); +utils.union = __webpack_require__(783); +utils.define = __webpack_require__(800); +utils.isObj = __webpack_require__(751); +utils.staticExtend = __webpack_require__(807); /** @@ -91136,7 +91348,7 @@ module.exports = utils; /***/ }), -/* 798 */ +/* 800 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91149,7 +91361,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(799); +var isDescriptor = __webpack_require__(801); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -91174,7 +91386,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 799 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91187,9 +91399,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(800); -var isAccessor = __webpack_require__(801); -var isData = __webpack_require__(803); +var typeOf = __webpack_require__(802); +var isAccessor = __webpack_require__(803); +var isData = __webpack_require__(805); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -91203,7 +91415,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 800 */ +/* 802 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -91356,7 +91568,7 @@ function isBuffer(val) { /***/ }), -/* 801 */ +/* 803 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91369,7 +91581,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(802); +var typeOf = __webpack_require__(804); // accessor descriptor properties var accessor = { @@ -91432,10 +91644,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 802 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -91554,7 +91766,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 803 */ +/* 805 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91567,7 +91779,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(804); +var typeOf = __webpack_require__(806); // data descriptor properties var data = { @@ -91616,10 +91828,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 804 */ +/* 806 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -91738,7 +91950,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 805 */ +/* 807 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91751,8 +91963,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(806); -var define = __webpack_require__(798); +var copy = __webpack_require__(808); +var define = __webpack_require__(800); var util = __webpack_require__(29); /** @@ -91835,15 +92047,15 @@ module.exports = extend; /***/ }), -/* 806 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(754); -var copyDescriptor = __webpack_require__(807); -var define = __webpack_require__(798); +var typeOf = __webpack_require__(756); +var copyDescriptor = __webpack_require__(809); +var define = __webpack_require__(800); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -92016,7 +92228,7 @@ module.exports.has = has; /***/ }), -/* 807 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92104,16 +92316,16 @@ function isObject(val) { /***/ }), -/* 808 */ +/* 810 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(809); -var define = __webpack_require__(798); -var debug = __webpack_require__(811)('snapdragon:compiler'); -var utils = __webpack_require__(817); +var use = __webpack_require__(811); +var define = __webpack_require__(800); +var debug = __webpack_require__(813)('snapdragon:compiler'); +var utils = __webpack_require__(819); /** * Create a new `Compiler` with the given `options`. @@ -92267,7 +92479,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(836); + var sourcemaps = __webpack_require__(838); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -92288,7 +92500,7 @@ module.exports = Compiler; /***/ }), -/* 809 */ +/* 811 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92301,7 +92513,7 @@ module.exports = Compiler; -var utils = __webpack_require__(810); +var utils = __webpack_require__(812); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -92416,7 +92628,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 810 */ +/* 812 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92430,8 +92642,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(798); -utils.isObject = __webpack_require__(749); +utils.define = __webpack_require__(800); +utils.isObject = __webpack_require__(751); utils.isString = function(val) { @@ -92446,7 +92658,7 @@ module.exports = utils; /***/ }), -/* 811 */ +/* 813 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -92455,14 +92667,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(812); + module.exports = __webpack_require__(814); } else { - module.exports = __webpack_require__(815); + module.exports = __webpack_require__(817); } /***/ }), -/* 812 */ +/* 814 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -92471,7 +92683,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(813); +exports = module.exports = __webpack_require__(815); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -92653,7 +92865,7 @@ function localstorage() { /***/ }), -/* 813 */ +/* 815 */ /***/ (function(module, exports, __webpack_require__) { @@ -92669,7 +92881,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(814); +exports.humanize = __webpack_require__(816); /** * The currently active debug mode names, and names to skip. @@ -92861,7 +93073,7 @@ function coerce(val) { /***/ }), -/* 814 */ +/* 816 */ /***/ (function(module, exports) { /** @@ -93019,14 +93231,14 @@ function plural(ms, n, name) { /***/ }), -/* 815 */ +/* 817 */ /***/ (function(module, exports, __webpack_require__) { /** * Module dependencies. */ -var tty = __webpack_require__(478); +var tty = __webpack_require__(484); var util = __webpack_require__(29); /** @@ -93035,7 +93247,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(813); +exports = module.exports = __webpack_require__(815); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -93214,7 +93426,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(816); + var net = __webpack_require__(818); stream = new net.Socket({ fd: fd, readable: false, @@ -93273,13 +93485,13 @@ exports.enable(load()); /***/ }), -/* 816 */ +/* 818 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 817 */ +/* 819 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -93289,9 +93501,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(740); -exports.SourceMap = __webpack_require__(818); -exports.sourceMapResolve = __webpack_require__(829); +exports.extend = __webpack_require__(742); +exports.SourceMap = __webpack_require__(820); +exports.sourceMapResolve = __webpack_require__(831); /** * Convert backslash in the given string to forward slashes @@ -93334,7 +93546,7 @@ exports.last = function(arr, n) { /***/ }), -/* 818 */ +/* 820 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -93342,13 +93554,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(819).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(825).SourceMapConsumer; -exports.SourceNode = __webpack_require__(828).SourceNode; +exports.SourceMapGenerator = __webpack_require__(821).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(827).SourceMapConsumer; +exports.SourceNode = __webpack_require__(830).SourceNode; /***/ }), -/* 819 */ +/* 821 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -93358,10 +93570,10 @@ exports.SourceNode = __webpack_require__(828).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(820); -var util = __webpack_require__(822); -var ArraySet = __webpack_require__(823).ArraySet; -var MappingList = __webpack_require__(824).MappingList; +var base64VLQ = __webpack_require__(822); +var util = __webpack_require__(824); +var ArraySet = __webpack_require__(825).ArraySet; +var MappingList = __webpack_require__(826).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -93770,7 +93982,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 820 */ +/* 822 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -93810,7 +94022,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(821); +var base64 = __webpack_require__(823); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -93916,7 +94128,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 821 */ +/* 823 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -93989,7 +94201,7 @@ exports.decode = function (charCode) { /***/ }), -/* 822 */ +/* 824 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94412,7 +94624,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 823 */ +/* 825 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94422,7 +94634,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(822); +var util = __webpack_require__(824); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -94539,7 +94751,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 824 */ +/* 826 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94549,7 +94761,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(822); +var util = __webpack_require__(824); /** * Determine whether mappingB is after mappingA with respect to generated @@ -94624,7 +94836,7 @@ exports.MappingList = MappingList; /***/ }), -/* 825 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94634,11 +94846,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(822); -var binarySearch = __webpack_require__(826); -var ArraySet = __webpack_require__(823).ArraySet; -var base64VLQ = __webpack_require__(820); -var quickSort = __webpack_require__(827).quickSort; +var util = __webpack_require__(824); +var binarySearch = __webpack_require__(828); +var ArraySet = __webpack_require__(825).ArraySet; +var base64VLQ = __webpack_require__(822); +var quickSort = __webpack_require__(829).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -95712,7 +95924,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 826 */ +/* 828 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95829,7 +96041,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 827 */ +/* 829 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95949,7 +96161,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 828 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -95959,8 +96171,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(819).SourceMapGenerator; -var util = __webpack_require__(822); +var SourceMapGenerator = __webpack_require__(821).SourceMapGenerator; +var util = __webpack_require__(824); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -96368,17 +96580,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 829 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(830) -var resolveUrl = __webpack_require__(831) -var decodeUriComponent = __webpack_require__(832) -var urix = __webpack_require__(834) -var atob = __webpack_require__(835) +var sourceMappingURL = __webpack_require__(832) +var resolveUrl = __webpack_require__(833) +var decodeUriComponent = __webpack_require__(834) +var urix = __webpack_require__(836) +var atob = __webpack_require__(837) @@ -96676,7 +96888,7 @@ module.exports = { /***/ }), -/* 830 */ +/* 832 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -96739,7 +96951,7 @@ void (function(root, factory) { /***/ }), -/* 831 */ +/* 833 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -96757,13 +96969,13 @@ module.exports = resolveUrl /***/ }), -/* 832 */ +/* 834 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(833) +var decodeUriComponent = __webpack_require__(835) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -96774,7 +96986,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 833 */ +/* 835 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96875,7 +97087,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 834 */ +/* 836 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -96898,7 +97110,7 @@ module.exports = urix /***/ }), -/* 835 */ +/* 837 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96912,7 +97124,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 836 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96920,8 +97132,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(23); var path = __webpack_require__(16); -var define = __webpack_require__(798); -var utils = __webpack_require__(817); +var define = __webpack_require__(800); +var utils = __webpack_require__(819); /** * Expose `mixin()`. @@ -97064,19 +97276,19 @@ exports.comment = function(node) { /***/ }), -/* 837 */ +/* 839 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(809); +var use = __webpack_require__(811); var util = __webpack_require__(29); -var Cache = __webpack_require__(838); -var define = __webpack_require__(798); -var debug = __webpack_require__(811)('snapdragon:parser'); -var Position = __webpack_require__(839); -var utils = __webpack_require__(817); +var Cache = __webpack_require__(840); +var define = __webpack_require__(800); +var debug = __webpack_require__(813)('snapdragon:parser'); +var Position = __webpack_require__(841); +var utils = __webpack_require__(819); /** * Create a new `Parser` with the given `input` and `options`. @@ -97604,7 +97816,7 @@ module.exports = Parser; /***/ }), -/* 838 */ +/* 840 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97711,13 +97923,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 839 */ +/* 841 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(798); +var define = __webpack_require__(800); /** * Store position for a node @@ -97732,16 +97944,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 840 */ +/* 842 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(841); -var define = __webpack_require__(847); -var extend = __webpack_require__(848); -var not = __webpack_require__(850); +var safe = __webpack_require__(843); +var define = __webpack_require__(849); +var extend = __webpack_require__(850); +var not = __webpack_require__(852); var MAX_LENGTH = 1024 * 64; /** @@ -97894,10 +98106,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 841 */ +/* 843 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(842); +var parse = __webpack_require__(844); var types = parse.types; module.exports = function (re, opts) { @@ -97943,13 +98155,13 @@ function isRegExp (x) { /***/ }), -/* 842 */ +/* 844 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(843); -var types = __webpack_require__(844); -var sets = __webpack_require__(845); -var positions = __webpack_require__(846); +var util = __webpack_require__(845); +var types = __webpack_require__(846); +var sets = __webpack_require__(847); +var positions = __webpack_require__(848); module.exports = function(regexpStr) { @@ -98231,11 +98443,11 @@ module.exports.types = types; /***/ }), -/* 843 */ +/* 845 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(844); -var sets = __webpack_require__(845); +var types = __webpack_require__(846); +var sets = __webpack_require__(847); // All of these are private and only used by randexp. @@ -98348,7 +98560,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 844 */ +/* 846 */ /***/ (function(module, exports) { module.exports = { @@ -98364,10 +98576,10 @@ module.exports = { /***/ }), -/* 845 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(844); +var types = __webpack_require__(846); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -98452,10 +98664,10 @@ exports.anyChar = function() { /***/ }), -/* 846 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(844); +var types = __webpack_require__(846); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -98475,7 +98687,7 @@ exports.end = function() { /***/ }), -/* 847 */ +/* 849 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98488,8 +98700,8 @@ exports.end = function() { -var isobject = __webpack_require__(749); -var isDescriptor = __webpack_require__(763); +var isobject = __webpack_require__(751); +var isDescriptor = __webpack_require__(765); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -98520,14 +98732,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 848 */ +/* 850 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(849); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(851); +var assignSymbols = __webpack_require__(752); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -98587,7 +98799,7 @@ function isEnum(obj, key) { /***/ }), -/* 849 */ +/* 851 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98600,7 +98812,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(750); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -98608,14 +98820,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 850 */ +/* 852 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(848); -var safe = __webpack_require__(841); +var extend = __webpack_require__(850); +var safe = __webpack_require__(843); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -98687,14 +98899,14 @@ module.exports = toRegex; /***/ }), -/* 851 */ +/* 853 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(852); -var extglob = __webpack_require__(868); +var nanomatch = __webpack_require__(854); +var extglob = __webpack_require__(870); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -98771,7 +98983,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 852 */ +/* 854 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98782,17 +98994,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(853); -var extend = __webpack_require__(854); +var toRegex = __webpack_require__(855); +var extend = __webpack_require__(856); /** * Local dependencies */ -var compilers = __webpack_require__(856); -var parsers = __webpack_require__(857); -var cache = __webpack_require__(860); -var utils = __webpack_require__(862); +var compilers = __webpack_require__(858); +var parsers = __webpack_require__(859); +var cache = __webpack_require__(862); +var utils = __webpack_require__(864); var MAX_LENGTH = 1024 * 64; /** @@ -99616,15 +99828,15 @@ module.exports = nanomatch; /***/ }), -/* 853 */ +/* 855 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(798); -var extend = __webpack_require__(740); -var not = __webpack_require__(739); +var define = __webpack_require__(800); +var extend = __webpack_require__(742); +var not = __webpack_require__(741); var MAX_LENGTH = 1024 * 64; /** @@ -99771,14 +99983,14 @@ module.exports.makeRe = makeRe; /***/ }), -/* 854 */ +/* 856 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(855); -var assignSymbols = __webpack_require__(750); +var isExtendable = __webpack_require__(857); +var assignSymbols = __webpack_require__(752); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -99838,7 +100050,7 @@ function isEnum(obj, key) { /***/ }), -/* 855 */ +/* 857 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99851,7 +100063,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(748); +var isPlainObject = __webpack_require__(750); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -99859,7 +100071,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 856 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100205,15 +100417,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 857 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(739); -var toRegex = __webpack_require__(853); -var isOdd = __webpack_require__(858); +var regexNot = __webpack_require__(741); +var toRegex = __webpack_require__(855); +var isOdd = __webpack_require__(860); /** * Characters to use in negation regex (we want to "not" match @@ -100599,7 +100811,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 858 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100612,7 +100824,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(859); +var isNumber = __webpack_require__(861); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -100626,7 +100838,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 859 */ +/* 861 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100654,14 +100866,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 860 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(861))(); +module.exports = new (__webpack_require__(863))(); /***/ }), -/* 861 */ +/* 863 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100674,7 +100886,7 @@ module.exports = new (__webpack_require__(861))(); -var MapCache = __webpack_require__(838); +var MapCache = __webpack_require__(840); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -100796,7 +101008,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 862 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100809,14 +101021,14 @@ var path = __webpack_require__(16); * Module dependencies */ -var isWindows = __webpack_require__(863)(); -var Snapdragon = __webpack_require__(771); -utils.define = __webpack_require__(864); -utils.diff = __webpack_require__(865); -utils.extend = __webpack_require__(854); -utils.pick = __webpack_require__(866); -utils.typeOf = __webpack_require__(867); -utils.unique = __webpack_require__(742); +var isWindows = __webpack_require__(865)(); +var Snapdragon = __webpack_require__(773); +utils.define = __webpack_require__(866); +utils.diff = __webpack_require__(867); +utils.extend = __webpack_require__(856); +utils.pick = __webpack_require__(868); +utils.typeOf = __webpack_require__(869); +utils.unique = __webpack_require__(744); /** * Returns true if the given value is effectively an empty string @@ -101182,7 +101394,7 @@ utils.unixify = function(options) { /***/ }), -/* 863 */ +/* 865 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -101210,7 +101422,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 864 */ +/* 866 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101223,8 +101435,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(749); -var isDescriptor = __webpack_require__(763); +var isobject = __webpack_require__(751); +var isDescriptor = __webpack_require__(765); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -101255,7 +101467,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 865 */ +/* 867 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101309,7 +101521,7 @@ function diffArray(one, two) { /***/ }), -/* 866 */ +/* 868 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101322,7 +101534,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(749); +var isObject = __webpack_require__(751); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -101351,7 +101563,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 867 */ +/* 869 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -101486,7 +101698,7 @@ function isBuffer(val) { /***/ }), -/* 868 */ +/* 870 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101496,18 +101708,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(740); -var unique = __webpack_require__(742); -var toRegex = __webpack_require__(853); +var extend = __webpack_require__(742); +var unique = __webpack_require__(744); +var toRegex = __webpack_require__(855); /** * Local dependencies */ -var compilers = __webpack_require__(869); -var parsers = __webpack_require__(880); -var Extglob = __webpack_require__(883); -var utils = __webpack_require__(882); +var compilers = __webpack_require__(871); +var parsers = __webpack_require__(882); +var Extglob = __webpack_require__(885); +var utils = __webpack_require__(884); var MAX_LENGTH = 1024 * 64; /** @@ -101824,13 +102036,13 @@ module.exports = extglob; /***/ }), -/* 869 */ +/* 871 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(870); +var brackets = __webpack_require__(872); /** * Extglob compilers @@ -102000,7 +102212,7 @@ module.exports = function(extglob) { /***/ }), -/* 870 */ +/* 872 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102010,17 +102222,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(871); -var parsers = __webpack_require__(873); +var compilers = __webpack_require__(873); +var parsers = __webpack_require__(875); /** * Module dependencies */ -var debug = __webpack_require__(875)('expand-brackets'); -var extend = __webpack_require__(740); -var Snapdragon = __webpack_require__(771); -var toRegex = __webpack_require__(853); +var debug = __webpack_require__(877)('expand-brackets'); +var extend = __webpack_require__(742); +var Snapdragon = __webpack_require__(773); +var toRegex = __webpack_require__(855); /** * Parses the given POSIX character class `pattern` and returns a @@ -102218,13 +102430,13 @@ module.exports = brackets; /***/ }), -/* 871 */ +/* 873 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(872); +var posix = __webpack_require__(874); module.exports = function(brackets) { brackets.compiler @@ -102312,7 +102524,7 @@ module.exports = function(brackets) { /***/ }), -/* 872 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102341,14 +102553,14 @@ module.exports = { /***/ }), -/* 873 */ +/* 875 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(874); -var define = __webpack_require__(798); +var utils = __webpack_require__(876); +var define = __webpack_require__(800); /** * Text regex @@ -102567,14 +102779,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 874 */ +/* 876 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(853); -var regexNot = __webpack_require__(739); +var toRegex = __webpack_require__(855); +var regexNot = __webpack_require__(741); var cached; /** @@ -102608,7 +102820,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 875 */ +/* 877 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -102617,14 +102829,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(876); + module.exports = __webpack_require__(878); } else { - module.exports = __webpack_require__(879); + module.exports = __webpack_require__(881); } /***/ }), -/* 876 */ +/* 878 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -102633,7 +102845,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(877); +exports = module.exports = __webpack_require__(879); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -102815,7 +103027,7 @@ function localstorage() { /***/ }), -/* 877 */ +/* 879 */ /***/ (function(module, exports, __webpack_require__) { @@ -102831,7 +103043,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(878); +exports.humanize = __webpack_require__(880); /** * The currently active debug mode names, and names to skip. @@ -103023,7 +103235,7 @@ function coerce(val) { /***/ }), -/* 878 */ +/* 880 */ /***/ (function(module, exports) { /** @@ -103181,14 +103393,14 @@ function plural(ms, n, name) { /***/ }), -/* 879 */ +/* 881 */ /***/ (function(module, exports, __webpack_require__) { /** * Module dependencies. */ -var tty = __webpack_require__(478); +var tty = __webpack_require__(484); var util = __webpack_require__(29); /** @@ -103197,7 +103409,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(877); +exports = module.exports = __webpack_require__(879); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -103376,7 +103588,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(816); + var net = __webpack_require__(818); stream = new net.Socket({ fd: fd, readable: false, @@ -103435,15 +103647,15 @@ exports.enable(load()); /***/ }), -/* 880 */ +/* 882 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(870); -var define = __webpack_require__(881); -var utils = __webpack_require__(882); +var brackets = __webpack_require__(872); +var define = __webpack_require__(883); +var utils = __webpack_require__(884); /** * Characters to use in text regex (we want to "not" match @@ -103598,7 +103810,7 @@ module.exports = parsers; /***/ }), -/* 881 */ +/* 883 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103611,7 +103823,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(763); +var isDescriptor = __webpack_require__(765); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -103636,14 +103848,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 882 */ +/* 884 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(739); -var Cache = __webpack_require__(861); +var regex = __webpack_require__(741); +var Cache = __webpack_require__(863); /** * Utils @@ -103712,7 +103924,7 @@ utils.createRegex = function(str) { /***/ }), -/* 883 */ +/* 885 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103722,16 +103934,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(771); -var define = __webpack_require__(881); -var extend = __webpack_require__(740); +var Snapdragon = __webpack_require__(773); +var define = __webpack_require__(883); +var extend = __webpack_require__(742); /** * Local dependencies */ -var compilers = __webpack_require__(869); -var parsers = __webpack_require__(880); +var compilers = __webpack_require__(871); +var parsers = __webpack_require__(882); /** * Customize Snapdragon parser and renderer @@ -103797,16 +104009,16 @@ module.exports = Extglob; /***/ }), -/* 884 */ +/* 886 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(868); -var nanomatch = __webpack_require__(852); -var regexNot = __webpack_require__(739); -var toRegex = __webpack_require__(840); +var extglob = __webpack_require__(870); +var nanomatch = __webpack_require__(854); +var regexNot = __webpack_require__(741); +var toRegex = __webpack_require__(842); var not; /** @@ -103887,14 +104099,14 @@ function textRegex(pattern) { /***/ }), -/* 885 */ +/* 887 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(861))(); +module.exports = new (__webpack_require__(863))(); /***/ }), -/* 886 */ +/* 888 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103907,13 +104119,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(771); -utils.define = __webpack_require__(847); -utils.diff = __webpack_require__(865); -utils.extend = __webpack_require__(848); -utils.pick = __webpack_require__(866); -utils.typeOf = __webpack_require__(887); -utils.unique = __webpack_require__(742); +var Snapdragon = __webpack_require__(773); +utils.define = __webpack_require__(849); +utils.diff = __webpack_require__(867); +utils.extend = __webpack_require__(850); +utils.pick = __webpack_require__(868); +utils.typeOf = __webpack_require__(889); +utils.unique = __webpack_require__(744); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -104210,7 +104422,7 @@ utils.unixify = function(options) { /***/ }), -/* 887 */ +/* 889 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -104345,7 +104557,7 @@ function isBuffer(val) { /***/ }), -/* 888 */ +/* 890 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104364,9 +104576,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(889); -var reader_1 = __webpack_require__(902); -var fs_stream_1 = __webpack_require__(906); +var readdir = __webpack_require__(891); +var reader_1 = __webpack_require__(904); +var fs_stream_1 = __webpack_require__(908); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -104427,15 +104639,15 @@ exports.default = ReaderAsync; /***/ }), -/* 889 */ +/* 891 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(890); -const readdirAsync = __webpack_require__(898); -const readdirStream = __webpack_require__(901); +const readdirSync = __webpack_require__(892); +const readdirAsync = __webpack_require__(900); +const readdirStream = __webpack_require__(903); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -104519,7 +104731,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 890 */ +/* 892 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104527,11 +104739,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(891); +const DirectoryReader = __webpack_require__(893); let syncFacade = { - fs: __webpack_require__(896), - forEach: __webpack_require__(897), + fs: __webpack_require__(898), + forEach: __webpack_require__(899), sync: true }; @@ -104560,7 +104772,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 891 */ +/* 893 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104569,9 +104781,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(27).Readable; const EventEmitter = __webpack_require__(379).EventEmitter; const path = __webpack_require__(16); -const normalizeOptions = __webpack_require__(892); -const stat = __webpack_require__(894); -const call = __webpack_require__(895); +const normalizeOptions = __webpack_require__(894); +const stat = __webpack_require__(896); +const call = __webpack_require__(897); /** * Asynchronously reads the contents of a directory and streams the results @@ -104947,14 +105159,14 @@ module.exports = DirectoryReader; /***/ }), -/* 892 */ +/* 894 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(893); +const globToRegExp = __webpack_require__(895); module.exports = normalizeOptions; @@ -105131,7 +105343,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 893 */ +/* 895 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -105268,13 +105480,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 894 */ +/* 896 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(895); +const call = __webpack_require__(897); module.exports = stat; @@ -105349,7 +105561,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 895 */ +/* 897 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105410,14 +105622,14 @@ function callOnce (fn) { /***/ }), -/* 896 */ +/* 898 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(895); +const call = __webpack_require__(897); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -105481,7 +105693,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 897 */ +/* 899 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105510,7 +105722,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 898 */ +/* 900 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105518,12 +105730,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(899); -const DirectoryReader = __webpack_require__(891); +const maybe = __webpack_require__(901); +const DirectoryReader = __webpack_require__(893); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(900), + forEach: __webpack_require__(902), async: true }; @@ -105565,7 +105777,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 899 */ +/* 901 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105592,7 +105804,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 900 */ +/* 902 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105628,7 +105840,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 901 */ +/* 903 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105636,11 +105848,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(891); +const DirectoryReader = __webpack_require__(893); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(900), + forEach: __webpack_require__(902), async: true }; @@ -105660,16 +105872,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 902 */ +/* 904 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(903); -var entry_1 = __webpack_require__(905); -var pathUtil = __webpack_require__(904); +var deep_1 = __webpack_require__(905); +var entry_1 = __webpack_require__(907); +var pathUtil = __webpack_require__(906); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -105735,14 +105947,14 @@ exports.default = Reader; /***/ }), -/* 903 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(904); -var patternUtils = __webpack_require__(721); +var pathUtils = __webpack_require__(906); +var patternUtils = __webpack_require__(723); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -105825,7 +106037,7 @@ exports.default = DeepFilter; /***/ }), -/* 904 */ +/* 906 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105856,14 +106068,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 905 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(904); -var patternUtils = __webpack_require__(721); +var pathUtils = __webpack_require__(906); +var patternUtils = __webpack_require__(723); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -105948,7 +106160,7 @@ exports.default = EntryFilter; /***/ }), -/* 906 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105968,8 +106180,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var fsStat = __webpack_require__(907); -var fs_1 = __webpack_require__(911); +var fsStat = __webpack_require__(909); +var fs_1 = __webpack_require__(913); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -106019,14 +106231,14 @@ exports.default = FileSystemStream; /***/ }), -/* 907 */ +/* 909 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(908); -const statProvider = __webpack_require__(910); +const optionsManager = __webpack_require__(910); +const statProvider = __webpack_require__(912); /** * Asynchronous API. */ @@ -106057,13 +106269,13 @@ exports.statSync = statSync; /***/ }), -/* 908 */ +/* 910 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(909); +const fsAdapter = __webpack_require__(911); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -106076,7 +106288,7 @@ exports.prepare = prepare; /***/ }), -/* 909 */ +/* 911 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106099,7 +106311,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 910 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106151,7 +106363,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 911 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106182,7 +106394,7 @@ exports.default = FileSystem; /***/ }), -/* 912 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106202,9 +106414,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var readdir = __webpack_require__(889); -var reader_1 = __webpack_require__(902); -var fs_stream_1 = __webpack_require__(906); +var readdir = __webpack_require__(891); +var reader_1 = __webpack_require__(904); +var fs_stream_1 = __webpack_require__(908); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -106272,7 +106484,7 @@ exports.default = ReaderStream; /***/ }), -/* 913 */ +/* 915 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106291,9 +106503,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(889); -var reader_1 = __webpack_require__(902); -var fs_sync_1 = __webpack_require__(914); +var readdir = __webpack_require__(891); +var reader_1 = __webpack_require__(904); +var fs_sync_1 = __webpack_require__(916); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -106353,7 +106565,7 @@ exports.default = ReaderSync; /***/ }), -/* 914 */ +/* 916 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106372,8 +106584,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(907); -var fs_1 = __webpack_require__(911); +var fsStat = __webpack_require__(909); +var fs_1 = __webpack_require__(913); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -106419,7 +106631,7 @@ exports.default = FileSystemSync; /***/ }), -/* 915 */ +/* 917 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106435,13 +106647,13 @@ exports.flatten = flatten; /***/ }), -/* 916 */ +/* 918 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(588); +var merge2 = __webpack_require__(590); /** * Merge multiple streams and propagate their errors into one stream in parallel. */ @@ -106456,13 +106668,13 @@ exports.merge = merge; /***/ }), -/* 917 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(918); +const pathType = __webpack_require__(920); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -106528,13 +106740,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 918 */ +/* 920 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(919); +const pify = __webpack_require__(921); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -106577,7 +106789,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 919 */ +/* 921 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106668,17 +106880,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 920 */ +/* 922 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(717); -const gitIgnore = __webpack_require__(921); -const pify = __webpack_require__(922); -const slash = __webpack_require__(923); +const fastGlob = __webpack_require__(719); +const gitIgnore = __webpack_require__(923); +const pify = __webpack_require__(924); +const slash = __webpack_require__(925); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -106776,7 +106988,7 @@ module.exports.sync = options => { /***/ }), -/* 921 */ +/* 923 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -107245,7 +107457,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 922 */ +/* 924 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107320,7 +107532,7 @@ module.exports = (input, options) => { /***/ }), -/* 923 */ +/* 925 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107338,17 +107550,17 @@ module.exports = input => { /***/ }), -/* 924 */ +/* 926 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const pEvent = __webpack_require__(925); -const CpFileError = __webpack_require__(928); -const fs = __webpack_require__(932); -const ProgressEmitter = __webpack_require__(935); +const pEvent = __webpack_require__(927); +const CpFileError = __webpack_require__(930); +const fs = __webpack_require__(934); +const ProgressEmitter = __webpack_require__(937); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -107462,12 +107674,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 925 */ +/* 927 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(926); +const pTimeout = __webpack_require__(928); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -107758,12 +107970,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 926 */ +/* 928 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(927); +const pFinally = __webpack_require__(929); class TimeoutError extends Error { constructor(message) { @@ -107809,7 +108021,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 927 */ +/* 929 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -107831,12 +108043,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 928 */ +/* 930 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(929); +const NestedError = __webpack_require__(931); class CpFileError extends NestedError { constructor(message, nested) { @@ -107850,10 +108062,10 @@ module.exports = CpFileError; /***/ }), -/* 929 */ +/* 931 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(930); +var inherits = __webpack_require__(932); var NestedError = function (message, nested) { this.nested = nested; @@ -107904,7 +108116,7 @@ module.exports = NestedError; /***/ }), -/* 930 */ +/* 932 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -107912,12 +108124,12 @@ try { if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { - module.exports = __webpack_require__(931); + module.exports = __webpack_require__(933); } /***/ }), -/* 931 */ +/* 933 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -107946,16 +108158,16 @@ if (typeof Object.create === 'function') { /***/ }), -/* 932 */ +/* 934 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const fs = __webpack_require__(22); -const makeDir = __webpack_require__(933); -const pEvent = __webpack_require__(925); -const CpFileError = __webpack_require__(928); +const makeDir = __webpack_require__(935); +const pEvent = __webpack_require__(927); +const CpFileError = __webpack_require__(930); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -108052,7 +108264,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 933 */ +/* 935 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108060,7 +108272,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(23); const path = __webpack_require__(16); const {promisify} = __webpack_require__(29); -const semver = __webpack_require__(934); +const semver = __webpack_require__(936); const defaults = { mode: 0o777 & (~process.umask()), @@ -108209,7 +108421,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 934 */ +/* 936 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -109811,7 +110023,7 @@ function coerce (version, options) { /***/ }), -/* 935 */ +/* 937 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -109852,7 +110064,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 936 */ +/* 938 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -109898,12 +110110,12 @@ exports.default = module.exports; /***/ }), -/* 937 */ +/* 939 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(938); +const NestedError = __webpack_require__(940); class CpyError extends NestedError { constructor(message, nested) { @@ -109917,7 +110129,7 @@ module.exports = CpyError; /***/ }), -/* 938 */ +/* 940 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -109973,14 +110185,14 @@ module.exports = NestedError; /***/ }), -/* 939 */ +/* 941 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return prepareExternalProjectDependencies; }); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(516); -/* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(515); +/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(518); +/* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(517); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts index 64270c677ff20..3ec478e3ca28d 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts @@ -149,13 +149,13 @@ describe('DocumentMigrator', () => { expect(_.get(migratedDoc, 'attributes.name')).toBe('Mike'); }); - it('migrates meta properties', () => { + it('migrates root properties', () => { const migrator = new DocumentMigrator({ ...testOpts(), typeRegistry: createRegistry({ name: 'acl', migrations: { - '2.3.5': setAttr('acl', 'admins-only,sucka!'), + '2.3.5': setAttr('acl', 'admins-only, sucka!'), }, }), }); @@ -165,13 +165,13 @@ describe('DocumentMigrator', () => { attributes: { name: 'Tyler' }, acl: 'anyone', migrationVersion: {}, - }); + } as SavedObjectUnsanitizedDoc); expect(actual).toEqual({ id: 'me', type: 'user', attributes: { name: 'Tyler' }, migrationVersion: { acl: '2.3.5' }, - acl: 'admins-only,sucka!', + acl: 'admins-only, sucka!', }); }); @@ -241,7 +241,7 @@ describe('DocumentMigrator', () => { type: 'user', attributes: { name: 'Tyler' }, bbb: 'Shazm', - }); + } as SavedObjectUnsanitizedDoc); expect(actual).toEqual({ id: 'me', type: 'user', @@ -405,7 +405,7 @@ describe('DocumentMigrator', () => { attributes: { name: 'Callie' }, dawg: 'Yo', migrationVersion: {}, - }); + } as SavedObjectUnsanitizedDoc); expect(actual).toEqual({ id: 'smelly', type: 'foo', diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts index 0284f513a361c..4ddb2b070d3ac 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts @@ -279,7 +279,7 @@ function props(doc: SavedObjectUnsanitizedDoc) { */ function propVersion(doc: SavedObjectUnsanitizedDoc | ActiveMigrations, prop: string) { return ( - (doc[prop] && doc[prop].latestVersion) || + ((doc as any)[prop] && (doc as any)[prop].latestVersion) || (doc.migrationVersion && (doc as any).migrationVersion[prop]) ); } diff --git a/src/core/server/saved_objects/serialization/types.ts b/src/core/server/saved_objects/serialization/types.ts index 7ea61f67e9496..a33e16895078e 100644 --- a/src/core/server/saved_objects/serialization/types.ts +++ b/src/core/server/saved_objects/serialization/types.ts @@ -45,10 +45,7 @@ export interface SavedObjectsRawDocSource { } /** - * A saved object type definition that allows for miscellaneous, unknown - * properties, as current discussions around security, ACLs, etc indicate - * that future props are likely to be added. Migrations support this - * scenario out of the box. + * Saved Object base document */ interface SavedObjectDoc { attributes: any; @@ -59,8 +56,6 @@ interface SavedObjectDoc { migrationVersion?: SavedObjectsMigrationVersion; version?: string; updated_at?: string; - - [rootProp: string]: any; } interface Referencable { @@ -68,14 +63,18 @@ interface Referencable { } /** - * We want to have two types, one that guarantees a "references" attribute - * will exist and one that allows it to be null. Since we're not migrating - * all the saved objects to have a "references" array, we need to support - * the scenarios where it may be missing (ex migrations). + * Describes Saved Object documents from Kibana < 7.0.0 which don't have a + * `references` root property defined. This type should only be used in + * migrations. * * @public */ export type SavedObjectUnsanitizedDoc = SavedObjectDoc & Partial; -/** @public */ +/** + * Describes Saved Object documents that have passed through the migration + * framework and are guaranteed to have a `references` root property. + * + * @public + */ export type SavedObjectSanitizedDoc = SavedObjectDoc & Referencable; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 2efa7dac393b4..a36e746f6d940 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1707,7 +1707,7 @@ export interface SavedObjectsAddToNamespacesOptions extends SavedObjectsBaseOpti // Warning: (ae-forgotten-export) The symbol "SavedObjectDoc" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Referencable" needs to be exported by the entry point index.d.ts // -// @public (undocumented) +// @public export type SavedObjectSanitizedDoc = SavedObjectDoc & Referencable; // @public (undocumented) diff --git a/src/dev/build/tasks/build_kibana_platform_plugins.js b/src/dev/build/tasks/build_kibana_platform_plugins.js index 79cd698e4782c..28d6b49f9e89a 100644 --- a/src/dev/build/tasks/build_kibana_platform_plugins.js +++ b/src/dev/build/tasks/build_kibana_platform_plugins.js @@ -17,7 +17,13 @@ * under the License. */ -import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; +import { CiStatsReporter } from '@kbn/dev-utils'; +import { + runOptimizer, + OptimizerConfig, + logOptimizerState, + reportOptimizerStats, +} from '@kbn/optimizer'; export const BuildKibanaPlatformPluginsTask = { description: 'Building distributable versions of Kibana platform plugins', @@ -32,8 +38,14 @@ export const BuildKibanaPlatformPluginsTask = { includeCoreBundle: true, }); + const reporter = CiStatsReporter.fromEnv(log); + const reportStatsName = build.isOss() ? 'oss distributable' : 'default distributable'; + await runOptimizer(optimizerConfig) - .pipe(logOptimizerState(log, optimizerConfig)) + .pipe( + reportOptimizerStats(reporter, reportStatsName), + logOptimizerState(log, optimizerConfig) + ) .toPromise(); }, }; diff --git a/src/dev/run_check_published_api_changes.ts b/src/dev/run_check_published_api_changes.ts index ba3cd1280f34b..6d5fa04a93951 100644 --- a/src/dev/run_check_published_api_changes.ts +++ b/src/dev/run_check_published_api_changes.ts @@ -250,7 +250,7 @@ async function run( Options: --accept {dim Accepts all changes by updating the API Review files and documentation} --docs {dim Updates the Core API documentation} - --only {dim RegExp that folder names must match, folders: [${folders.join(', ')}]} + --filter {dim RegExp that folder names must match, folders: [${folders.join(', ')}]} --help {dim Show this message} `) ); diff --git a/src/es_archiver/actions/rebuild_all.ts b/src/es_archiver/actions/rebuild_all.ts index 1467a1d0430b7..f35b2ca49c666 100644 --- a/src/es_archiver/actions/rebuild_all.ts +++ b/src/es_archiver/actions/rebuild_all.ts @@ -18,7 +18,7 @@ */ import { resolve, dirname, relative } from 'path'; -import { stat, rename, createReadStream, createWriteStream } from 'fs'; +import { stat, Stats, rename, createReadStream, createWriteStream } from 'fs'; import { Readable, Writable } from 'stream'; import { fromNode } from 'bluebird'; import { ToolingLog } from '@kbn/dev-utils'; @@ -33,7 +33,7 @@ import { } from '../lib'; async function isDirectory(path: string): Promise { - const stats = await fromNode(cb => stat(path, cb)); + const stats: Stats = await fromNode(cb => stat(path, cb)); return stats.isDirectory(); } diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 19ae3f7a177ef..48d86e3628e49 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -118,16 +118,6 @@ export default function(kibana) { }, ], - savedObjectsManagement: { - url: { - defaultSearchField: 'url', - isImportableAndExportable: true, - getTitle(obj) { - return `/goto/${encodeURIComponent(obj.id)}`; - }, - }, - }, - injectDefaultVars(server, options) { const mapConfig = server.config().get('map'); const tilemap = mapConfig.tilemap; diff --git a/src/legacy/core_plugins/kibana/mappings.json b/src/legacy/core_plugins/kibana/mappings.json index 81b46878f6c1a..e2cbd584dbe1f 100644 --- a/src/legacy/core_plugins/kibana/mappings.json +++ b/src/legacy/core_plugins/kibana/mappings.json @@ -1,26 +1,4 @@ { - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 2048 - } - } - } - } - }, "server": { "properties": { "uuid": { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx index 4839870f0f3c8..564f115cf2c48 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx @@ -23,6 +23,7 @@ import { FieldEditor } from 'ui/field_editor'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { HttpStart, DocLinksStart } from 'src/core/public'; import { IndexHeader } from '../index_header'; import { IndexPattern, IndexPatternField } from '../../../../../../../../../plugins/data/public'; import { ChromeDocTitle, NotificationsStart } from '../../../../../../../../../core/public'; @@ -37,7 +38,8 @@ interface CreateEditFieldProps extends RouteComponentProps { services: { notifications: NotificationsStart; docTitle: ChromeDocTitle; - http: Function; + getHttpStart: () => HttpStart; + docLinksScriptedFields: DocLinksStart['links']['scriptedFields']; }; } @@ -68,16 +70,14 @@ export const CreateEditField = withRouter( const url = `/management/kibana/index_patterns/${indexPattern.id}`; - if (mode === 'edit') { - if (!field) { - const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', { - defaultMessage: - "'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'", - values: { indexPatternTitle: indexPattern.title, fieldName }, - }); - services.notifications.toasts.addWarning(message); - history.push(url); - } + if (mode === 'edit' && !field) { + const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', { + defaultMessage: + "'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'", + values: { indexPatternTitle: indexPattern.title, fieldName }, + }); + services.notifications.toasts.addWarning(message); + history.push(url); } const docFieldName = field?.name || newFieldPlaceholder; @@ -88,24 +88,29 @@ export const CreateEditField = withRouter( history.push(`${url}?_a=(tab:${field?.scripted ? TAB_SCRIPTED_FIELDS : TAB_INDEXED_FIELDS})`); }; - return ( - - - - - - - - - ); + if (field) { + return ( + + + + + + + + + ); + } else { + return <>; + } } ); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js index e05aea3678fe2..e2f387c0291a7 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js @@ -95,7 +95,7 @@ uiModules // routes for create edit field. Will be removed after migartion all component to react. const REACT_FIELD_EDITOR_ID = 'reactFieldEditor'; -const renderCreateEditField = ($scope, $route, getConfig, $http, fieldFormatEditors) => { +const renderCreateEditField = ($scope, $route, getConfig, fieldFormatEditors) => { $scope.$$postDigest(() => { const node = document.getElementById(REACT_FIELD_EDITOR_ID); if (!node) { @@ -112,9 +112,10 @@ const renderCreateEditField = ($scope, $route, getConfig, $http, fieldFormatEdit fieldFormatEditors={fieldFormatEditors} getConfig={getConfig} services={{ - http: $http, + getHttpStart: () => npStart.core.http, notifications: npStart.core.notifications, docTitle: npStart.core.chrome.docTitle, + docLinksScriptedFields: npStart.core.docLinks.links.scriptedFields, }} /> @@ -162,11 +163,11 @@ uiRoutes }, }, controllerAs: 'fieldSettings', - controller: function FieldEditorPageController($scope, $route, $http, Private, config) { + controller: function FieldEditorPageController($scope, $route, Private, config) { const getConfig = (...args) => config.get(...args); const fieldFormatEditors = Private(RegistryFieldFormatEditorsProvider); - renderCreateEditField($scope, $route, getConfig, $http, fieldFormatEditors); + renderCreateEditField($scope, $route, getConfig, fieldFormatEditors); $scope.$on('$destroy', () => { destroyCreateEditField(); diff --git a/src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.js.snap b/src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.tsx.snap similarity index 77% rename from src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.js.snap rename to src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.tsx.snap index 19d12f4bbbd4c..dc11bdfefa46b 100644 --- a/src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.js.snap +++ b/src/legacy/ui/public/field_editor/__snapshots__/field_editor.test.tsx.snap @@ -19,10 +19,31 @@ exports[`FieldEditor should render create new scripted field correctly 1`] = ` isVisible={false} /> - Test format - , - } - } + defaultMessage="Format" + id="common.ui.fieldEditor.formatHeader" + values={Object {}} /> } > @@ -134,8 +149,8 @@ exports[`FieldEditor should render create new scripted field correctly 1`] = ` "value": "", }, Object { - "text": "Test format", - "value": "test_format", + "text": undefined, + "value": "", }, ] } @@ -260,10 +275,31 @@ exports[`FieldEditor should render edit scripted field correctly 1`] = ` isVisible={false} /> - Test format - , - } - } + defaultMessage="Format" + id="common.ui.fieldEditor.formatHeader" + values={Object {}} /> } > @@ -371,8 +401,8 @@ exports[`FieldEditor should render edit scripted field correctly 1`] = ` "value": "", }, Object { - "text": "Test format", - "value": "test_format", + "text": undefined, + "value": "", }, ] } @@ -508,10 +538,31 @@ exports[`FieldEditor should show conflict field warning 1`] = ` isVisible={false} /> - Test format - , - } - } + defaultMessage="Format" + id="common.ui.fieldEditor.formatHeader" + values={Object {}} /> } > @@ -667,8 +712,8 @@ exports[`FieldEditor should show conflict field warning 1`] = ` "value": "", }, Object { - "text": "Test format", - "value": "test_format", + "text": undefined, + "value": "", }, ] } @@ -793,10 +838,31 @@ exports[`FieldEditor should show deprecated lang warning 1`] = ` isVisible={false} /> , "painlessLink": - Test format - , - } - } + defaultMessage="Format" + id="common.ui.fieldEditor.formatHeader" + values={Object {}} /> } > @@ -994,8 +1054,8 @@ exports[`FieldEditor should show deprecated lang warning 1`] = ` "value": "", }, Object { - "text": "Test format", - "value": "test_format", + "text": undefined, + "value": "", }, ] } @@ -1131,10 +1191,31 @@ exports[`FieldEditor should show multiple type field warning with a table contai isVisible={false} /> - Test format - , - } - } + defaultMessage="Format" + id="common.ui.fieldEditor.formatHeader" + values={Object {}} /> } > @@ -1346,8 +1421,8 @@ exports[`FieldEditor should show multiple type field warning with a table contai "value": "", }, Object { - "text": "Test format", - "value": "test_format", + "text": undefined, + "value": "", }, ] } diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.tsx.snap similarity index 62% rename from src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.tsx.snap index b83ae8a901ecc..82d21eb5d30ad 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/__snapshots__/field_format_editor.test.tsx.snap @@ -12,4 +12,14 @@ exports[`FieldFormatEditor should render normally 1`] = ` `; -exports[`FieldFormatEditor should render nothing if there is no editor for the format 1`] = ``; +exports[`FieldFormatEditor should render nothing if there is no editor for the format 1`] = ` + + + +`; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap index 1f77660c9784c..bf1682faf9a9d 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/bytes/__snapshots__/bytes.test.tsx.snap @@ -5,7 +5,6 @@ exports[`BytesFormatEditor should render normally 1`] = ` input => input * 2), + getConverterFor: jest.fn().mockImplementation(() => (input: number) => input * 2), getParamDefaults: jest.fn().mockImplementation(() => { return { pattern: '0,0.[000]b' }; }), }; -const formatParams = {}; +const formatParams = { + pattern: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -41,8 +44,9 @@ describe('BytesFormatEditor', () => { it('should render normally', async () => { const component = shallow( { it('should render string type normally (regex field)', async () => { const component = shallowWithI18nProvider( { it('should render other type normally (range field)', async () => { const component = shallowWithI18nProvider( { it('should render multiple colors', async () => { const component = shallowWithI18nProvider( { + static formatId = 'color'; + constructor(props: FormatEditorProps) { super(props); this.onChange({ fieldType: props.fieldType, }); } - onColorChange = (newColorParams, index) => { + onColorChange = (newColorParams: Partial, index: number) => { const colors = [...this.props.formatParams.colors]; colors[index] = { ...colors[index], @@ -54,7 +69,7 @@ export class ColorFormatEditor extends DefaultFormatEditor { }); }; - removeColor = index => { + removeColor = (index: number) => { const colors = [...this.props.formatParams.colors]; colors.splice(index, 1); this.onChange({ @@ -86,7 +101,7 @@ export class ColorFormatEditor extends DefaultFormatEditor { defaultMessage="Pattern (regular expression)" /> ), - render: (value, item) => { + render: (value: string, item: IndexedColor) => { return ( ), - render: (value, item) => { + render: (value: string, item: IndexedColor) => { return ( ), - render: (color, item) => { + render: (color: string, item: IndexedColor) => { return ( ), - render: (color, item) => { + render: (color: string, item: IndexedColor) => { return ( ), - render: item => { + render: (item: IndexedColor) => { return (
{ + onClick: (item: IndexedColor) => { this.removeColor(item.index); }, type: 'icon', @@ -230,5 +249,3 @@ export class ColorFormatEditor extends DefaultFormatEditor { ); } } - -ColorFormatEditor.formatId = 'color'; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/color/index.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/color/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/color/index.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/color/index.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.tsx.snap similarity index 99% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.tsx.snap index e33f0d6ee9c61..2d73f775e316c 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/__snapshots__/date.test.tsx.snap @@ -5,7 +5,6 @@ exports[`DateFormatEditor should render normally 1`] = ` input => `converted date for ${input}`), + getConverterFor: jest + .fn() + .mockImplementation(() => (input: string) => `converted date for ${input}`), getParamDefaults: jest.fn().mockImplementation(() => { return { pattern: 'MMMM Do YYYY, HH:mm:ss.SSS' }; }), }; -const formatParams = {}; +const formatParams = { pattern: '' }; const onChange = jest.fn(); const onError = jest.fn(); @@ -41,8 +44,9 @@ describe('DateFormatEditor', () => { it('should render normally', async () => { const component = shallow( { static formatId = 'date'; - - constructor(props) { - super(props); - this.state.sampleInputs = [ + state = { + ...defaultState, + sampleInputs: [ Date.now(), moment() .startOf('year') @@ -41,8 +43,8 @@ export class DateFormatEditor extends DefaultFormatEditor { moment() .endOf('year') .valueOf(), - ]; - } + ], + }; render() { const { format, formatParams } = this.props; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/index.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/index.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/date/index.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.tsx.snap similarity index 99% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.tsx.snap index cb570144fcee3..1456deaa13e47 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/__snapshots__/date_nanos.test.tsx.snap @@ -5,7 +5,6 @@ exports[`DateFormatEditor should render normally 1`] = ` input => `converted date for ${input}`), + getConverterFor: jest + .fn() + .mockImplementation(() => (input: string) => `converted date for ${input}`), getParamDefaults: jest.fn().mockImplementation(() => { return { pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS' }; }), }; -const formatParams = {}; +const formatParams = { + pattern: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -41,8 +46,9 @@ describe('DateFormatEditor', () => { it('should render normally', async () => { const component = shallow( { static formatId = 'date_nanos'; - - constructor(props) { - super(props); - this.state.sampleInputs = [ + state = { + ...defaultState, + sampleInputs: [ '2015-01-01T12:10:30.123456789Z', '2019-05-08T06:55:21.567891234Z', '2019-08-06T17:22:30.987654321Z', - ]; - } + ], + }; render() { const { format, formatParams } = this.props; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/index.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/index.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/date_nanos/index.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.js.snap deleted file mode 100644 index 0f9eef6f922c8..0000000000000 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.js.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DefaultFormatEditor should render nothing 1`] = `""`; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.tsx.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.tsx.snap new file mode 100644 index 0000000000000..74468ea1451f4 --- /dev/null +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/__snapshots__/default.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DefaultFormatEditor should render nothing 1`] = ``; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.tsx similarity index 77% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.tsx index cf87d4a886024..3f30af97dc063 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/default.test.tsx @@ -19,8 +19,9 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { FieldFormat } from 'src/plugins/data/public'; -import { DefaultFormatEditor, convertSampleInput } from './default'; +import { DefaultFormatEditor, convertSampleInput, ConverterParams } from './default'; const fieldType = 'number'; const format = { @@ -32,13 +33,11 @@ const onError = jest.fn(); describe('DefaultFormatEditor', () => { describe('convertSampleInput', () => { - const converter = input => { - if (isNaN(input)) { - throw { - message: 'Input is not a number', - }; + const converter = (input: ConverterParams) => { + if (typeof input !== 'number') { + throw new Error('Input is not a number'); } else { - return input * 2; + return (input * 2).toString(); } }; @@ -46,12 +45,12 @@ describe('DefaultFormatEditor', () => { const inputs = [1, 10, 15]; const output = convertSampleInput(converter, inputs); - expect(output.error).toEqual(null); + expect(output.error).toBeUndefined(); expect(JSON.stringify(output.samples)).toEqual( JSON.stringify([ - { input: 1, output: 2 }, - { input: 10, output: 20 }, - { input: 15, output: 30 }, + { input: 1, output: '2' }, + { input: 10, output: '20' }, + { input: 15, output: '30' }, ]) ); }); @@ -70,8 +69,9 @@ describe('DefaultFormatEditor', () => { it('should render nothing', async () => { const component = shallow( { it('should call prop onChange()', async () => { const component = shallow( ); - component.instance().onChange(); + (component.instance() as DefaultFormatEditor).onChange(); expect(onChange).toBeCalled(); }); it('should call prop onError() if converter throws an error', async () => { const newFormat = { getConverterFor: jest.fn().mockImplementation(() => () => { - throw { message: 'Test error message' }; + throw new Error('Test error message'); }), }; shallow( { - let error = null; - let samples = []; +import { FieldFormat, FieldFormatsContentType } from 'src/plugins/data/public'; +import { Sample } from '../../../../types'; +import { FieldFormatEditorProps } from '../../field_format_editor'; + +export type ConverterParams = string | number | Array; + +export const convertSampleInput = ( + converter: (input: ConverterParams) => string, + inputs: ConverterParams[] +) => { + let error; + let samples: Sample[] = []; try { samples = inputs.map(input => { @@ -45,32 +53,48 @@ export const convertSampleInput = (converter, inputs) => { }; }; -export class DefaultFormatEditor extends PureComponent { - static propTypes = { - fieldType: PropTypes.string.isRequired, - format: PropTypes.object.isRequired, - formatParams: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - onError: PropTypes.func.isRequired, - }; +interface SampleInputs { + [key: string]: Array; +} - constructor(props) { - super(props); - this.state = { - sampleInputs: [], - sampleConverterType: 'text', - error: null, - samples: [], - }; - } +export interface FormatEditorProps

{ + fieldType: string; + format: FieldFormat; + formatParams: { type?: string } & P; + onChange: (newParams: Record) => void; + onError: FieldFormatEditorProps['onError']; + basePath: string; +} - static getDerivedStateFromProps(nextProps, state) { +export interface FormatEditorState { + sampleInputs: ReactText[]; + sampleConverterType: FieldFormatsContentType; + error?: string; + samples: Sample[]; + sampleInputsByType: SampleInputs; +} + +export const defaultState = { + sampleInputs: [] as ReactText[], + sampleConverterType: 'text' as FieldFormatsContentType, + error: undefined, + samples: [] as Sample[], + sampleInputsByType: {}, +}; + +export class DefaultFormatEditor

extends PureComponent< + FormatEditorProps

, + FormatEditorState & S +> { + state = defaultState as FormatEditorState & S; + + static getDerivedStateFromProps(nextProps: FormatEditorProps<{}>, state: FormatEditorState) { const { format, formatParams, onError } = nextProps; const { sampleInputsByType, sampleInputs, sampleConverterType } = state; const converter = format.getConverterFor(sampleConverterType); const type = typeof sampleInputsByType === 'object' && formatParams.type; - const inputs = type ? sampleInputsByType[formatParams.type] || [] : sampleInputs; + const inputs = type ? sampleInputsByType[formatParams.type as string] || [] : sampleInputs; const output = convertSampleInput(converter, inputs); onError(output.error); return output; @@ -78,6 +102,7 @@ export class DefaultFormatEditor extends PureComponent { onChange = (newParams = {}) => { const { onChange, formatParams } = this.props; + onChange({ ...formatParams, ...newParams, @@ -85,6 +110,6 @@ export class DefaultFormatEditor extends PureComponent { }; render() { - return null; + return <>; } } diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.ts b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.ts new file mode 100644 index 0000000000000..a6575f296864d --- /dev/null +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/default/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { DefaultFormatEditor, defaultState, FormatEditorProps, FormatEditorState } from './default'; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap index ef11d70926ad7..dbebd324b16b6 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/duration/__snapshots__/duration.test.tsx.snap @@ -5,7 +5,6 @@ exports[`DurationFormatEditor should render human readable output normally 1`] = input => `converted duration for ${input}`), + getConverterFor: jest + .fn() + .mockImplementation(() => (input: string) => `converted duration for ${input}`), getParamDefaults: jest.fn().mockImplementation(() => { return { inputFormat: 'seconds', @@ -52,7 +55,11 @@ const format = { ], }, }; -const formatParams = {}; +const formatParams = { + outputPrecision: 2, + inputFormat: '', + outputFormat: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -64,8 +71,9 @@ describe('DurationFormatEditor', () => { it('should render human readable output normally', async () => { const component = shallow( { }; const component = shallow( { + static formatId = 'duration'; + state = { + ...defaultState, + sampleInputs: [-123, 1, 12, 123, 658, 1988, 3857, 123292, 923528271], + hasDecimalError: false, + }; - static getDerivedStateFromProps(nextProps, state) { + static getDerivedStateFromProps( + nextProps: FormatEditorProps, + state: FormatEditorState & DurationFormatEditorState + ) { const output = super.getDerivedStateFromProps(nextProps, state); let error = null; - if (!nextProps.format.isHuman() && nextProps.formatParams.outputPrecision > 20) { + if ( + !(nextProps.format as DurationFormat).isHuman() && + nextProps.formatParams.outputPrecision > 20 + ) { error = i18n.translate('common.ui.fieldEditor.durationErrorMessage', { defaultMessage: 'Decimal places must be between 0 and 20', }); @@ -77,10 +110,10 @@ export class DurationFormatEditor extends DefaultFormatEditor { > { + options={format.type.inputFormats.map((fmt: InputFormat) => { return { - value: format.kind, - text: format.text, + value: fmt.kind, + text: fmt.text, }; })} onChange={e => { @@ -100,10 +133,10 @@ export class DurationFormatEditor extends DefaultFormatEditor { > { + options={format.type.outputFormats.map((fmt: OutputFormat) => { return { - value: format.method, - text: format.text, + value: fmt.method, + text: fmt.text, }; })} onChange={e => { @@ -112,7 +145,7 @@ export class DurationFormatEditor extends DefaultFormatEditor { isInvalid={!!error} /> - {!format.isHuman() ? ( + {!(format as DurationFormat).isHuman() ? ( input => input * 2), + getConverterFor: jest.fn().mockImplementation(() => (input: number) => input * 2), getParamDefaults: jest.fn().mockImplementation(() => { return { pattern: '0,0.[000]' }; }), }; -const formatParams = {}; +const formatParams = { + pattern: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -41,8 +44,9 @@ describe('NumberFormatEditor', () => { it('should render normally', async () => { const component = shallow( { static formatId = 'number'; - - constructor(props) { - super(props); - this.state.sampleInputs = [10000, 12.345678, -1, -999, 0.52]; - } + state = { + ...defaultState, + sampleInputs: [10000, 12.345678, -1, -999, 0.52], + }; render() { const { format, formatParams } = this.props; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap similarity index 99% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap index 30d1de270522e..0784a3f5e407d 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/percent/__snapshots__/percent.test.tsx.snap @@ -5,7 +5,6 @@ exports[`PercentFormatEditor should render normally 1`] = ` input => input * 2), + getConverterFor: jest.fn().mockImplementation(() => (input: number) => input * 2), getParamDefaults: jest.fn().mockImplementation(() => { return { pattern: '0,0.[000]%' }; }), }; -const formatParams = {}; +const formatParams = { + pattern: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -41,8 +44,9 @@ describe('PercentFormatEditor', () => { it('should render normally', async () => { const component = shallow( { it('should render normally', async () => { const component = shallowWithI18nProvider( { it('should render multiple lookup entries and unknown key value', async () => { const component = shallowWithI18nProvider( diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.tsx similarity index 86% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.tsx index 31ff99696da01..f998e271b6c99 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/static_lookup/static_lookup.tsx @@ -21,13 +21,26 @@ import React, { Fragment } from 'react'; import { EuiBasicTable, EuiButton, EuiFieldText, EuiFormRow, EuiSpacer } from '@elastic/eui'; -import { DefaultFormatEditor } from '../default'; - import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { DefaultFormatEditor } from '../default'; + +export interface StaticLookupFormatEditorFormatParams { + lookupEntries: Array<{ key: string; value: string }>; + unknownKeyValue: string; +} + +interface StaticLookupItem { + key: string; + value: string; + index: number; +} -export class StaticLookupFormatEditor extends DefaultFormatEditor { - onLookupChange = (newLookupParams, index) => { +export class StaticLookupFormatEditor extends DefaultFormatEditor< + StaticLookupFormatEditorFormatParams +> { + static formatId = 'static_lookup'; + onLookupChange = (newLookupParams: { value?: string; key?: string }, index: number) => { const lookupEntries = [...this.props.formatParams.lookupEntries]; lookupEntries[index] = { ...lookupEntries[index], @@ -45,7 +58,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor { }); }; - removeLookup = index => { + removeLookup = (index: number) => { const lookupEntries = [...this.props.formatParams.lookupEntries]; lookupEntries.splice(index, 1); this.onChange({ @@ -73,7 +86,7 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor { name: ( ), - render: (value, item) => { + render: (value: number, item: StaticLookupItem) => { return ( ), - render: (value, item) => { + render: (value: number, item: StaticLookupItem) => { return ( { + onClick: (item: StaticLookupItem) => { this.removeLookup(item.index); }, type: 'icon', @@ -172,5 +189,3 @@ export class StaticLookupFormatEditor extends DefaultFormatEditor { ); } } - -StaticLookupFormatEditor.formatId = 'static_lookup'; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.tsx.snap index 270ff844fd086..cde081ff10d14 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/string/__snapshots__/string.test.tsx.snap @@ -5,7 +5,6 @@ exports[`StringFormatEditor should render normally 1`] = ` input => input.toUpperCase()), + getConverterFor: jest.fn().mockImplementation(() => (input: string) => input.toUpperCase()), getParamDefaults: jest.fn().mockImplementation(() => { return { transform: 'upper' }; }), @@ -37,7 +38,9 @@ const format = { ], }, }; -const formatParams = {}; +const formatParams = { + transform: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -49,8 +52,9 @@ describe('StringFormatEditor', () => { it('should render normally', async () => { const component = shallow( { + static formatId = 'string'; + state = { + ...defaultState, + sampleInputs: [ 'A Quick Brown Fox.', 'STAY CALM!', 'com.organizations.project.ClassName', 'hostname.net', 'SGVsbG8gd29ybGQ=', '%EC%95%88%EB%85%95%20%ED%82%A4%EB%B0%94%EB%82%98', - ]; - } + ], + }; render() { const { format, formatParams } = this.props; @@ -61,7 +68,7 @@ export class StringFormatEditor extends DefaultFormatEditor { { + options={format.type.transformOptions.map((option: TransformOptions) => { return { value: option.kind, text: option.text, diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap index 729487dfae5d7..f646d5b4afca8 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/__snapshots__/truncate.test.tsx.snap @@ -5,7 +5,6 @@ exports[`TruncateFormatEditor should render normally 1`] = ` input => input.substring(0, 10)), + getConverterFor: jest.fn().mockImplementation(() => (input: string) => input.substring(0, 10)), getParamDefaults: jest.fn().mockImplementation(() => { return { fieldLength: 10 }; }), }; -const formatParams = {}; +const formatParams = { + fieldLength: 5, +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -47,8 +50,9 @@ describe('TruncateFormatEditor', () => { it('should render normally', async () => { const component = shallow( { it('should fire error, when input is invalid', async () => { const component = shallow( { validationMessage: 'Error!', }, }; - await input.invoke('onChange')(changeEvent); + + await input!.invoke('onChange')!((changeEvent as unknown) as ChangeEvent); expect(onError).toBeCalledWith(changeEvent.target.validationMessage); expect(onChange).not.toBeCalled(); @@ -85,8 +91,9 @@ describe('TruncateFormatEditor', () => { it('should fire change, when input changed and is valid', async () => { const component = shallow( { }, }; onError.mockClear(); - await input.invoke('onChange')(changeEvent); + await input!.invoke('onChange')!((changeEvent as unknown) as ChangeEvent); expect(onError).not.toBeCalled(); expect(onChange).toBeCalledWith({ fieldLength: 123 }); }); diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.tsx similarity index 87% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.tsx index 9a9b6c954b78d..9fd44c5f9655d 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/truncate/truncate.tsx @@ -21,21 +21,23 @@ import React, { Fragment } from 'react'; import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; -import { DefaultFormatEditor } from '../default'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { DefaultFormatEditor, defaultState } from '../default'; import { FormatEditorSamples } from '../../samples'; import { sample } from './sample'; -import { FormattedMessage } from '@kbn/i18n/react'; +interface TruncateFormatEditorFormatParams { + fieldLength: number; +} -export class TruncateFormatEditor extends DefaultFormatEditor { +export class TruncateFormatEditor extends DefaultFormatEditor { static formatId = 'truncate'; - - constructor(props) { - super(props); - this.state.sampleInputs = [sample]; - } + state = { + ...defaultState, + sampleInputs: [sample], + }; render() { const { formatParams, onError } = this.props; diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/label_template_flyout.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/label_template_flyout.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/label_template_flyout.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/label_template_flyout.test.tsx.snap diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.tsx.snap index c727f54874db4..a3418077ad258 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/__snapshots__/url.test.tsx.snap @@ -49,7 +49,6 @@ exports[`UrlFormatEditor should render label template help 1`] = ` ' + + i18n.translate('common.ui.fieldEditor.labelTemplate.example.output.idLabel', { + defaultMessage: 'User', + }) + + ' #1234', + }, + { + input: '/assets/main.css', + urlTemplate: 'http://site.com{{rawValue}}', + labelTemplate: i18n.translate('common.ui.fieldEditor.labelTemplate.example.pathLabel', { + defaultMessage: 'View Asset', + }), + output: + '' + + i18n.translate('common.ui.fieldEditor.labelTemplate.example.output.pathLabel', { + defaultMessage: 'View Asset', + }) + + '', + }, +]; + export const LabelTemplateFlyout = ({ isVisible = false, onClose = () => {} }) => { return isVisible ? ( @@ -66,40 +103,8 @@ export const LabelTemplateFlyout = ({ isVisible = false, onClose = () => {} }) = defaultMessage="Examples" /> - ' + - i18n.translate('common.ui.fieldEditor.labelTemplate.example.output.idLabel', { - defaultMessage: 'User', - }) + - ' #1234', - }, - { - input: '/assets/main.css', - urlTemplate: 'http://site.com{{rawValue}}', - labelTemplate: i18n.translate( - 'common.ui.fieldEditor.labelTemplate.example.pathLabel', - { defaultMessage: 'View Asset' } - ), - output: - '' + - i18n.translate('common.ui.fieldEditor.labelTemplate.example.output.pathLabel', { - defaultMessage: 'View Asset', - }) + - '', - }, - ]} + + items={items} columns={[ { field: 'input', @@ -125,14 +130,14 @@ export const LabelTemplateFlyout = ({ isVisible = false, onClose = () => {} }) = name: i18n.translate('common.ui.fieldEditor.labelTemplate.outputHeader', { defaultMessage: 'Output', }), - render: value => { + render: (value: LabelTemplateExampleItem['output']) => { return ( ); }, diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.tsx similarity index 78% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.tsx index 1d732b50db3d0..4d09da84edfb6 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url.test.tsx @@ -19,12 +19,15 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { FieldFormat } from 'src/plugins/data/public'; import { UrlFormatEditor } from './url'; const fieldType = 'string'; const format = { - getConverterFor: jest.fn().mockImplementation(() => input => `converted url for ${input}`), + getConverterFor: jest + .fn() + .mockImplementation(() => (input: string) => `converted url for ${input}`), type: { urlTypes: [ { kind: 'a', text: 'Link' }, @@ -33,7 +36,13 @@ const format = { ], }, }; -const formatParams = {}; +const formatParams = { + openLinkInCurrentTab: true, + urlTemplate: '', + labelTemplate: '', + width: '', + height: '', +}; const onChange = jest.fn(); const onError = jest.fn(); @@ -49,8 +58,9 @@ describe('UrlFormatEditor', () => { it('should render normally', async () => { const component = shallow( { it('should render url template help', async () => { const component = shallow( ); - component.instance().showUrlTemplateHelp(); + (component.instance() as UrlFormatEditor).showUrlTemplateHelp(); component.update(); expect(component).toMatchSnapshot(); }); @@ -79,15 +90,16 @@ describe('UrlFormatEditor', () => { it('should render label template help', async () => { const component = shallow( ); - component.instance().showLabelTemplateHelp(); + (component.instance() as UrlFormatEditor).showLabelTemplateHelp(); component.update(); expect(component).toMatchSnapshot(); }); @@ -95,8 +107,9 @@ describe('UrlFormatEditor', () => { it('should render width and height fields if image', async () => { const component = shallow( { static formatId = 'url'; + iconPattern: string; - constructor(props) { + constructor(props: FormatEditorProps) { super(props); - const bp = chrome.getBasePath(); - this.iconPattern = `${bp}/bundles/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/icons/{{value}}.png`; + + this.iconPattern = `${props.basePath}/bundles/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/icons/{{value}}.png`; this.state = { ...this.state, sampleInputsByType: { @@ -61,17 +88,17 @@ export class UrlFormatEditor extends DefaultFormatEditor { }; } - sanitizeNumericValue = val => { - const sanitizedValue = parseInt(val); + sanitizeNumericValue = (val: string) => { + const sanitizedValue = parseInt(val, 10); if (isNaN(sanitizedValue)) { return ''; } return sanitizedValue; }; - onTypeChange = newType => { + onTypeChange = (newType: string) => { const { urlTemplate, width, height } = this.props.formatParams; - const params = { + const params: OnChangeParam = { type: newType, }; if (newType === 'img') { @@ -81,7 +108,7 @@ export class UrlFormatEditor extends DefaultFormatEditor { params.urlTemplate = this.iconPattern; } } else if (newType !== 'img' && urlTemplate === this.iconPattern) { - params.urlTemplate = null; + params.urlTemplate = undefined; } this.onChange(params); }; @@ -169,7 +196,7 @@ export class UrlFormatEditor extends DefaultFormatEditor { { + options={format.type.urlTypes.map((type: UrlType) => { return { value: type.kind, text: type.text, diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.test.tsx similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.test.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.test.tsx diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.js b/src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.tsx similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/editors/url/url_template_flyout.tsx diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.tsx similarity index 84% rename from src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.tsx index 9e03841397872..f6e631c8b7ac0 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.test.tsx @@ -21,6 +21,7 @@ import React, { PureComponent } from 'react'; import { shallow } from 'enzyme'; import { FieldFormatEditor } from './field_format_editor'; +import { DefaultFormatEditor } from './editors/default'; class TestEditor extends PureComponent { render() { @@ -31,19 +32,22 @@ class TestEditor extends PureComponent { } } +const formatEditors = { + byFormatId: { + ip: TestEditor, + number: TestEditor, + }, +}; + describe('FieldFormatEditor', () => { it('should render normally', async () => { const component = shallow( { - return TestEditor; - }, - }} + fieldFormatEditors={formatEditors} onChange={() => {}} onError={() => {}} /> @@ -56,14 +60,10 @@ describe('FieldFormatEditor', () => { const component = shallow( { - return null; - }, - }} + fieldFormatEditors={formatEditors} onChange={() => {}} onError={() => {}} /> diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.js b/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.tsx similarity index 54% rename from src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.tsx index 204554ad94644..2de6dff5d251a 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/field_format_editor.tsx @@ -18,29 +18,44 @@ */ import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; +import { DefaultFormatEditor } from '../../components/field_format_editor/editors/default'; -export class FieldFormatEditor extends PureComponent { - static propTypes = { - fieldType: PropTypes.string.isRequired, - fieldFormat: PropTypes.object.isRequired, - fieldFormatId: PropTypes.string.isRequired, - fieldFormatParams: PropTypes.object.isRequired, - fieldFormatEditors: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - onError: PropTypes.func.isRequired, - }; +export interface FieldFormatEditorProps { + fieldType: string; + fieldFormat: DefaultFormatEditor; + fieldFormatId: string; + fieldFormatParams: { [key: string]: unknown }; + fieldFormatEditors: any; + onChange: (change: { fieldType: string; [key: string]: any }) => void; + onError: (error?: string) => void; +} + +interface EditorComponentProps { + fieldType: FieldFormatEditorProps['fieldType']; + format: FieldFormatEditorProps['fieldFormat']; + formatParams: FieldFormatEditorProps['fieldFormatParams']; + onChange: FieldFormatEditorProps['onChange']; + onError: FieldFormatEditorProps['onError']; +} + +interface FieldFormatEditorState { + EditorComponent: React.FC; +} - constructor(props) { +export class FieldFormatEditor extends PureComponent< + FieldFormatEditorProps, + FieldFormatEditorState +> { + constructor(props: FieldFormatEditorProps) { super(props); this.state = { - EditorComponent: null, + EditorComponent: props.fieldFormatEditors.byFormatId[props.fieldFormatId], }; } - static getDerivedStateFromProps(nextProps) { + static getDerivedStateFromProps(nextProps: FieldFormatEditorProps) { return { - EditorComponent: nextProps.fieldFormatEditors.getEditor(nextProps.fieldFormatId) || null, + EditorComponent: nextProps.fieldFormatEditors.byFormatId[nextProps.fieldFormatId] || null, }; } diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/index.js b/src/legacy/ui/public/field_editor/components/field_format_editor/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/index.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/index.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/register.js b/src/legacy/ui/public/field_editor/components/field_format_editor/register.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/register.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/register.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.js.snap b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.tsx.snap similarity index 97% rename from src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.js.snap rename to src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.tsx.snap index 73a7c1141c601..2883ffb6bc8a1 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/__snapshots__/samples.test.tsx.snap @@ -41,7 +41,7 @@ exports[`FormatEditorSamples should render normally 1`] = ` }, Object { "input": 123, - "output": 456, + "output": "456", }, Object { "input": Array [ diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/index.js b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/field_format_editor/samples/index.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/samples/index.ts diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.js b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.tsx similarity index 97% rename from src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.tsx index 8e18f1f5f4de8..01f405e9aff1f 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.test.tsx @@ -28,7 +28,7 @@ describe('FormatEditorSamples', () => { foo, bar' }, ]} /> diff --git a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.js b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.tsx similarity index 81% rename from src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.js rename to src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.tsx index b3345f085882c..d63674bf4d205 100644 --- a/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.js +++ b/src/legacy/ui/public/field_editor/components/field_format_editor/samples/samples.tsx @@ -18,26 +18,22 @@ */ import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; import { EuiBasicTable, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { Sample } from '../../../types'; -export class FormatEditorSamples extends PureComponent { +interface FormatEditorSamplesProps { + samples: Sample[]; + sampleType: string; +} + +export class FormatEditorSamples extends PureComponent { static defaultProps = { sampleType: 'text', }; - static propTypes = { - samples: PropTypes.arrayOf( - PropTypes.shape({ - input: PropTypes.any.isRequired, - output: PropTypes.any.isRequired, - }) - ).isRequired, - sampleType: PropTypes.oneOf(['html', 'text']), - }; render() { const { samples, sampleType } = this.props; @@ -48,7 +44,7 @@ export class FormatEditorSamples extends PureComponent { name: i18n.translate('common.ui.fieldEditor.samples.inputHeader', { defaultMessage: 'Input', }), - render: input => { + render: (input: {} | string) => { return typeof input === 'object' ? JSON.stringify(input) : input; }, }, @@ -57,14 +53,14 @@ export class FormatEditorSamples extends PureComponent { name: i18n.translate('common.ui.fieldEditor.samples.outputHeader', { defaultMessage: 'Output', }), - render: output => { + render: (output: string) => { return sampleType === 'html' ? (

) : (
{output}
@@ -79,7 +75,7 @@ export class FormatEditorSamples extends PureComponent { } > - className="kbnFieldFormatEditor__samples" compressed={true} items={samples} diff --git a/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/disabled_call_out.test.js.snap b/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/disabled_call_out.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/disabled_call_out.test.js.snap rename to src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/disabled_call_out.test.tsx.snap diff --git a/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.js.snap b/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.tsx.snap similarity index 94% rename from src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.js.snap rename to src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.tsx.snap index f09ea05f6711a..b331c1e38eb34 100644 --- a/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.js.snap +++ b/src/legacy/ui/public/field_editor/components/scripting_call_outs/__snapshots__/warning_call_out.test.tsx.snap @@ -20,7 +20,6 @@ exports[`ScriptingWarningCallOut should render normally 1`] = ` values={ Object { "scripFields": , "scriptsInAggregation": ({ - getDocLink: doc => `(docLink for ${doc})`, -})); - -jest.mock('./test_script', () => ({ - TestScript: () => { - return `
mockTestScript
`; - }, -})); - -const indexPatternMock = {}; - -describe('ScriptingHelpFlyout', () => { +describe('ScriptingWarningCallOut', () => { + const docLinksScriptedFields = docLinksServiceMock.createStartContract().links.scriptedFields; it('should render normally', async () => { const component = shallow( - {}} + docLinksScriptedFields={{} as typeof docLinksScriptedFields} /> ); @@ -50,10 +39,9 @@ describe('ScriptingHelpFlyout', () => { it('should render nothing if not visible', async () => { const component = shallow( - {}} + ); diff --git a/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.js b/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.tsx similarity index 85% rename from src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.js rename to src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.tsx index b810541d72697..7dac6681fa1ea 100644 --- a/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.js +++ b/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.tsx @@ -18,13 +18,21 @@ */ import React, { Fragment } from 'react'; -import { getDocLink } from 'ui/documentation_links'; +import { DocLinksStart } from 'src/core/public'; import { EuiCallOut, EuiIcon, EuiLink, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -export const ScriptingWarningCallOut = ({ isVisible = false }) => { +export interface ScriptingWarningCallOutProps { + isVisible: boolean; + docLinksScriptedFields: DocLinksStart['links']['scriptedFields']; +} + +export const ScriptingWarningCallOut = ({ + isVisible = false, + docLinksScriptedFields, +}: ScriptingWarningCallOutProps) => { return isVisible ? ( { defaultMessage="Please familiarize yourself with {scripFields} and with {scriptsInAggregation} before using scripted fields." values={{ scripFields: ( - + { ), scriptsInAggregation: ( - + - - , - "data-test-subj": "syntaxTab", - "id": "syntax", - "name": "Syntax", - } - } - tabs={ - Array [ - Object { - "content": , - "data-test-subj": "syntaxTab", - "id": "syntax", - "name": "Syntax", - }, - Object { - "content": , - "data-test-subj": "testTab", - "id": "test", - "name": "Preview results", - }, - ] - } - /> - - -`; - -exports[`ScriptingHelpFlyout should render nothing if not visible 1`] = `""`; diff --git a/src/legacy/ui/public/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap b/src/legacy/ui/public/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap new file mode 100644 index 0000000000000..282e8e311d984 --- /dev/null +++ b/src/legacy/ui/public/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ScriptingHelpFlyout should render normally 1`] = ` + + + , + "data-test-subj": "syntaxTab", + "id": "syntax", + "name": "Syntax", + } + } + tabs={ + Array [ + Object { + "content": , + "data-test-subj": "syntaxTab", + "id": "syntax", + "name": "Syntax", + }, + Object { + "content": , + "data-test-subj": "testTab", + "id": "test", + "name": "Preview results", + }, + ] + } + /> + + +`; + +exports[`ScriptingHelpFlyout should render nothing if not visible 1`] = ` + + + , + "data-test-subj": "syntaxTab", + "id": "syntax", + "name": "Syntax", + } + } + tabs={ + Array [ + Object { + "content": , + "data-test-subj": "syntaxTab", + "id": "syntax", + "name": "Syntax", + }, + Object { + "content": , + "data-test-subj": "testTab", + "id": "test", + "name": "Preview results", + }, + ] + } + /> + + +`; diff --git a/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.test.tsx b/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.test.tsx new file mode 100644 index 0000000000000..4106eb7b283ee --- /dev/null +++ b/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.test.tsx @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { HttpStart } from 'src/core/public'; +// eslint-disable-next-line +import { docLinksServiceMock } from '../../../../../../core/public/doc_links/doc_links_service.mock'; + +import { ScriptingHelpFlyout } from './help_flyout'; + +import { IndexPattern } from '../../../../../../plugins/data/public'; + +import { ExecuteScript } from '../../types'; + +jest.mock('./test_script', () => ({ + TestScript: () => { + return `
mockTestScript
`; + }, +})); + +const indexPatternMock = {} as IndexPattern; + +describe('ScriptingHelpFlyout', () => { + const docLinksScriptedFields = docLinksServiceMock.createStartContract().links.scriptedFields; + it('should render normally', async () => { + const component = shallow( + {}) as unknown) as ExecuteScript} + onClose={() => {}} + getHttpStart={() => (({} as unknown) as HttpStart)} + // docLinksScriptedFields={docLinksScriptedFields} + docLinksScriptedFields={{} as typeof docLinksScriptedFields} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + it('should render nothing if not visible', async () => { + const component = shallow( + {}) as unknown) as ExecuteScript} + onClose={() => {}} + getHttpStart={() => (({} as unknown) as HttpStart)} + docLinksScriptedFields={{} as typeof docLinksScriptedFields} + /> + ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.js b/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.tsx similarity index 72% rename from src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.js rename to src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.tsx index c512b5f5f2019..6f51379c796d4 100644 --- a/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.js +++ b/src/legacy/ui/public/field_editor/components/scripting_help/help_flyout.tsx @@ -18,14 +18,29 @@ */ import React from 'react'; -import PropTypes from 'prop-types'; +import { HttpStart, DocLinksStart } from 'src/core/public'; import { EuiFlyout, EuiFlyoutBody, EuiTabbedContent } from '@elastic/eui'; import { ScriptingSyntax } from './scripting_syntax'; import { TestScript } from './test_script'; -export const ScriptingHelpFlyout = ({ +import { IndexPattern } from '../../../../../../plugins/data/public'; +import { ExecuteScript } from '../../types'; + +interface ScriptingHelpFlyoutProps { + indexPattern: IndexPattern; + lang: string; + name?: string; + script?: string; + executeScript: ExecuteScript; + isVisible: boolean; + onClose: () => void; + getHttpStart: () => HttpStart; + docLinksScriptedFields: DocLinksStart['links']['scriptedFields']; +} + +export const ScriptingHelpFlyout: React.FC = ({ isVisible = false, onClose = () => {}, indexPattern, @@ -33,13 +48,15 @@ export const ScriptingHelpFlyout = ({ name, script, executeScript, + getHttpStart, + docLinksScriptedFields, }) => { const tabs = [ { id: 'syntax', name: 'Syntax', ['data-test-subj']: 'syntaxTab', - content: , + content: , }, { id: 'test', @@ -52,6 +69,7 @@ export const ScriptingHelpFlyout = ({ name={name} script={script} executeScript={executeScript} + getHttpStart={getHttpStart} /> ), }, @@ -67,11 +85,3 @@ export const ScriptingHelpFlyout = ({ }; ScriptingHelpFlyout.displayName = 'ScriptingHelpFlyout'; - -ScriptingHelpFlyout.propTypes = { - indexPattern: PropTypes.object.isRequired, - lang: PropTypes.string.isRequired, - name: PropTypes.string, - script: PropTypes.string, - executeScript: PropTypes.func.isRequired, -}; diff --git a/src/legacy/ui/public/field_editor/components/scripting_help/index.js b/src/legacy/ui/public/field_editor/components/scripting_help/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/components/scripting_help/index.js rename to src/legacy/ui/public/field_editor/components/scripting_help/index.ts diff --git a/src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.js b/src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.tsx similarity index 92% rename from src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.js rename to src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.tsx index ba47b94aaea0c..8158c6881acf9 100644 --- a/src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.js +++ b/src/legacy/ui/public/field_editor/components/scripting_help/scripting_syntax.tsx @@ -18,13 +18,17 @@ */ import React, { Fragment } from 'react'; -import { getDocLink } from 'ui/documentation_links'; +import { DocLinksStart } from 'src/core/public'; import { EuiCode, EuiIcon, EuiLink, EuiText, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -export const ScriptingSyntax = () => ( +export interface ScriptingSyntaxProps { + docLinksScriptedFields: DocLinksStart['links']['scriptedFields']; +} + +export const ScriptingSyntax = ({ docLinksScriptedFields }: ScriptingSyntaxProps) => ( @@ -38,7 +42,7 @@ export const ScriptingSyntax = () => ( specifically for use with Elasticsearch, to access values in the document use the following format:" values={{ painless: ( - + ( you'll be up to speed in no time!" values={{ javaAPIs: ( - + ( ), syntax: ( - + ( are a lot like JavaScript, but limited to basic arithmetic, bitwise and comparison operations." values={{ lucene: ( - + HttpStart; +} + +interface AdditionalField { + value: string; + label: string; +} + +interface TestScriptState { + isLoading: boolean; + additionalFields: AdditionalField[]; + previewData?: Record; +} + +export class TestScript extends Component { + defaultProps = { + name: 'myScriptedField', + }; -export class TestScript extends Component { state = { isLoading: false, additionalFields: [], + previewData: undefined, }; componentDidMount() { @@ -52,8 +79,8 @@ export class TestScript extends Component { } } - previewScript = async searchContext => { - const { indexPattern, lang, name, script, executeScript } = this.props; + previewScript = async (searchContext?: { query?: Query | undefined }) => { + const { indexPattern, lang, name, script, executeScript, getHttpStart } = this.props; if (!script || script.length === 0) { return; @@ -68,21 +95,20 @@ export class TestScript extends Component { const esQueryConfigs = esQuery.getEsQueryConfig(uiSettings); query = esQuery.buildEsQuery( this.props.indexPattern, - searchContext.query, - null, + searchContext.query || [], + [], esQueryConfigs ); } const scriptResponse = await executeScript({ - name, + name: name as string, lang, script, indexPatternTitle: indexPattern.title, query, - additionalFields: this.state.additionalFields.map(option => { - return option.value; - }), + additionalFields: this.state.additionalFields.map((option: AdditionalField) => option.value), + getHttpStart, }); if (scriptResponse.status !== 200) { @@ -103,15 +129,13 @@ export class TestScript extends Component { }); }; - onAdditionalFieldsChange = selectedOptions => { + onAdditionalFieldsChange = (selectedOptions: AdditionalField[]) => { this.setState({ additionalFields: selectedOptions, }); }; - renderPreview() { - const { previewData } = this.state; - + renderPreview(previewData: { error: any } | undefined) { if (!previewData) { return null; } @@ -160,7 +184,7 @@ export class TestScript extends Component { renderToolbar() { const fieldsByTypeMap = new Map(); - const fields = []; + const fields: EuiComboBoxOptionOption[] = []; this.props.indexPattern.fields .filter(field => { @@ -180,7 +204,7 @@ export class TestScript extends Component { fieldsByTypeMap.forEach((fieldsList, fieldType) => { fields.push({ label: fieldType, - options: fieldsList.sort().map(fieldName => { + options: fieldsList.sort().map((fieldName: string) => { return { value: fieldName, label: fieldName }; }), }); @@ -206,7 +230,7 @@ export class TestScript extends Component { })} options={fields} selectedOptions={this.state.additionalFields} - onChange={this.onAdditionalFieldsChange} + onChange={selected => this.onAdditionalFieldsChange(selected as AdditionalField[])} data-test-subj="additionalFieldsSelect" fullWidth /> @@ -214,6 +238,7 @@ export class TestScript extends Component {
{this.renderToolbar()} - {this.renderPreview()} + {this.renderPreview(this.state.previewData)} ); } } - -TestScript.propTypes = { - indexPattern: PropTypes.object.isRequired, - lang: PropTypes.string.isRequired, - name: PropTypes.string, - script: PropTypes.string, - executeScript: PropTypes.func.isRequired, -}; - -TestScript.defaultProps = { - name: 'myScriptedField', -}; diff --git a/src/legacy/ui/public/field_editor/constants/index.js b/src/legacy/ui/public/field_editor/constants/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/constants/index.js rename to src/legacy/ui/public/field_editor/constants/index.ts diff --git a/src/legacy/ui/public/field_editor/field_editor.test.js b/src/legacy/ui/public/field_editor/field_editor.test.tsx similarity index 69% rename from src/legacy/ui/public/field_editor/field_editor.test.js rename to src/legacy/ui/public/field_editor/field_editor.test.tsx index cf61b6140f42c..5716305b51483 100644 --- a/src/legacy/ui/public/field_editor/field_editor.test.js +++ b/src/legacy/ui/public/field_editor/field_editor.test.tsx @@ -17,12 +17,19 @@ * under the License. */ -jest.mock('ui/kfetch', () => ({})); - import React from 'react'; import { npStart } from 'ui/new_platform'; import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; +import { + Field, + IndexPattern, + IndexPatternFieldList, + FieldFormatInstanceType, +} from 'src/plugins/data/public'; +import { HttpStart } from '../../../../core/public'; +// eslint-disable-next-line +import { docLinksServiceMock } from '../../../../core/public/doc_links/doc_links_service.mock'; jest.mock('brace/mode/groovy', () => ({})); jest.mock('ui/new_platform'); @@ -54,23 +61,11 @@ jest.mock('@elastic/eui', () => ({ })); jest.mock('ui/scripting_languages', () => ({ - GetEnabledScriptingLanguagesProvider: jest - .fn() - .mockImplementation(() => () => ['painless', 'testlang']), + getEnabledScriptingLanguages: () => ['painless', 'testlang'], getSupportedScriptingLanguages: () => ['painless'], getDeprecatedScriptingLanguages: () => ['testlang'], })); -jest.mock('ui/documentation_links', () => ({ - getDocLink: doc => `(docLink for ${doc})`, -})); - -jest.mock('ui/notify', () => ({ - toastNotifications: { - addSuccess: jest.fn(), - }, -})); - jest.mock('./components/scripting_call_outs', () => ({ ScriptingDisabledCallOut: 'scripting-disabled-callOut', ScriptingWarningCallOut: 'scripting-warning-callOut', @@ -81,18 +76,15 @@ jest.mock('./components/field_format_editor', () => ({ FieldFormatEditor: 'field-format-editor', })); -const fields = [ +const fields: Field[] = [ { name: 'foobar', - }, + } as Field, ]; -fields.getByName = name => { - const fields = { - foobar: { - name: 'foobar', - }, - }; - return fields[name]; + +// @ts-ignore +fields.getByName = (name: string) => { + return fields.find(field => field.name === name); }; class Format { @@ -111,30 +103,39 @@ const field = { const helpers = { Field: () => {}, getConfig: () => {}, - $http: () => {}, - fieldFormatEditors: {}, + getHttpStart: () => (({} as unknown) as HttpStart), + fieldFormatEditors: [], redirectAway: () => {}, + docLinksScriptedFields: docLinksServiceMock.createStartContract().links.scriptedFields, }; describe('FieldEditor', () => { - let indexPattern; + let indexPattern: IndexPattern; beforeEach(() => { - indexPattern = { - fields, - }; + indexPattern = ({ + fields: fields as IndexPatternFieldList, + } as unknown) as IndexPattern; - npStart.plugins.data.fieldFormats.getDefaultType = jest.fn(() => Format); + npStart.plugins.data.fieldFormats.getDefaultType = jest.fn( + () => (({} as unknown) as FieldFormatInstanceType) + ); npStart.plugins.data.fieldFormats.getByFieldType = jest.fn(fieldType => { if (fieldType === 'number') { - return [Format]; + return [({} as unknown) as FieldFormatInstanceType]; + } else { + return []; } }); }); it('should render create new scripted field correctly', async () => { const component = shallowWithI18nProvider( - + ); await new Promise(resolve => process.nextTick(resolve)); @@ -148,16 +149,20 @@ describe('FieldEditor', () => { name: 'test', script: 'doc.test.value', }; - indexPattern.fields.push(testField); + indexPattern.fields.push(testField as Field); indexPattern.fields.getByName = name => { - const fields = { + const flds = { [testField.name]: testField, }; - return fields[name]; + return flds[name] as Field; }; const component = shallowWithI18nProvider( - + ); await new Promise(resolve => process.nextTick(resolve)); @@ -172,16 +177,20 @@ describe('FieldEditor', () => { script: 'doc.test.value', lang: 'testlang', }; - indexPattern.fields.push(testField); + indexPattern.fields.push((testField as unknown) as Field); indexPattern.fields.getByName = name => { - const fields = { + const flds = { [testField.name]: testField, }; - return fields[name]; + return flds[name] as Field; }; const component = shallowWithI18nProvider( - + ); await new Promise(resolve => process.nextTick(resolve)); @@ -192,11 +201,15 @@ describe('FieldEditor', () => { it('should show conflict field warning', async () => { const testField = { ...field }; const component = shallowWithI18nProvider( - + ); await new Promise(resolve => process.nextTick(resolve)); - component.instance().onFieldChange('name', 'foobar'); + (component.instance() as FieldEditor).onFieldChange('name', 'foobar'); component.update(); expect(component).toMatchSnapshot(); }); @@ -211,11 +224,15 @@ describe('FieldEditor', () => { }, }; const component = shallowWithI18nProvider( - + ); await new Promise(resolve => process.nextTick(resolve)); - component.instance().onFieldChange('name', 'foobar'); + (component.instance() as FieldEditor).onFieldChange('name', 'foobar'); component.update(); expect(component).toMatchSnapshot(); }); diff --git a/src/legacy/ui/public/field_editor/field_editor.js b/src/legacy/ui/public/field_editor/field_editor.tsx similarity index 83% rename from src/legacy/ui/public/field_editor/field_editor.js rename to src/legacy/ui/public/field_editor/field_editor.tsx index e90cb110ac304..aa62a53f2c32a 100644 --- a/src/legacy/ui/public/field_editor/field_editor.js +++ b/src/legacy/ui/public/field_editor/field_editor.tsx @@ -18,19 +18,15 @@ */ import React, { PureComponent, Fragment } from 'react'; -import PropTypes from 'prop-types'; import { intersection, union, get } from 'lodash'; +import { HttpStart, DocLinksStart } from 'src/core/public'; import { - GetEnabledScriptingLanguagesProvider, + getEnabledScriptingLanguages, getDeprecatedScriptingLanguages, getSupportedScriptingLanguages, } from 'ui/scripting_languages'; -import { getDocLink } from 'ui/documentation_links'; - -import { toastNotifications } from 'ui/notify'; - import { npStart } from 'ui/new_platform'; import { @@ -56,6 +52,16 @@ import { EUI_MODAL_CONFIRM_BUTTON, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + IndexPattern, + IFieldType, + KBN_FIELD_TYPES, + ES_FIELD_TYPES, +} from '../../../../plugins/data/public'; +import { FieldFormatInstanceType } from '../../../../plugins/data/common'; +import { Field } from '../../../../plugins/data/public'; import { ScriptingDisabledCallOut, ScriptingWarningCallOut, @@ -65,23 +71,27 @@ import { ScriptingHelpFlyout } from './components/scripting_help'; import { FieldFormatEditor } from './components/field_format_editor'; +import { DefaultFormatEditor } from './components/field_format_editor/editors/default'; + import { FIELD_TYPES_BY_LANG, DEFAULT_FIELD_TYPES } from './constants'; import { executeScript, isScriptValid } from './lib'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - // This loads Ace editor's "groovy" mode, used below to highlight the script. import 'brace/mode/groovy'; const getFieldFormats = () => npStart.plugins.data.fieldFormats; -const getFieldTypeFormatsList = (field, defaultFieldFormat) => { +const getFieldTypeFormatsList = ( + field: IFieldType, + defaultFieldFormat: FieldFormatInstanceType +) => { const fieldFormats = getFieldFormats(); - const formatsByType = fieldFormats.getByFieldType(field.type).map(({ id, title }) => ({ - id, - title, - })); + const formatsByType = fieldFormats + .getByFieldType(field.type as KBN_FIELD_TYPES) + .map(({ id, title }) => ({ + id, + title, + })); return [ { @@ -95,19 +105,54 @@ const getFieldTypeFormatsList = (field, defaultFieldFormat) => { ]; }; -export class FieldEditor extends PureComponent { - static propTypes = { - indexPattern: PropTypes.object.isRequired, - field: PropTypes.object.isRequired, - helpers: PropTypes.shape({ - getConfig: PropTypes.func.isRequired, - $http: PropTypes.func.isRequired, - fieldFormatEditors: PropTypes.object.isRequired, - redirectAway: PropTypes.func.isRequired, - }), +interface FieldTypeFormat { + id: string; + title: string; +} + +interface InitialFieldTypeFormat extends FieldTypeFormat { + defaultFieldFormat: FieldFormatInstanceType; +} + +interface FieldClone extends Field { + format: any; +} + +export interface FieldEditorState { + isReady: boolean; + isCreating: boolean; + isDeprecatedLang: boolean; + scriptingLangs: string[]; + fieldTypes: string[]; + fieldTypeFormats: FieldTypeFormat[]; + existingFieldNames: string[]; + field: FieldClone; + fieldFormatId?: string; + fieldFormatParams: { [key: string]: unknown }; + showScriptingHelp: boolean; + showDeleteModal: boolean; + hasFormatError: boolean; + hasScriptError: boolean; + isSaving: boolean; + errors?: string[]; +} + +export interface FieldEdiorProps { + indexPattern: IndexPattern; + field: Field; + helpers: { + getConfig: (key: string) => any; + getHttpStart: () => HttpStart; + fieldFormatEditors: DefaultFormatEditor[]; + redirectAway: () => void; + docLinksScriptedFields: DocLinksStart['links']['scriptedFields']; }; +} - constructor(props) { +export class FieldEditor extends PureComponent { + supportedLangs: string[] = []; + deprecatedLangs: string[] = []; + constructor(props: FieldEdiorProps) { super(props); const { field, indexPattern } = props; @@ -119,7 +164,7 @@ export class FieldEditor extends PureComponent { scriptingLangs: [], fieldTypes: [], fieldTypeFormats: [], - existingFieldNames: indexPattern.fields.map(f => f.name), + existingFieldNames: indexPattern.fields.map((f: IFieldType) => f.name), field: { ...field, format: field.format }, fieldFormatId: undefined, fieldFormatParams: {}, @@ -135,48 +180,53 @@ export class FieldEditor extends PureComponent { } async init() { - const { $http } = this.props.helpers; + const { getHttpStart } = this.props.helpers; const { field } = this.state; const { indexPattern } = this.props; - const getEnabledScriptingLanguages = new GetEnabledScriptingLanguagesProvider($http); - const enabledLangs = await getEnabledScriptingLanguages(); + const enabledLangs = await getEnabledScriptingLanguages(await getHttpStart()); const scriptingLangs = intersection( enabledLangs, union(this.supportedLangs, this.deprecatedLangs) ); - field.lang = scriptingLangs.includes(field.lang) ? field.lang : undefined; + field.lang = field.lang && scriptingLangs.includes(field.lang) ? field.lang : undefined; - const fieldTypes = get(FIELD_TYPES_BY_LANG, field.lang, DEFAULT_FIELD_TYPES); + const fieldTypes = get(FIELD_TYPES_BY_LANG, field.lang || '', DEFAULT_FIELD_TYPES); field.type = fieldTypes.includes(field.type) ? field.type : fieldTypes[0]; const fieldFormats = getFieldFormats(); - const DefaultFieldFormat = fieldFormats.getDefaultType(field.type, field.esTypes); + const DefaultFieldFormat = fieldFormats.getDefaultType( + field.type as KBN_FIELD_TYPES, + field.esTypes as ES_FIELD_TYPES[] + ); this.setState({ isReady: true, - isCreating: !indexPattern.fields.getByName(field.name), - isDeprecatedLang: this.deprecatedLangs.includes(field.lang), + isCreating: !indexPattern.fields.find(f => f.name === field.name), + isDeprecatedLang: this.deprecatedLangs.includes(field.lang || ''), errors: [], scriptingLangs, fieldTypes, - fieldTypeFormats: getFieldTypeFormatsList(field, DefaultFieldFormat), + fieldTypeFormats: getFieldTypeFormatsList( + field, + DefaultFieldFormat as FieldFormatInstanceType + ), fieldFormatId: get(indexPattern, ['fieldFormatMap', field.name, 'type', 'id']), fieldFormatParams: field.format.params(), }); } - onFieldChange = (fieldName, value) => { + onFieldChange = (fieldName: string, value: string | number) => { const { field } = this.state; - field[fieldName] = value; + (field as any)[fieldName] = value; this.forceUpdate(); }; - onTypeChange = type => { + onTypeChange = (type: KBN_FIELD_TYPES) => { const { getConfig } = this.props.helpers; const { field } = this.state; const fieldFormats = getFieldFormats(); - const DefaultFieldFormat = fieldFormats.getDefaultType(type); + const DefaultFieldFormat = fieldFormats.getDefaultType(type) as FieldFormatInstanceType; field.type = type; field.format = new DefaultFieldFormat(null, getConfig); @@ -188,7 +238,7 @@ export class FieldEditor extends PureComponent { }); }; - onLangChange = lang => { + onLangChange = (lang: string) => { const { field } = this.state; const fieldTypes = get(FIELD_TYPES_BY_LANG, lang, DEFAULT_FIELD_TYPES); field.lang = lang; @@ -199,12 +249,12 @@ export class FieldEditor extends PureComponent { }); }; - onFormatChange = (formatId, params) => { + onFormatChange = (formatId: string, params?: any) => { const fieldFormats = getFieldFormats(); const { field, fieldTypeFormats } = this.state; const FieldFormat = fieldFormats.getType( - formatId || fieldTypeFormats[0]?.defaultFieldFormat.id - ); + formatId || (fieldTypeFormats[0] as InitialFieldTypeFormat).defaultFieldFormat.id + ) as FieldFormatInstanceType; field.format = new FieldFormat(params, this.props.helpers.getConfig); @@ -214,12 +264,12 @@ export class FieldEditor extends PureComponent { }); }; - onFormatParamsChange = newParams => { + onFormatParamsChange = (newParams: { fieldType: string; [key: string]: any }) => { const { fieldFormatId } = this.state; - this.onFormatChange(fieldFormatId, newParams); + this.onFormatChange(fieldFormatId as string, newParams); }; - onFormatParamsError = error => { + onFormatParamsError = (error?: string) => { this.setState({ hasFormatError: !!error, }); @@ -312,7 +362,10 @@ export class FieldEditor extends PureComponent { values={{ language: {field.lang}, painlessLink: ( - + { - this.onTypeChange(e.target.value); + this.onTypeChange(e.target.value as KBN_FIELD_TYPES); }} /> @@ -366,7 +419,7 @@ export class FieldEditor extends PureComponent { * in case there are indices with different types */ renderTypeConflict() { - const { field = {} } = this.state; + const { field } = this.state; if (!field.conflictDescriptions || typeof field.conflictDescriptions !== 'object') { return null; } @@ -420,7 +473,7 @@ export class FieldEditor extends PureComponent { renderFormat() { const { field, fieldTypeFormats, fieldFormatId, fieldFormatParams } = this.state; const { fieldFormatEditors } = this.props.helpers; - const defaultFormat = fieldTypeFormats[0]?.defaultFieldFormat.title; + const defaultFormat = (fieldTypeFormats[0] as InitialFieldTypeFormat).defaultFieldFormat.title; const label = defaultFormat ? ( { + onScriptChange = (value: string) => { this.setState({ hasScriptError: false, }); @@ -690,15 +743,20 @@ export class FieldEditor extends PureComponent { return ( - + ); @@ -716,7 +774,7 @@ export class FieldEditor extends PureComponent { defaultMessage: "Deleted '{fieldName}'", values: { fieldName: field.name }, }); - toastNotifications.addSuccess(message); + npStart.core.notifications.toasts.addSuccess(message); redirectAway(); }); } else { @@ -736,9 +794,10 @@ export class FieldEditor extends PureComponent { const isValid = await isScriptValid({ name: field.name, - lang: field.lang, - script: field.script, + lang: field.lang as string, + script: field.script as string, indexPatternTitle: indexPattern.title, + getHttpStart: this.props.helpers.getHttpStart, }); if (!isValid) { @@ -751,7 +810,7 @@ export class FieldEditor extends PureComponent { } const { redirectAway } = this.props.helpers; - const index = indexPattern.fields.findIndex(f => f.name === field.name); + const index = indexPattern.fields.findIndex((f: IFieldType) => f.name === field.name); if (index > -1) { indexPattern.fields.update(field); @@ -770,7 +829,7 @@ export class FieldEditor extends PureComponent { defaultMessage: "Saved '{fieldName}'", values: { fieldName: field.name }, }); - toastNotifications.addSuccess(message); + npStart.core.notifications.toasts.addSuccess(message); redirectAway(); }); }; diff --git a/src/legacy/ui/public/field_editor/index.js b/src/legacy/ui/public/field_editor/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/index.js rename to src/legacy/ui/public/field_editor/index.ts diff --git a/src/legacy/ui/public/field_editor/lib/index.js b/src/legacy/ui/public/field_editor/lib/index.ts similarity index 100% rename from src/legacy/ui/public/field_editor/lib/index.js rename to src/legacy/ui/public/field_editor/lib/index.ts diff --git a/src/legacy/ui/public/field_editor/lib/validate_script.js b/src/legacy/ui/public/field_editor/lib/validate_script.ts similarity index 67% rename from src/legacy/ui/public/field_editor/lib/validate_script.js rename to src/legacy/ui/public/field_editor/lib/validate_script.ts index 47e2091565c30..4db827a4229fd 100644 --- a/src/legacy/ui/public/field_editor/lib/validate_script.js +++ b/src/legacy/ui/public/field_editor/lib/validate_script.ts @@ -17,7 +17,9 @@ * under the License. */ -import { kfetch } from 'ui/kfetch'; +import { Query } from 'src/plugins/data/public'; +import { HttpStart } from 'src/core/public'; +import { ExecuteScriptParams, ExecuteScriptResult } from '../types'; export const executeScript = async ({ name, @@ -26,7 +28,8 @@ export const executeScript = async ({ indexPatternTitle, query, additionalFields = [], -}) => { + getHttpStart, +}: ExecuteScriptParams): Promise => { // Using _msearch because _search with index name in path dorks everything up const header = { index: indexPatternTitle, @@ -36,7 +39,7 @@ export const executeScript = async ({ const search = { query: { match_all: {}, - }, + } as Query['query'], script_fields: { [name]: { script: { @@ -45,6 +48,7 @@ export const executeScript = async ({ }, }, }, + _source: undefined as string[] | undefined, size: 10, timeout: '30s', }; @@ -58,13 +62,32 @@ export const executeScript = async ({ } const body = `${JSON.stringify(header)}\n${JSON.stringify(search)}\n`; - const esResp = await kfetch({ method: 'POST', pathname: '/elasticsearch/_msearch', body }); + const http = await getHttpStart(); + const esResp = await http.fetch('/elasticsearch/_msearch', { method: 'POST', body }); // unwrap _msearch response return esResp.responses[0]; }; -export const isScriptValid = async ({ name, lang, script, indexPatternTitle }) => { - const scriptResponse = await executeScript({ name, lang, script, indexPatternTitle }); +export const isScriptValid = async ({ + name, + lang, + script, + indexPatternTitle, + getHttpStart, +}: { + name: string; + lang: string; + script: string; + indexPatternTitle: string; + getHttpStart: () => HttpStart; +}) => { + const scriptResponse = await executeScript({ + name, + lang, + script, + indexPatternTitle, + getHttpStart, + }); if (scriptResponse.status !== 200) { return false; diff --git a/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.test.js b/src/legacy/ui/public/field_editor/types.ts similarity index 56% rename from src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.test.js rename to src/legacy/ui/public/field_editor/types.ts index 48094f63f8fe8..174cb7da73ceb 100644 --- a/src/legacy/ui/public/field_editor/components/scripting_call_outs/warning_call_out.test.js +++ b/src/legacy/ui/public/field_editor/types.ts @@ -17,25 +17,29 @@ * under the License. */ -import React from 'react'; -import { shallow } from 'enzyme'; +import { ReactText } from 'react'; +import { Query } from 'src/plugins/data/public'; +import { HttpStart } from 'src/core/public'; -import { ScriptingWarningCallOut } from './warning_call_out'; +export interface Sample { + input: ReactText | ReactText[]; + output: string; +} -jest.mock('ui/documentation_links', () => ({ - getDocLink: doc => `(docLink for ${doc})`, -})); +export interface ExecuteScriptParams { + name: string; + lang: string; + script: string; + indexPatternTitle: string; + query?: Query['query']; + additionalFields?: string[]; + getHttpStart: () => HttpStart; +} -describe('ScriptingWarningCallOut', () => { - it('should render normally', async () => { - const component = shallow(); +export interface ExecuteScriptResult { + status: number; + hits: { hits: any[] }; + error?: any; +} - expect(component).toMatchSnapshot(); - }); - - it('should render nothing if not visible', async () => { - const component = shallow(); - - expect(component).toMatchSnapshot(); - }); -}); +export type ExecuteScript = (params: ExecuteScriptParams) => Promise; diff --git a/src/legacy/ui/public/registry/field_format_editors.js b/src/legacy/ui/public/registry/field_format_editors.ts similarity index 88% rename from src/legacy/ui/public/registry/field_format_editors.js rename to src/legacy/ui/public/registry/field_format_editors.ts index 85850e56fdb86..5489ce9250e04 100644 --- a/src/legacy/ui/public/registry/field_format_editors.js +++ b/src/legacy/ui/public/registry/field_format_editors.ts @@ -22,9 +22,4 @@ import { uiRegistry } from './_registry'; export const RegistryFieldFormatEditorsProvider = uiRegistry({ name: 'fieldFormatEditors', index: ['formatId'], - constructor: function() { - this.getEditor = function(formatId) { - return this.byFormatId[formatId]; - }; - }, }); diff --git a/src/legacy/ui/public/scripting_languages/index.ts b/src/legacy/ui/public/scripting_languages/index.ts index 283a3273a2a5d..459e72c0c67c1 100644 --- a/src/legacy/ui/public/scripting_languages/index.ts +++ b/src/legacy/ui/public/scripting_languages/index.ts @@ -17,10 +17,8 @@ * under the License. */ -import { IHttpService } from 'angular'; import { i18n } from '@kbn/i18n'; - -import chrome from '../chrome'; +import { HttpStart } from 'src/core/public'; import { toastNotifications } from '../notify'; export function getSupportedScriptingLanguages(): string[] { @@ -31,18 +29,12 @@ export function getDeprecatedScriptingLanguages(): string[] { return []; } -export function GetEnabledScriptingLanguagesProvider($http: IHttpService) { - return () => { - return $http - .get(chrome.addBasePath('/api/kibana/scripts/languages')) - .then((res: any) => res.data) - .catch(() => { - toastNotifications.addDanger( - i18n.translate('common.ui.scriptingLanguages.errorFetchingToastDescription', { - defaultMessage: 'Error getting available scripting languages from Elasticsearch', - }) - ); - return []; - }); - }; -} +export const getEnabledScriptingLanguages = (http: HttpStart) => + http.get('/api/kibana/scripts/languages').catch(() => { + toastNotifications.addDanger( + i18n.translate('common.ui.scriptingLanguages.errorFetchingToastDescription', { + defaultMessage: 'Error getting available scripting languages from Elasticsearch', + }) + ); + return []; + }); diff --git a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx index fb33649093c8d..f8632011002d0 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx +++ b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx @@ -275,6 +275,7 @@ class DashboardGridUi extends React.Component { getEmbeddableFactory={this.props.kibana.services.embeddable.getEmbeddableFactory} getAllEmbeddableFactories={this.props.kibana.services.embeddable.getEmbeddableFactories} overlays={this.props.kibana.services.overlays} + application={this.props.kibana.services.application} notifications={this.props.kibana.services.notifications} inspector={this.props.kibana.services.inspector} SavedObjectFinder={this.props.kibana.services.SavedObjectFinder} diff --git a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx index 836cea298f035..5dab21ff671b4 100644 --- a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx @@ -84,6 +84,7 @@ test('DashboardContainer in edit mode shows edit mode actions', async () => { getAllEmbeddableFactories={(() => []) as any} getEmbeddableFactory={(() => null) as any} notifications={{} as any} + application={{} as any} overlays={{} as any} inspector={inspector} SavedObjectFinder={() => null} diff --git a/src/plugins/data/common/field_formats/field_format.ts b/src/plugins/data/common/field_formats/field_format.ts index 96d0024dff2a2..26f07a12067ce 100644 --- a/src/plugins/data/common/field_formats/field_format.ts +++ b/src/plugins/data/common/field_formats/field_format.ts @@ -127,12 +127,12 @@ export abstract class FieldFormat { */ getConverterFor( contentType: FieldFormatsContentType = DEFAULT_CONTEXT_TYPE - ): FieldFormatConvertFunction | null { + ): FieldFormatConvertFunction { if (!this.convertObject) { this.convertObject = this.setupContentType(); } - return this.convertObject[contentType] || null; + return this.convertObject[contentType]; } /** diff --git a/src/plugins/data/common/field_formats/field_formats_registry.ts b/src/plugins/data/common/field_formats/field_formats_registry.ts index b0a57ad6912a7..2eb9a3e593d1a 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -110,7 +110,7 @@ export class FieldFormatsRegistry { */ getDefaultType = ( fieldType: KBN_FIELD_TYPES, - esTypes: ES_FIELD_TYPES[] + esTypes?: ES_FIELD_TYPES[] ): FieldFormatInstanceType | undefined => { const config = this.getDefaultConfig(fieldType, esTypes); diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e1e2576b2a0e7..60d8079b22347 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -204,11 +204,13 @@ export const fieldFormats = { export { IFieldFormat, + FieldFormatInstanceType, IFieldFormatsRegistry, FieldFormatsContentType, FieldFormatsGetConfigFn, FieldFormatConfig, FieldFormatId, + FieldFormat, } from '../common'; /* @@ -255,6 +257,7 @@ export { AggregationRestrictions as IndexPatternAggRestrictions, // TODO: exported only in stub_index_pattern test. Move into data plugin and remove export. FieldList as IndexPatternFieldList, + Field, } from './index_patterns'; export { diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts index 0fb92393d56f7..d83c0a7d3445e 100644 --- a/src/plugins/data/public/index_patterns/fields/field.ts +++ b/src/plugins/data/public/index_patterns/fields/field.ts @@ -47,6 +47,7 @@ export class Field implements IFieldType { indexPattern?: IndexPattern; format: any; $$spec: FieldSpec; + conflictDescriptions?: Record; constructor( indexPattern: IndexPattern, diff --git a/src/plugins/data/public/index_patterns/fields/field_list.ts b/src/plugins/data/public/index_patterns/fields/field_list.ts index d6067280fd7b6..9772370199b24 100644 --- a/src/plugins/data/public/index_patterns/fields/field_list.ts +++ b/src/plugins/data/public/index_patterns/fields/field_list.ts @@ -29,6 +29,7 @@ export interface IFieldList extends Array { getByType(type: Field['type']): Field[]; add(field: FieldSpec): void; remove(field: IFieldType): void; + update(field: FieldSpec): void; } export class FieldList extends Array implements IFieldList { diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index f5177df022ff2..86560b3ccf7b1 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -451,6 +451,97 @@ export interface FetchOptions { searchStrategyId?: string; } +// Warning: (ae-missing-release-tag) "Field" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +class Field implements IFieldType { + // Warning: (ae-forgotten-export) The symbol "FieldSpec" needs to be exported by the entry point index.d.ts + // + // (undocumented) + $$spec: FieldSpec; + constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable?: boolean); + // (undocumented) + aggregatable?: boolean; + // (undocumented) + conflictDescriptions?: Record; + // (undocumented) + count?: number; + // (undocumented) + displayName?: string; + // (undocumented) + esTypes?: string[]; + // (undocumented) + filterable?: boolean; + // (undocumented) + format: any; + // (undocumented) + indexPattern?: IndexPattern; + // (undocumented) + lang?: string; + // (undocumented) + name: string; + // (undocumented) + script?: string; + // (undocumented) + scripted?: boolean; + // (undocumented) + searchable?: boolean; + // (undocumented) + sortable?: boolean; + // (undocumented) + subType?: IFieldSubType; + // (undocumented) + type: string; + // (undocumented) + visualizable?: boolean; +} + +export { Field } + +export { Field as IndexPatternField } + +// Warning: (ae-missing-release-tag) "FieldFormat" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export abstract class FieldFormat { + // Warning: (ae-forgotten-export) The symbol "IFieldFormatMetaParams" needs to be exported by the entry point index.d.ts + constructor(_params?: IFieldFormatMetaParams, getConfig?: FieldFormatsGetConfigFn); + // Warning: (ae-forgotten-export) The symbol "HtmlContextTypeOptions" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "TextContextTypeOptions" needs to be exported by the entry point index.d.ts + convert(value: any, contentType?: FieldFormatsContentType, options?: HtmlContextTypeOptions | TextContextTypeOptions): string; + // Warning: (ae-forgotten-export) The symbol "FieldFormatConvert" needs to be exported by the entry point index.d.ts + convertObject: FieldFormatConvert | undefined; + static fieldType: string | string[]; + // Warning: (ae-incompatible-release-tags) The symbol "from" is marked as @public, but its signature references "FieldFormatInstanceType" which is marked as @internal + // + // (undocumented) + static from(convertFn: FieldFormatConvertFunction): FieldFormatInstanceType; + // (undocumented) + protected getConfig: FieldFormatsGetConfigFn | undefined; + // Warning: (ae-forgotten-export) The symbol "FieldFormatConvertFunction" needs to be exported by the entry point index.d.ts + getConverterFor(contentType?: FieldFormatsContentType): FieldFormatConvertFunction; + getParamDefaults(): Record; + // Warning: (ae-forgotten-export) The symbol "HtmlContextTypeConvert" needs to be exported by the entry point index.d.ts + htmlConvert: HtmlContextTypeConvert | undefined; + static id: string; + // (undocumented) + static isInstanceOfFieldFormat(fieldFormat: any): fieldFormat is FieldFormat; + param(name: string): any; + params(): Record; + // (undocumented) + protected readonly _params: any; + // (undocumented) + setupContentType(): FieldFormatConvert; + // Warning: (ae-forgotten-export) The symbol "TextContextTypeConvert" needs to be exported by the entry point index.d.ts + textConvert: TextContextTypeConvert | undefined; + static title: string; + toJSON(): { + id: unknown; + params: _.Dictionary | undefined; + }; + type: any; +} + // Warning: (ae-missing-release-tag) "FieldFormatConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -469,6 +560,13 @@ export interface FieldFormatConfig { // @public export type FieldFormatId = FIELD_FORMAT_IDS | string; +// @internal (undocumented) +export type FieldFormatInstanceType = (new (params?: any, getConfig?: FieldFormatsGetConfigFn) => FieldFormat) & { + id: FieldFormatId; + title: string; + fieldType: string | string[]; +}; + // Warning: (ae-missing-release-tag) "fieldFormats" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -825,17 +923,17 @@ export class IndexPattern implements IIndexPattern { }[]; }; // (undocumented) - getFieldByName(name: string): IndexPatternField | void; + getFieldByName(name: string): Field | void; // (undocumented) - getNonScriptedFields(): IndexPatternField[]; + getNonScriptedFields(): Field[]; // (undocumented) - getScriptedFields(): IndexPatternField[]; + getScriptedFields(): Field[]; // (undocumented) getSourceFiltering(): { excludes: any[]; }; // (undocumented) - getTimeField(): IndexPatternField | undefined; + getTimeField(): Field | undefined; // (undocumented) id?: string; // (undocumented) @@ -912,58 +1010,15 @@ export interface IndexPatternAttributes { typeMeta: string; } -// Warning: (ae-missing-release-tag) "Field" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class IndexPatternField implements IFieldType { - // Warning: (ae-forgotten-export) The symbol "FieldSpec" needs to be exported by the entry point index.d.ts - // - // (undocumented) - $$spec: FieldSpec; - constructor(indexPattern: IndexPattern, spec: FieldSpec | IndexPatternField, shortDotsEnable?: boolean); - // (undocumented) - aggregatable?: boolean; - // (undocumented) - count?: number; - // (undocumented) - displayName?: string; - // (undocumented) - esTypes?: string[]; - // (undocumented) - filterable?: boolean; - // (undocumented) - format: any; - // (undocumented) - indexPattern?: IndexPattern; - // (undocumented) - lang?: string; - // (undocumented) - name: string; - // (undocumented) - script?: string; - // (undocumented) - scripted?: boolean; - // (undocumented) - searchable?: boolean; - // (undocumented) - sortable?: boolean; - // (undocumented) - subType?: IFieldSubType; - // (undocumented) - type: string; - // (undocumented) - visualizable?: boolean; -} - // Warning: (ae-missing-release-tag) "FieldList" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class IndexPatternFieldList extends Array implements IFieldList { +export class IndexPatternFieldList extends Array implements IFieldList { constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean); // (undocumented) add: (field: Record) => void; // (undocumented) - getByName: (name: string) => IndexPatternField | undefined; + getByName: (name: string) => Field | undefined; // (undocumented) getByType: (type: string) => any[]; // (undocumented) @@ -1788,7 +1843,6 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts @@ -1804,28 +1858,28 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:386:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 9b673de60ca65..5d94b6516c2ba 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -609,7 +609,7 @@ export class Plugin implements Plugin_2 { // (undocumented) setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; search: ISearchSetup; }; diff --git a/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx b/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx index d07bf915845e9..fc5438b8c8dcb 100644 --- a/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx @@ -41,7 +41,7 @@ class EditableEmbeddable extends Embeddable { } test('is compatible when edit url is available, in edit mode and editable', async () => { - const action = new EditPanelAction(getFactory); + const action = new EditPanelAction(getFactory, {} as any); expect( await action.isCompatible({ embeddable: new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true), @@ -50,7 +50,7 @@ test('is compatible when edit url is available, in edit mode and editable', asyn }); test('getHref returns the edit urls', async () => { - const action = new EditPanelAction(getFactory); + const action = new EditPanelAction(getFactory, {} as any); expect(action.getHref).toBeDefined(); if (action.getHref) { @@ -64,7 +64,7 @@ test('getHref returns the edit urls', async () => { }); test('is not compatible when edit url is not available', async () => { - const action = new EditPanelAction(getFactory); + const action = new EditPanelAction(getFactory, {} as any); const embeddable = new ContactCardEmbeddable( { id: '123', @@ -83,7 +83,7 @@ test('is not compatible when edit url is not available', async () => { }); test('is not visible when edit url is available but in view mode', async () => { - const action = new EditPanelAction(getFactory); + const action = new EditPanelAction(getFactory, {} as any); expect( await action.isCompatible({ embeddable: new EditableEmbeddable( @@ -98,7 +98,7 @@ test('is not visible when edit url is available but in view mode', async () => { }); test('is not compatible when edit url is available, in edit mode, but not editable', async () => { - const action = new EditPanelAction(getFactory); + const action = new EditPanelAction(getFactory, {} as any); expect( await action.isCompatible({ embeddable: new EditableEmbeddable( diff --git a/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts b/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts index 044e7b5d35ad8..0abbc25ff49a6 100644 --- a/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts +++ b/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts @@ -18,6 +18,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ApplicationStart } from 'kibana/public'; import { Action } from 'src/plugins/ui_actions/public'; import { ViewMode } from '../types'; import { EmbeddableFactoryNotFoundError } from '../errors'; @@ -35,7 +36,10 @@ export class EditPanelAction implements Action { public readonly id = ACTION_EDIT_PANEL; public order = 15; - constructor(private readonly getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']) {} + constructor( + private readonly getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'], + private readonly application: ApplicationStart + ) {} public getDisplayName({ embeddable }: ActionContext) { const factory = this.getEmbeddableFactory(embeddable.type); @@ -56,18 +60,35 @@ export class EditPanelAction implements Action { public async isCompatible({ embeddable }: ActionContext) { const canEditEmbeddable = Boolean( - embeddable && embeddable.getOutput().editable && embeddable.getOutput().editUrl + embeddable && + embeddable.getOutput().editable && + (embeddable.getOutput().editUrl || + (embeddable.getOutput().editApp && embeddable.getOutput().editPath)) ); const inDashboardEditMode = embeddable.getInput().viewMode === ViewMode.EDIT; return Boolean(canEditEmbeddable && inDashboardEditMode); } public async execute(context: ActionContext) { + const appTarget = this.getAppTarget(context); + + if (appTarget) { + await this.application.navigateToApp(appTarget.app, { path: appTarget.path }); + return; + } + const href = await this.getHref(context); if (href) { - // TODO: when apps start using browser router instead of hash router this has to be fixed - // https://github.com/elastic/kibana/issues/58217 window.location.href = href; + return; + } + } + + public getAppTarget({ embeddable }: ActionContext): { app: string; path: string } | undefined { + const app = embeddable ? embeddable.getOutput().editApp : undefined; + const path = embeddable ? embeddable.getOutput().editPath : undefined; + if (app && path) { + return { app, path }; } } diff --git a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx index 2a0ffd723850b..b046376a304ae 100644 --- a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx @@ -66,6 +66,7 @@ test('EmbeddableChildPanel renders an embeddable when it is done loading', async getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={getEmbeddableFactory} notifications={{} as any} + application={{} as any} overlays={{} as any} inspector={inspector} SavedObjectFinder={() => null} @@ -105,6 +106,7 @@ test(`EmbeddableChildPanel renders an error message if the factory doesn't exist getEmbeddableFactory={(() => undefined) as any} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} /> diff --git a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx index 4c08a80a356bf..70628665e6e8c 100644 --- a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx +++ b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx @@ -40,6 +40,7 @@ export interface EmbeddableChildPanelProps { getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; + application: CoreStart['application']; inspector: InspectorStartContract; SavedObjectFinder: React.ComponentType; } @@ -101,6 +102,7 @@ export class EmbeddableChildPanel extends React.Component { getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} + application={{} as any} overlays={{} as any} inspector={inspector} SavedObjectFinder={() => null} @@ -198,6 +199,7 @@ const renderInEditModeAndOpenContextMenu = async ( getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} /> @@ -296,6 +298,7 @@ test('HelloWorldContainer in edit mode shows edit mode actions', async () => { getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} /> @@ -358,6 +361,7 @@ test('Updates when hidePanelTitles is toggled', async () => { getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} /> @@ -410,6 +414,7 @@ test('Check when hide header option is false', async () => { getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} hideHeader={false} @@ -447,6 +452,7 @@ test('Check when hide header option is true', async () => { getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} + application={{} as any} inspector={inspector} SavedObjectFinder={() => null} hideHeader={true} diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index b95060a73252f..c43359382a33d 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -45,6 +45,7 @@ interface Props { getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; + application: CoreStart['application']; inspector: InspectorStartContract; SavedObjectFinder: React.ComponentType; hideHeader?: boolean; @@ -243,7 +244,7 @@ export class EmbeddablePanel extends React.Component { ), new InspectPanelAction(this.props.inspector), new RemovePanelAction(), - new EditPanelAction(this.props.getEmbeddableFactory), + new EditPanelAction(this.props.getEmbeddableFactory, this.props.application), ]; const sorted = actions diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx index a88c3ba086325..31e14a0af59d7 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx @@ -49,6 +49,7 @@ interface HelloWorldContainerOptions { getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; + application: CoreStart['application']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; SavedObjectFinder: React.ComponentType; @@ -81,6 +82,7 @@ export class HelloWorldContainer extends Container; @@ -112,6 +113,7 @@ export class HelloWorldContainerComponent extends Component { getAllEmbeddableFactories={this.props.getAllEmbeddableFactories} overlays={this.props.overlays} notifications={this.props.notifications} + application={this.props.application} inspector={this.props.inspector} SavedObjectFinder={this.props.SavedObjectFinder} /> diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 01fbf52c80182..36f49f2508e80 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -118,6 +118,7 @@ export class EmbeddablePublicPlugin implements Plugin diff --git a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts index 3bd414ecf0d4a..ebb76c743393b 100644 --- a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts +++ b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts @@ -110,6 +110,7 @@ test('ApplyFilterAction is incompatible if the root container does not accept a getAllEmbeddableFactories: api.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector, SavedObjectFinder: () => null, } @@ -145,6 +146,7 @@ test('trying to execute on incompatible context throws an error ', async () => { getAllEmbeddableFactories: api.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector, SavedObjectFinder: () => null, } diff --git a/src/plugins/embeddable/public/tests/container.test.ts b/src/plugins/embeddable/public/tests/container.test.ts index 1aae43550ec6f..d2769e208ba42 100644 --- a/src/plugins/embeddable/public/tests/container.test.ts +++ b/src/plugins/embeddable/public/tests/container.test.ts @@ -74,6 +74,7 @@ async function creatHelloWorldContainerAndEmbeddable( getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, }); @@ -147,6 +148,7 @@ test('Container.removeEmbeddable removes and cleans up', async done => { getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -327,6 +329,7 @@ test(`Container updates its state when a child's input is updated`, async done = getEmbeddableFactory: start.getEmbeddableFactory, notifications: coreStart.notifications, overlays: coreStart.overlays, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, }); @@ -584,6 +587,7 @@ test('Container changes made directly after adding a new embeddable are propagat getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -708,6 +712,7 @@ test('untilEmbeddableLoaded() throws an error if there is no such child panel in getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -742,6 +747,7 @@ test('untilEmbeddableLoaded() resolves if child is loaded in the container', asy getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -781,6 +787,7 @@ test('untilEmbeddableLoaded resolves with undefined if child is subsequently rem getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -821,6 +828,7 @@ test('adding a panel then subsequently removing it before its loaded removes the getAllEmbeddableFactories: start.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } diff --git a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx index 19e461b8bde7e..a9cb83504d958 100644 --- a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx +++ b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx @@ -63,6 +63,7 @@ beforeEach(async () => { getAllEmbeddableFactories: api.getEmbeddableFactories, overlays: coreStart.overlays, notifications: coreStart.notifications, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } diff --git a/src/plugins/embeddable/public/tests/explicit_input.test.ts b/src/plugins/embeddable/public/tests/explicit_input.test.ts index 0e03db3ec8358..ef3c4b6f17e7f 100644 --- a/src/plugins/embeddable/public/tests/explicit_input.test.ts +++ b/src/plugins/embeddable/public/tests/explicit_input.test.ts @@ -88,6 +88,7 @@ test('Explicit embeddable input mapped to undefined with no inherited value will getEmbeddableFactory: start.getEmbeddableFactory, notifications: coreStart.notifications, overlays: coreStart.overlays, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } @@ -136,6 +137,7 @@ test('Explicit input tests in async situations', (done: () => void) => { getEmbeddableFactory: start.getEmbeddableFactory, notifications: coreStart.notifications, overlays: coreStart.overlays, + application: coreStart.application, inspector: {} as any, SavedObjectFinder: () => null, } diff --git a/src/plugins/share/server/plugin.ts b/src/plugins/share/server/plugin.ts index bcb681a50652a..0d9f183d13404 100644 --- a/src/plugins/share/server/plugin.ts +++ b/src/plugins/share/server/plugin.ts @@ -19,12 +19,14 @@ import { CoreSetup, Plugin, PluginInitializerContext } from 'kibana/server'; import { createRoutes } from './routes/create_routes'; +import { url } from './saved_objects'; export class SharePlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} public async setup(core: CoreSetup) { createRoutes(core, this.initializerContext.logger.get()); + core.savedObjects.registerType(url); } public start() { diff --git a/src/plugins/share/server/saved_objects/index.ts b/src/plugins/share/server/saved_objects/index.ts new file mode 100644 index 0000000000000..956f031d2f1a5 --- /dev/null +++ b/src/plugins/share/server/saved_objects/index.ts @@ -0,0 +1,19 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +export { url } from './url'; diff --git a/src/plugins/share/server/saved_objects/url.ts b/src/plugins/share/server/saved_objects/url.ts new file mode 100644 index 0000000000000..c76c21993a13f --- /dev/null +++ b/src/plugins/share/server/saved_objects/url.ts @@ -0,0 +1,54 @@ +/* + * 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 { SavedObjectsType } from 'kibana/server'; + +export const url: SavedObjectsType = { + name: 'url', + namespaceType: 'single', + hidden: false, + management: { + icon: 'link', + defaultSearchField: 'url', + importableAndExportable: true, + getTitle(obj) { + return `/goto/${encodeURIComponent(obj.id)}`; + }, + }, + mappings: { + properties: { + accessCount: { + type: 'long', + }, + accessDate: { + type: 'date', + }, + createDate: { + type: 'date', + }, + url: { + type: 'text', + fields: { + keyword: { + type: 'keyword', + }, + }, + }, + }, + }, +}; diff --git a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts b/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts index 3127e03ada0ef..fa4427fbb8c12 100644 --- a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts +++ b/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts @@ -36,6 +36,7 @@ const queryObject = Joi.object({ language: Joi.string().allow(''), query: Joi.string().allow(''), }); +const stringOrNumberOptionalNullable = Joi.alternatives([stringOptionalNullable, numberOptional]); const numberOptionalOrEmptyString = Joi.alternatives(numberOptional, Joi.string().valid('')); const annotationsItems = Joi.object({ @@ -78,7 +79,7 @@ const metricsItems = Joi.object({ unit: stringOptionalNullable, model_type: stringOptionalNullable, mode: stringOptionalNullable, - lag: numberOptional, + lag: numberOptionalOrEmptyString, alpha: numberOptional, beta: numberOptional, gamma: numberOptional, @@ -130,8 +131,8 @@ const seriesItems = Joi.object({ aggregate_by: stringOptionalNullable, aggregate_function: stringOptionalNullable, axis_position: stringRequired, - axis_max: stringOptionalNullable, - axis_min: stringOptionalNullable, + axis_max: stringOrNumberOptionalNullable, + axis_min: stringOrNumberOptionalNullable, chart_type: stringRequired, color: stringRequired, color_rules: Joi.array() @@ -198,8 +199,8 @@ export const visPayloadSchema = Joi.object({ axis_formatter: stringRequired, axis_position: stringRequired, axis_scale: stringRequired, - axis_min: stringOptionalNullable, - axis_max: stringOptionalNullable, + axis_min: stringOrNumberOptionalNullable, + axis_max: stringOrNumberOptionalNullable, bar_color_rules: arrayNullable.optional(), background_color: stringOptionalNullable, background_color_rules: Joi.array() @@ -221,9 +222,9 @@ export const visPayloadSchema = Joi.object({ .optional(), gauge_width: [stringOptionalNullable, numberOptional], gauge_inner_color: stringOptionalNullable, - gauge_inner_width: Joi.alternatives(stringOptionalNullable, numberIntegerOptional), + gauge_inner_width: stringOrNumberOptionalNullable, gauge_style: stringOptionalNullable, - gauge_max: stringOptionalNullable, + gauge_max: stringOrNumberOptionalNullable, id: stringRequired, ignore_global_filters: numberOptional, ignore_global_filter: numberOptional, diff --git a/src/plugins/vis_type_timeseries/server/saved_objects/tsvb_telemetry.ts b/src/plugins/vis_type_timeseries/server/saved_objects/tsvb_telemetry.ts index f18fa1e4cc2fa..34922976f22ff 100644 --- a/src/plugins/vis_type_timeseries/server/saved_objects/tsvb_telemetry.ts +++ b/src/plugins/vis_type_timeseries/server/saved_objects/tsvb_telemetry.ts @@ -41,5 +41,6 @@ export const tsvbTelemetrySavedObjectType: SavedObjectsType = { }, migrations: { '7.7.0': flow(resetCount), + '7.8.0': flow(resetCount), }, }; diff --git a/vars/workers.groovy b/vars/workers.groovy index 1c55c676d9425..b4e4a115f2011 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -57,6 +57,26 @@ def base(Map params, Closure closure) { // Try to clone from Github up to 8 times, waiting 15 secs between attempts retryWithDelay(8, 15) { scmVars = checkout scm + + def mergeBase + if (env.ghprbTargetBranch) { + sh( + script: "cd kibana && git fetch origin ${env.ghprbTargetBranch}", + label: "update reference to target branch 'origin/${env.ghprbTargetBranch}'" + ) + mergeBase = sh( + script: "cd kibana && git merge-base HEAD FETCH_HEAD", + label: "determining merge point with target branch 'origin/${env.ghprbTargetBranch}'", + returnStdout: true + ).trim() + } + + ciStats.reportGitInfo( + env.ghprbSourceBranch ?: scmVars.GIT_LOCAL_BRANCH ?: scmVars.GIT_BRANCH, + scmVars.GIT_COMMIT, + env.ghprbTargetBranch, + mergeBase + ) } } diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index ee08dfb87e1c1..1e8983a0ca5e5 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -45,6 +45,7 @@ const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => { getAllEmbeddableFactories={plugins.embeddable.getEmbeddableFactories} notifications={core.notifications} overlays={core.overlays} + application={core.application} inspector={plugins.inspector} SavedObjectFinder={getSavedObjectFinder(core.savedObjects, core.uiSettings)} /> diff --git a/x-pack/legacy/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap b/x-pack/legacy/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap new file mode 100644 index 0000000000000..aa22c3f66df18 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/server/usage/__snapshots__/reporting_usage_collector.test.ts.snap @@ -0,0 +1,343 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`data modeling with empty data 1`] = ` +Object { + "PNG": Object { + "available": true, + "total": 0, + }, + "_all": 0, + "available": true, + "browser_type": undefined, + "csv": Object { + "available": true, + "total": 0, + }, + "enabled": true, + "last7Days": Object { + "PNG": Object { + "available": true, + "total": 0, + }, + "_all": 0, + "csv": Object { + "available": true, + "total": 0, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 0, + "failed": 0, + }, + "statuses": Object {}, + }, + "lastDay": Object { + "PNG": Object { + "available": true, + "total": 0, + }, + "_all": 0, + "csv": Object { + "available": true, + "total": 0, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 0, + "failed": 0, + }, + "statuses": Object {}, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 0, + "failed": 0, + }, + "statuses": Object {}, +} +`; + +exports[`data modeling with normal looking usage data 1`] = ` +Object { + "PNG": Object { + "available": true, + "total": 3, + }, + "_all": 12, + "available": true, + "browser_type": undefined, + "csv": Object { + "available": true, + "total": 0, + }, + "enabled": true, + "last7Days": Object { + "PNG": Object { + "available": true, + "total": 1, + }, + "_all": 1, + "csv": Object { + "available": true, + "total": 0, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 0, + "completed_with_warnings": 1, + "failed": 0, + }, + "statuses": Object { + "completed_with_warnings": Object { + "PNG": Object { + "dashboard": 1, + }, + }, + }, + }, + "lastDay": Object { + "PNG": Object { + "available": true, + "total": 1, + }, + "_all": 1, + "csv": Object { + "available": true, + "total": 0, + }, + "printable_pdf": Object { + "app": Object { + "dashboard": 0, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 0, + "print": 0, + }, + "total": 0, + }, + "status": Object { + "completed": 0, + "completed_with_warnings": 1, + "failed": 0, + }, + "statuses": Object { + "completed_with_warnings": Object { + "PNG": Object { + "dashboard": 1, + }, + }, + }, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": 6, + "dashboard": 0, + "visualization": 3, + }, + "available": true, + "layout": Object { + "preserve_layout": 9, + "print": 0, + }, + "total": 9, + }, + "status": Object { + "completed": 10, + "completed_with_warnings": 1, + "failed": 1, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "visualization": 1, + }, + "printable_pdf": Object { + "canvas workpad": 6, + "visualization": 3, + }, + }, + "completed_with_warnings": Object { + "PNG": Object { + "dashboard": 1, + }, + }, + "failed": Object { + "PNG": Object { + "dashboard": 1, + }, + }, + }, +} +`; + +exports[`data modeling with sparse data 1`] = ` +Object { + "PNG": Object { + "available": true, + "total": 1, + }, + "_all": 4, + "available": true, + "browser_type": undefined, + "csv": Object { + "available": true, + "total": 1, + }, + "enabled": true, + "last7Days": Object { + "PNG": Object { + "available": true, + "total": 1, + }, + "_all": 4, + "csv": Object { + "available": true, + "total": 1, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": 1, + "dashboard": 1, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 2, + "print": 0, + }, + "total": 2, + }, + "status": Object { + "completed": 4, + "failed": 0, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "dashboard": 1, + }, + "csv": Object {}, + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 1, + }, + }, + }, + }, + "lastDay": Object { + "PNG": Object { + "available": true, + "total": 1, + }, + "_all": 4, + "csv": Object { + "available": true, + "total": 1, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": 1, + "dashboard": 1, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 2, + "print": 0, + }, + "total": 2, + }, + "status": Object { + "completed": 4, + "failed": 0, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "dashboard": 1, + }, + "csv": Object {}, + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 1, + }, + }, + }, + }, + "printable_pdf": Object { + "app": Object { + "canvas workpad": 1, + "dashboard": 1, + "visualization": 0, + }, + "available": true, + "layout": Object { + "preserve_layout": 2, + "print": 0, + }, + "total": 2, + }, + "status": Object { + "completed": 4, + "failed": 0, + }, + "statuses": Object { + "completed": Object { + "PNG": Object { + "dashboard": 1, + }, + "csv": Object {}, + "printable_pdf": Object { + "canvas workpad": 1, + "dashboard": 1, + }, + }, + }, +} +`; diff --git a/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts b/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts index 359bcc45230c3..ef985d2dd1cf3 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/decorate_range_stats.ts @@ -6,7 +6,7 @@ import { uniq } from 'lodash'; import { CSV_JOB_TYPE, PDF_JOB_TYPE, PNG_JOB_TYPE } from '../../common/constants'; -import { AvailableTotal, FeatureAvailabilityMap, RangeStats, ExportType } from './types'; +import { AvailableTotal, ExportType, FeatureAvailabilityMap, RangeStats } from './types'; function getForFeature( range: Partial, @@ -47,6 +47,7 @@ export const decorateRangeStats = ( const { _all: rangeAll, status: rangeStatus, + statuses: rangeStatusByApp, [PDF_JOB_TYPE]: rangeStatsPdf, ...rangeStatsBasic } = rangeStats; @@ -73,6 +74,7 @@ export const decorateRangeStats = ( const resultStats = { _all: rangeAll || 0, status: { completed: 0, failed: 0, ...rangeStatus }, + statuses: rangeStatusByApp, ...rangePdf, ...rangeBasic, } as RangeStats; diff --git a/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts b/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts index e9523d9e70202..2c3bb8f4bf71c 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts @@ -11,13 +11,13 @@ import { ReportingConfig } from '../types'; import { decorateRangeStats } from './decorate_range_stats'; import { getExportTypesHandler } from './get_export_type_handler'; import { - AggregationBuckets, - AggregationResults, + AggregationResultBuckets, FeatureAvailabilityMap, JobTypes, KeyCountBucket, - RangeAggregationResults, RangeStats, + SearchResponse, + StatusByAppBucket, } from './types'; type XPackInfo = XPackMainPlugin['info']; @@ -29,6 +29,7 @@ const LAYOUT_TYPES_FIELD = 'meta.layout.keyword'; const OBJECT_TYPES_KEY = 'objectTypes'; const OBJECT_TYPES_FIELD = 'meta.objectType.keyword'; const STATUS_TYPES_KEY = 'statusTypes'; +const STATUS_BY_APP_KEY = 'statusByApp'; const STATUS_TYPES_FIELD = 'status'; const DEFAULT_TERMS_SIZE = 10; @@ -38,16 +39,30 @@ const PRINTABLE_PDF_JOBTYPE = 'printable_pdf'; const getKeyCount = (buckets: KeyCountBucket[]): { [key: string]: number } => buckets.reduce((accum, { key, doc_count: count }) => ({ ...accum, [key]: count }), {}); -function getAggStats(aggs: AggregationResults) { - const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY] as AggregationBuckets; - const jobTypes: JobTypes = jobBuckets.reduce( +// indexes some key/count buckets by statusType > jobType > appName: statusCount +const getAppStatuses = (buckets: StatusByAppBucket[]) => + buckets.reduce((statuses, statusBucket) => { + return { + ...statuses, + [statusBucket.key]: statusBucket.jobTypes.buckets.reduce((jobTypes, job) => { + return { + ...jobTypes, + [job.key]: job.appNames.buckets.reduce((apps, app) => { + return { + ...apps, + [app.key]: app.doc_count, + }; + }, {}), + }; + }, {}), + }; + }, {}); + +function getAggStats(aggs: AggregationResultBuckets): RangeStats { + const { buckets: jobBuckets } = aggs[JOB_TYPES_KEY]; + const jobTypes = jobBuckets.reduce( (accum: JobTypes, { key, doc_count: count }: { key: string; doc_count: number }) => { - return { - ...accum, - [key]: { - total: count, - }, - }; + return { ...accum, [key]: { total: count } }; }, {} as JobTypes ); @@ -55,8 +70,8 @@ function getAggStats(aggs: AggregationResults) { // merge pdf stats into pdf jobtype key const pdfJobs = jobTypes[PRINTABLE_PDF_JOBTYPE]; if (pdfJobs) { - const pdfAppBuckets = get(aggs[OBJECT_TYPES_KEY], '.pdf.buckets', []); - const pdfLayoutBuckets = get(aggs[LAYOUT_TYPES_KEY], '.pdf.buckets', []); + const pdfAppBuckets = get(aggs[OBJECT_TYPES_KEY], '.pdf.buckets', []); + const pdfLayoutBuckets = get(aggs[LAYOUT_TYPES_KEY], '.pdf.buckets', []); pdfJobs.app = getKeyCount(pdfAppBuckets) as { visualization: number; dashboard: number; @@ -69,26 +84,35 @@ function getAggStats(aggs: AggregationResults) { const all = aggs.doc_count as number; let statusTypes = {}; - const statusBuckets = get(aggs[STATUS_TYPES_KEY], 'buckets', []); + const statusBuckets = get(aggs[STATUS_TYPES_KEY], 'buckets', []); if (statusBuckets) { statusTypes = getKeyCount(statusBuckets); } - return { _all: all, status: statusTypes, ...jobTypes }; + let statusByApp = {}; + const statusAppBuckets = get(aggs[STATUS_BY_APP_KEY], 'buckets', []); + if (statusAppBuckets) { + statusByApp = getAppStatuses(statusAppBuckets); + } + + return { _all: all, status: statusTypes, statuses: statusByApp, ...jobTypes }; } +type SearchAggregation = SearchResponse['aggregations']['ranges']['buckets']; + type RangeStatSets = Partial< RangeStats & { lastDay: RangeStats; last7Days: RangeStats; } >; -async function handleResponse(response: AggregationResults): Promise { - const buckets = get(response, 'aggregations.ranges.buckets'); + +async function handleResponse(response: SearchResponse): Promise { + const buckets = get(response, 'aggregations.ranges.buckets'); if (!buckets) { return {}; } - const { lastDay, last7Days, all } = buckets as RangeAggregationResults; + const { lastDay, last7Days, all } = buckets; const lastDayUsage = lastDay ? getAggStats(lastDay) : ({} as RangeStats); const last7DaysUsage = last7Days ? getAggStats(last7Days) : ({} as RangeStats); @@ -126,6 +150,17 @@ export async function getReportingUsage( aggs: { [JOB_TYPES_KEY]: { terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, [STATUS_TYPES_KEY]: { terms: { field: STATUS_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, + [STATUS_BY_APP_KEY]: { + terms: { field: 'status', size: DEFAULT_TERMS_SIZE }, + aggs: { + jobTypes: { + terms: { field: JOB_TYPES_FIELD, size: DEFAULT_TERMS_SIZE }, + aggs: { + appNames: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } }, // NOTE Discover/CSV export is missing the 'meta.objectType' field, so Discover/CSV results are missing for this agg + }, + }, + }, + }, [OBJECT_TYPES_KEY]: { filter: { term: { jobtype: PRINTABLE_PDF_JOBTYPE } }, aggs: { pdf: { terms: { field: OBJECT_TYPES_FIELD, size: DEFAULT_TERMS_SIZE } } }, @@ -141,7 +176,7 @@ export async function getReportingUsage( }; return callCluster('search', params) - .then((response: AggregationResults) => handleResponse(response)) + .then((response: SearchResponse) => handleResponse(response)) .then((usage: RangeStatSets) => { // Allow this to explicitly throw an exception if/when this config is deprecated, // because we shouldn't collect browserType in that case! diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts index dbc674ce36ec8..61b736a3e4d8c 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.ts @@ -12,6 +12,7 @@ import { getReportingUsageCollector, } from './reporting_usage_collector'; import { ReportingConfig } from '../types'; +import { SearchResponse } from './types'; const exportTypesRegistry = getExportTypesRegistry(); @@ -61,7 +62,7 @@ const getMockReportingConfig = () => ({ get: () => {}, kbnConfig: { get: () => '' }, }); -const getResponseMock = (customization = {}) => customization; +const getResponseMock = (base = {}) => base; describe('license checks', () => { let mockConfig: ReportingConfig; @@ -206,212 +207,143 @@ describe('data modeling', () => { ranges: { buckets: { all: { - doc_count: 54, - layoutTypes: { - doc_count: 23, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'preserve_layout', doc_count: 13 }, - { key: 'print', doc_count: 10 }, - ], - }, - }, - objectTypes: { - doc_count: 23, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'dashboard', doc_count: 23 }], - }, - }, - statusTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'pending', doc_count: 33 }, - { key: 'completed', doc_count: 20 }, - { key: 'processing', doc_count: 1 }, - ], - }, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'csv', doc_count: 27 }, - { key: 'printable_pdf', doc_count: 23 }, - { key: 'PNG', doc_count: 4 }, - ], - }, - }, - lastDay: { - doc_count: 11, - layoutTypes: { - doc_count: 2, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'print', doc_count: 2 }], - }, - }, - objectTypes: { - doc_count: 2, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'dashboard', doc_count: 2 }], - }, - }, - statusTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'pending', doc_count: 11 }], - }, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'csv', doc_count: 5 }, - { key: 'PNG', doc_count: 4 }, - { key: 'printable_pdf', doc_count: 2 }, - ], - }, + doc_count: 12, + jobTypes: { buckets: [ { doc_count: 9, key: 'printable_pdf' }, { doc_count: 3, key: 'PNG' }, ], }, + layoutTypes: { doc_count: 9, pdf: { buckets: [{ doc_count: 9, key: 'preserve_layout' }] }, }, + objectTypes: { doc_count: 9, pdf: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, }, + statusByApp: { buckets: [ { doc_count: 10, jobTypes: { buckets: [ { appNames: { buckets: [ { doc_count: 6, key: 'canvas workpad' }, { doc_count: 3, key: 'visualization' }, ], }, doc_count: 9, key: 'printable_pdf', }, { appNames: { buckets: [{ doc_count: 1, key: 'visualization' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'failed', }, ], }, + statusTypes: { buckets: [ { doc_count: 10, key: 'completed' }, { doc_count: 1, key: 'completed_with_warnings' }, { doc_count: 1, key: 'failed' }, ], }, }, last7Days: { - doc_count: 27, - layoutTypes: { - doc_count: 13, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'print', doc_count: 10 }, - { key: 'preserve_layout', doc_count: 3 }, - ], - }, - }, - objectTypes: { - doc_count: 13, - pdf: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'dashboard', doc_count: 13 }], - }, - }, - statusTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [{ key: 'pending', doc_count: 27 }], - }, - jobTypes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { key: 'printable_pdf', doc_count: 13 }, - { key: 'csv', doc_count: 10 }, - { key: 'PNG', doc_count: 4 }, - ], - }, + doc_count: 1, + jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] }, + layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, + objectTypes: { doc_count: 0, pdf: { buckets: [] } }, + statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], }, + statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] }, + }, + lastDay: { + doc_count: 1, + jobTypes: { buckets: [{ doc_count: 1, key: 'PNG' }] }, + layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, + objectTypes: { doc_count: 0, pdf: { buckets: [] } }, + statusByApp: { buckets: [ { doc_count: 1, jobTypes: { buckets: [ { appNames: { buckets: [{ doc_count: 1, key: 'dashboard' }] }, doc_count: 1, key: 'PNG', }, ], }, key: 'completed_with_warnings', }, ], }, + statusTypes: { buckets: [{ doc_count: 1, key: 'completed_with_warnings' }] }, }, }, }, }, - }) + } as SearchResponse) // prettier-ignore ) ); const usageStats = await fetch(callClusterMock as any); - expect(usageStats).toMatchInlineSnapshot(` - Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 54, - "available": true, - "browser_type": undefined, - "csv": Object { - "available": true, - "total": 27, - }, - "enabled": true, - "last7Days": Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 27, - "csv": Object { - "available": true, - "total": 10, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 13, - "visualization": 0, - }, - "available": true, - "layout": Object { - "preserve_layout": 3, - "print": 10, + expect(usageStats).toMatchSnapshot(); + }); + + test('with sparse data', async () => { + const mockConfig = getMockReportingConfig(); + const plugins = getPluginsMock(); + const { fetch } = getReportingUsageCollector( + mockConfig, + plugins.usageCollection, + plugins.__LEGACY.plugins.xpack_main.info, + exportTypesRegistry, + function isReady() { + return Promise.resolve(true); + } + ); + const callClusterMock = jest.fn(() => + Promise.resolve( + getResponseMock({ + aggregations: { + ranges: { + buckets: { + all: { + doc_count: 4, + layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, + objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, + statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, + }, + last7Days: { + doc_count: 4, + layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, + objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, + statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, + }, + lastDay: { + doc_count: 4, + layoutTypes: { doc_count: 2, pdf: { buckets: [{ key: 'preserve_layout', doc_count: 2 }] }, }, + statusByApp: { buckets: [ { key: 'completed', doc_count: 4, jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2, appNames: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, { key: 'PNG', doc_count: 1, appNames: { buckets: [{ key: 'dashboard', doc_count: 1 }] }, }, { key: 'csv', doc_count: 1, appNames: { buckets: [] } }, ], }, }, ], }, + objectTypes: { doc_count: 2, pdf: { buckets: [ { key: 'canvas workpad', doc_count: 1 }, { key: 'dashboard', doc_count: 1 }, ], }, }, + statusTypes: { buckets: [{ key: 'completed', doc_count: 4 }] }, + jobTypes: { buckets: [ { key: 'printable_pdf', doc_count: 2 }, { key: 'PNG', doc_count: 1 }, { key: 'csv', doc_count: 1 }, ], }, + }, + }, }, - "total": 13, }, - "status": Object { - "completed": 0, - "failed": 0, - "pending": 27, - }, - }, - "lastDay": Object { - "PNG": Object { - "available": true, - "total": 4, - }, - "_all": 11, - "csv": Object { - "available": true, - "total": 5, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 2, - "visualization": 0, - }, - "available": true, - "layout": Object { - "preserve_layout": 0, - "print": 2, + } as SearchResponse) // prettier-ignore + ) + ); + + const usageStats = await fetch(callClusterMock as any); + expect(usageStats).toMatchSnapshot(); + }); + + test('with empty data', async () => { + const mockConfig = getMockReportingConfig(); + const plugins = getPluginsMock(); + const { fetch } = getReportingUsageCollector( + mockConfig, + plugins.usageCollection, + plugins.__LEGACY.plugins.xpack_main.info, + exportTypesRegistry, + function isReady() { + return Promise.resolve(true); + } + ); + const callClusterMock = jest.fn(() => + Promise.resolve( + getResponseMock({ + aggregations: { + ranges: { + buckets: { + all: { + doc_count: 0, + jobTypes: { buckets: [] }, + layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, + objectTypes: { doc_count: 0, pdf: { buckets: [] } }, + statusByApp: { buckets: [] }, + statusTypes: { buckets: [] }, + }, + last7Days: { + doc_count: 0, + jobTypes: { buckets: [] }, + layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, + objectTypes: { doc_count: 0, pdf: { buckets: [] } }, + statusByApp: { buckets: [] }, + statusTypes: { buckets: [] }, + }, + lastDay: { + doc_count: 0, + jobTypes: { buckets: [] }, + layoutTypes: { doc_count: 0, pdf: { buckets: [] } }, + objectTypes: { doc_count: 0, pdf: { buckets: [] } }, + statusByApp: { buckets: [] }, + statusTypes: { buckets: [] }, + }, + }, }, - "total": 2, - }, - "status": Object { - "completed": 0, - "failed": 0, - "pending": 11, - }, - }, - "printable_pdf": Object { - "app": Object { - "dashboard": 23, - "visualization": 0, }, - "available": true, - "layout": Object { - "preserve_layout": 13, - "print": 10, - }, - "total": 23, - }, - "status": Object { - "completed": 20, - "failed": 0, - "pending": 33, - "processing": 1, - }, - } - `); + } as SearchResponse) + ) + ); + const usageStats = await fetch(callClusterMock as any); + expect(usageStats).toMatchSnapshot(); }); }); diff --git a/x-pack/legacy/plugins/reporting/server/usage/types.d.ts b/x-pack/legacy/plugins/reporting/server/usage/types.d.ts index 98e025ccf661e..83f1701863355 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/types.d.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/types.d.ts @@ -4,15 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface AvailableTotal { - available: boolean; - total: number; -} - -interface StatusCounts { - [statusType: string]: number; -} - export interface KeyCountBucket { key: string; doc_count: number; @@ -20,22 +11,53 @@ export interface KeyCountBucket { export interface AggregationBuckets { buckets: KeyCountBucket[]; - pdf?: { - buckets: KeyCountBucket[]; - }; } -/* - * Mapped Types and Intersection Types - */ +export interface StatusByAppBucket { + key: string; + doc_count: number; + jobTypes: { + buckets: Array<{ + doc_count: number; + key: string; + appNames: AggregationBuckets; + }>; + }; +} -type AggregationKeys = 'jobTypes' | 'layoutTypes' | 'objectTypes' | 'statusTypes'; -export type AggregationResults = { [K in AggregationKeys]: AggregationBuckets } & { +export interface AggregationResultBuckets { + jobTypes: AggregationBuckets; + layoutTypes: { + doc_count: number; + pdf: AggregationBuckets; + }; + objectTypes: { + doc_count: number; + pdf: AggregationBuckets; + }; + statusTypes: AggregationBuckets; + statusByApp: { + buckets: StatusByAppBucket[]; + }; doc_count: number; -}; +} -type RangeAggregationKeys = 'all' | 'lastDay' | 'last7Days'; -export type RangeAggregationResults = { [K in RangeAggregationKeys]?: AggregationResults }; +export interface SearchResponse { + aggregations: { + ranges: { + buckets: { + all: AggregationResultBuckets; + last7Days: AggregationResultBuckets; + lastDay: AggregationResultBuckets; + }; + }; + }; +} + +export interface AvailableTotal { + available: boolean; + total: number; +} type BaseJobTypeKeys = 'csv' | 'PNG'; export type JobTypes = { [K in BaseJobTypeKeys]: AvailableTotal } & { @@ -51,9 +73,22 @@ export type JobTypes = { [K in BaseJobTypeKeys]: AvailableTotal } & { }; }; +interface StatusCounts { + [statusType: string]: number; +} + +interface StatusByAppCounts { + [statusType: string]: { + [jobType: string]: { + [appName: string]: number; + }; + }; +} + export type RangeStats = JobTypes & { _all: number; status: StatusCounts; + statuses: StatusByAppCounts; }; export type ExportType = 'csv' | 'printable_pdf' | 'PNG'; diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx index a7272593c2b27..e18f9b0d346ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/embedded_map.tsx @@ -208,6 +208,7 @@ export const EmbeddedMapComponent = ({ notifications={services.notifications} overlays={services.overlays} inspector={services.inspector} + application={services.application} SavedObjectFinder={getSavedObjectFinder(services.savedObjects, services.uiSettings)} /> ) : !isLoading && isIndexError ? ( diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts index d2491b39fdf56..388875724afe9 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/mock.ts @@ -9,8 +9,25 @@ import { CasesConfigureResponse, CasesConfigureRequest, } from '../../../../../../../plugins/case/common/api'; -import { CaseConfigure } from './types'; +import { CaseConfigure, CasesConfigurationMapping } from './types'; +export const mapping: CasesConfigurationMapping[] = [ + { + source: 'title', + target: 'short_description', + actionType: 'overwrite', + }, + { + source: 'description', + target: 'description', + actionType: 'append', + }, + { + source: 'comments', + target: 'comments', + actionType: 'append', + }, +]; export const connectorsMock: Connector[] = [ { id: '123', @@ -19,26 +36,10 @@ export const connectorsMock: Connector[] = [ config: { apiUrl: 'https://instance1.service-now.com', casesConfiguration: { - mapping: [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'append', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, - ], + mapping, }, }, - isPreconfigured: true, + isPreconfigured: false, }, { id: '456', @@ -66,7 +67,7 @@ export const connectorsMock: Connector[] = [ ], }, }, - isPreconfigured: true, + isPreconfigured: false, }, ]; @@ -75,7 +76,7 @@ export const caseConfigurationResposeMock: CasesConfigureResponse = { created_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' }, connector_id: '123', connector_name: 'My Connector', - closure_type: 'close-by-user', + closure_type: 'close-by-pushing', updated_at: '2020-04-06T14:03:18.657Z', updated_by: { username: 'elastic', full_name: 'Elastic', email: 'elastic@elastic.co' }, version: 'WzHJ12', @@ -92,7 +93,7 @@ export const caseConfigurationCamelCaseResponseMock: CaseConfigure = { createdBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' }, connectorId: '123', connectorName: 'My Connector', - closureType: 'close-by-user', + closureType: 'close-by-pushing', updatedAt: '2020-04-06T14:03:18.657Z', updatedBy: { username: 'elastic', fullName: 'Elastic', email: 'elastic@elastic.co' }, version: 'WzHJ12', diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx index 3ee16e19eaf9f..2826e9a2c2e55 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.test.tsx @@ -5,13 +5,18 @@ */ import { renderHook, act } from '@testing-library/react-hooks'; -import { useCaseConfigure, ReturnUseCaseConfigure, PersistCaseConfigure } from './use_configure'; -import { caseConfigurationCamelCaseResponseMock } from './mock'; +import { + initialState, + useCaseConfigure, + ReturnUseCaseConfigure, + ConnectorConfiguration, +} from './use_configure'; +import { mapping, caseConfigurationCamelCaseResponseMock } from './mock'; import * as api from './api'; jest.mock('./api'); -const configuration: PersistCaseConfigure = { +const configuration: ConnectorConfiguration = { connectorId: '456', connectorName: 'My Connector 2', closureType: 'close-by-pushing', @@ -23,23 +28,20 @@ describe('useConfigure', () => { jest.restoreAllMocks(); }); - const args = { - setConnector: jest.fn(), - setClosureType: jest.fn(), - setCurrentConfiguration: jest.fn(), - }; - test('init', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); expect(result.current).toEqual({ - loading: true, - persistLoading: false, + ...initialState, refetchCaseConfigure: result.current.refetchCaseConfigure, persistCaseConfigure: result.current.persistCaseConfigure, + setCurrentConfiguration: result.current.setCurrentConfiguration, + setConnector: result.current.setConnector, + setClosureType: result.current.setClosureType, + setMapping: result.current.setMapping, }); }); }); @@ -47,89 +49,64 @@ describe('useConfigure', () => { test('fetch case configuration', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); expect(result.current).toEqual({ + ...initialState, + closureType: caseConfigurationCamelCaseResponseMock.closureType, + connectorId: caseConfigurationCamelCaseResponseMock.connectorId, + connectorName: caseConfigurationCamelCaseResponseMock.connectorName, + currentConfiguration: { + closureType: caseConfigurationCamelCaseResponseMock.closureType, + connectorId: caseConfigurationCamelCaseResponseMock.connectorId, + connectorName: caseConfigurationCamelCaseResponseMock.connectorName, + }, + version: caseConfigurationCamelCaseResponseMock.version, + firstLoad: true, loading: false, - persistLoading: false, refetchCaseConfigure: result.current.refetchCaseConfigure, persistCaseConfigure: result.current.persistCaseConfigure, + setCurrentConfiguration: result.current.setCurrentConfiguration, + setConnector: result.current.setConnector, + setClosureType: result.current.setClosureType, + setMapping: result.current.setMapping, }); }); }); - test('fetch case configuration - setConnector', async () => { - await act(async () => { - const { waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(args.setConnector).toHaveBeenCalledWith('123', 'My Connector'); - }); - }); - - test('fetch case configuration - setClosureType', async () => { - await act(async () => { - const { waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(args.setClosureType).toHaveBeenCalledWith('close-by-user'); - }); - }); - - test('fetch case configuration - setCurrentConfiguration', async () => { - await act(async () => { - const { waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(args.setCurrentConfiguration).toHaveBeenCalledWith({ - connectorId: '123', - closureType: 'close-by-user', - }); - }); - }); + test('refetch case configuration', async () => { + const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - test('fetch case configuration - only setConnector', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure({ setConnector: jest.fn() }) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); - expect(result.current).toEqual({ - loading: false, - persistLoading: false, - refetchCaseConfigure: result.current.refetchCaseConfigure, - persistCaseConfigure: result.current.persistCaseConfigure, - }); + result.current.refetchCaseConfigure(); + expect(spyOnGetCaseConfigure).toHaveBeenCalledTimes(2); }); }); - test('refetch case configuration', async () => { - const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); - + test('correctly sets mappings', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); - result.current.refetchCaseConfigure(); - expect(spyOnGetCaseConfigure).toHaveBeenCalledTimes(2); + expect(result.current.mapping).toEqual(null); + result.current.setMapping(mapping); + expect(result.current.mapping).toEqual(mapping); }); }); test('set isLoading to true when fetching case configuration', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); @@ -142,19 +119,12 @@ describe('useConfigure', () => { test('persist case configuration', async () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); - result.current.persistCaseConfigure(configuration); - - expect(result.current).toEqual({ - loading: false, - persistLoading: true, - refetchCaseConfigure: result.current.refetchCaseConfigure, - persistCaseConfigure: result.current.persistCaseConfigure, - }); + expect(result.current.persistLoading).toBeTruthy(); }); }); @@ -178,21 +148,16 @@ describe('useConfigure', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); result.current.persistCaseConfigure(configuration); + expect(result.current.connectorId).toEqual('123'); await waitForNextUpdate(); - - expect(args.setConnector).toHaveBeenNthCalledWith(2, '456'); - expect(args.setClosureType).toHaveBeenNthCalledWith(2, 'close-by-pushing'); - expect(args.setCurrentConfiguration).toHaveBeenNthCalledWith(2, { - connectorId: '456', - closureType: 'close-by-pushing', - }); + expect(result.current.connectorId).toEqual('456'); }); }); @@ -207,43 +172,16 @@ describe('useConfigure', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - - result.current.persistCaseConfigure(configuration); - - await waitForNextUpdate(); - - expect(args.setConnector).toHaveBeenNthCalledWith(2, '456'); - expect(args.setClosureType).toHaveBeenNthCalledWith(2, 'close-by-pushing'); - expect(args.setCurrentConfiguration).toHaveBeenNthCalledWith(2, { - connectorId: '456', - closureType: 'close-by-pushing', - }); - }); - }); - - test('save case configuration - only setConnector', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure({ setConnector: jest.fn() }) + useCaseConfigure() ); - await waitForNextUpdate(); await waitForNextUpdate(); result.current.persistCaseConfigure(configuration); + expect(result.current.connectorId).toEqual('123'); await waitForNextUpdate(); - - expect(result.current).toEqual({ - loading: false, - persistLoading: false, - refetchCaseConfigure: result.current.refetchCaseConfigure, - persistCaseConfigure: result.current.persistCaseConfigure, - }); + expect(result.current.connectorId).toEqual('456'); }); }); @@ -255,22 +193,34 @@ describe('useConfigure', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); await waitForNextUpdate(); expect(result.current).toEqual({ + ...initialState, loading: false, persistLoading: false, refetchCaseConfigure: result.current.refetchCaseConfigure, persistCaseConfigure: result.current.persistCaseConfigure, + setCurrentConfiguration: result.current.setCurrentConfiguration, + setConnector: result.current.setConnector, + setClosureType: result.current.setClosureType, + setMapping: result.current.setMapping, }); }); }); test('unhappy path - persist case configuration', async () => { + const spyOnGetCaseConfigure = jest.spyOn(api, 'getCaseConfigure'); + spyOnGetCaseConfigure.mockImplementation(() => + Promise.resolve({ + ...caseConfigurationCamelCaseResponseMock, + version: '', + }) + ); const spyOnPostCaseConfigure = jest.spyOn(api, 'postCaseConfigure'); spyOnPostCaseConfigure.mockImplementation(() => { throw new Error('Something went wrong'); @@ -278,7 +228,7 @@ describe('useConfigure', () => { await act(async () => { const { result, waitForNextUpdate } = renderHook(() => - useCaseConfigure(args) + useCaseConfigure() ); await waitForNextUpdate(); @@ -286,13 +236,24 @@ describe('useConfigure', () => { result.current.persistCaseConfigure(configuration); - await waitForNextUpdate(); - expect(result.current).toEqual({ + ...initialState, + closureType: caseConfigurationCamelCaseResponseMock.closureType, + connectorId: caseConfigurationCamelCaseResponseMock.connectorId, + connectorName: caseConfigurationCamelCaseResponseMock.connectorName, + currentConfiguration: { + closureType: caseConfigurationCamelCaseResponseMock.closureType, + connectorId: caseConfigurationCamelCaseResponseMock.connectorId, + connectorName: caseConfigurationCamelCaseResponseMock.connectorName, + }, + firstLoad: true, loading: false, - persistLoading: false, refetchCaseConfigure: result.current.refetchCaseConfigure, persistCaseConfigure: result.current.persistCaseConfigure, + setCurrentConfiguration: result.current.setCurrentConfiguration, + setConnector: result.current.setConnector, + setClosureType: result.current.setClosureType, + setMapping: result.current.setMapping, }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx index 1c03a09a8c2ea..a185d435f7165 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/use_configure.tsx @@ -4,47 +4,203 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useState, useEffect, useCallback } from 'react'; +import { useEffect, useCallback, useReducer } from 'react'; import { getCaseConfigure, patchCaseConfigure, postCaseConfigure } from './api'; import { useStateToaster, errorToToaster, displaySuccessToast } from '../../../components/toasters'; import * as i18n from './translations'; -import { ClosureType } from './types'; -import { CurrentConfiguration } from '../../../pages/case/components/configure_cases/reducer'; +import { CasesConfigurationMapping, ClosureType } from './types'; -export interface PersistCaseConfigure { +interface Connector { connectorId: string; connectorName: string; +} +export interface ConnectorConfiguration extends Connector { closureType: ClosureType; } -export interface ReturnUseCaseConfigure { +export interface State extends ConnectorConfiguration { + currentConfiguration: ConnectorConfiguration; + firstLoad: boolean; loading: boolean; - refetchCaseConfigure: () => void; + mapping: CasesConfigurationMapping[] | null; + persistLoading: boolean; + version: string; +} +export type Action = + | { + type: 'setCurrentConfiguration'; + currentConfiguration: ConnectorConfiguration; + } + | { + type: 'setConnector'; + connector: Connector; + } + | { + type: 'setLoading'; + payload: boolean; + } + | { + type: 'setFirstLoad'; + payload: boolean; + } + | { + type: 'setPersistLoading'; + payload: boolean; + } + | { + type: 'setVersion'; + payload: string; + } + | { + type: 'setClosureType'; + closureType: ClosureType; + } + | { + type: 'setMapping'; + mapping: CasesConfigurationMapping[]; + }; + +export const configureCasesReducer = (state: State, action: Action) => { + switch (action.type) { + case 'setLoading': + return { + ...state, + loading: action.payload, + }; + case 'setFirstLoad': + return { + ...state, + firstLoad: action.payload, + }; + case 'setPersistLoading': + return { + ...state, + persistLoading: action.payload, + }; + case 'setVersion': + return { + ...state, + version: action.payload, + }; + case 'setCurrentConfiguration': { + return { + ...state, + currentConfiguration: { ...action.currentConfiguration }, + }; + } + case 'setConnector': { + return { + ...state, + ...action.connector, + }; + } + case 'setClosureType': { + return { + ...state, + closureType: action.closureType, + }; + } + case 'setMapping': { + return { + ...state, + mapping: action.mapping, + }; + } + default: + return state; + } +}; + +export interface ReturnUseCaseConfigure extends State { persistCaseConfigure: ({ connectorId, connectorName, closureType, - }: PersistCaseConfigure) => unknown; - persistLoading: boolean; + }: ConnectorConfiguration) => unknown; + refetchCaseConfigure: () => void; + setClosureType: (closureType: ClosureType) => void; + setConnector: (connectorId: string, connectorName?: string) => void; + setCurrentConfiguration: (configuration: ConnectorConfiguration) => void; + setMapping: (newMapping: CasesConfigurationMapping[]) => void; } -interface UseCaseConfigure { - setConnector: (newConnectorId: string, newConnectorName?: string) => void; - setClosureType?: (newClosureType: ClosureType) => void; - setCurrentConfiguration?: (configuration: CurrentConfiguration) => void; -} +export const initialState: State = { + closureType: 'close-by-user', + connectorId: 'none', + connectorName: 'none', + currentConfiguration: { + closureType: 'close-by-user', + connectorId: 'none', + connectorName: 'none', + }, + firstLoad: false, + loading: true, + mapping: null, + persistLoading: false, + version: '', +}; + +export const useCaseConfigure = (): ReturnUseCaseConfigure => { + const [state, dispatch] = useReducer(configureCasesReducer, initialState); + + const setCurrentConfiguration = useCallback((configuration: ConnectorConfiguration) => { + dispatch({ + currentConfiguration: configuration, + type: 'setCurrentConfiguration', + }); + }, []); + + const setConnector = useCallback((connectorId: string, connectorName?: string) => { + dispatch({ + connector: { connectorId, connectorName: connectorName ?? '' }, + type: 'setConnector', + }); + }, []); + + const setClosureType = useCallback((closureType: ClosureType) => { + dispatch({ + closureType, + type: 'setClosureType', + }); + }, []); + + const setMapping = useCallback((newMapping: CasesConfigurationMapping[]) => { + dispatch({ + mapping: newMapping, + type: 'setMapping', + }); + }, []); + + const setLoading = useCallback((isLoading: boolean) => { + dispatch({ + payload: isLoading, + type: 'setLoading', + }); + }, []); + + const setFirstLoad = useCallback((isFirstLoad: boolean) => { + dispatch({ + payload: isFirstLoad, + type: 'setFirstLoad', + }); + }, []); + + const setPersistLoading = useCallback((isPersistLoading: boolean) => { + dispatch({ + payload: isPersistLoading, + type: 'setPersistLoading', + }); + }, []); + + const setVersion = useCallback((version: string) => { + dispatch({ + payload: version, + type: 'setVersion', + }); + }, []); -export const useCaseConfigure = ({ - setConnector, - setClosureType, - setCurrentConfiguration, -}: UseCaseConfigure): ReturnUseCaseConfigure => { const [, dispatchToaster] = useStateToaster(); - const [loading, setLoading] = useState(true); - const [firstLoad, setFirstLoad] = useState(false); - const [persistLoading, setPersistLoading] = useState(false); - const [version, setVersion] = useState(''); const refetchCaseConfigure = useCallback(() => { let didCancel = false; @@ -62,12 +218,13 @@ export const useCaseConfigure = ({ } setVersion(res.version); - if (!firstLoad) { + if (!state.firstLoad) { setFirstLoad(true); if (setCurrentConfiguration != null) { setCurrentConfiguration({ - connectorId: res.connectorId, closureType: res.closureType, + connectorId: res.connectorId, + connectorName: res.connectorName, }); } } @@ -78,9 +235,9 @@ export const useCaseConfigure = ({ if (!didCancel) { setLoading(false); errorToToaster({ - title: i18n.ERROR_TITLE, - error: error.body && error.body.message ? new Error(error.body.message) : error, dispatchToaster, + error: error.body && error.body.message ? new Error(error.body.message) : error, + title: i18n.ERROR_TITLE, }); } } @@ -92,10 +249,10 @@ export const useCaseConfigure = ({ didCancel = true; abortCtrl.abort(); }; - }, []); + }, [state.firstLoad]); const persistCaseConfigure = useCallback( - async ({ connectorId, connectorName, closureType }: PersistCaseConfigure) => { + async ({ connectorId, connectorName, closureType }: ConnectorConfiguration) => { let didCancel = false; const abortCtrl = new AbortController(); const saveCaseConfiguration = async () => { @@ -107,17 +264,17 @@ export const useCaseConfigure = ({ closure_type: closureType, }; const res = - version.length === 0 + state.version.length === 0 ? await postCaseConfigure(connectorObj, abortCtrl.signal) : await patchCaseConfigure( { ...connectorObj, - version, + version: state.version, }, abortCtrl.signal ); if (!didCancel) { - setConnector(res.connectorId); + setConnector(res.connectorId, res.connectorName); if (setClosureType) { setClosureType(res.closureType); } @@ -126,6 +283,7 @@ export const useCaseConfigure = ({ setCurrentConfiguration({ connectorId: res.connectorId, closureType: res.closureType, + connectorName: res.connectorName, }); } @@ -149,7 +307,7 @@ export const useCaseConfigure = ({ abortCtrl.abort(); }; }, - [version] + [state.version] ); useEffect(() => { @@ -157,9 +315,12 @@ export const useCaseConfigure = ({ }, []); return { - loading, + ...state, refetchCaseConfigure, persistCaseConfigure, - persistLoading, + setCurrentConfiguration, + setConnector, + setClosureType, + setMapping, }; }; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/__mock__/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/__mock__/index.tsx index 135f0f2a7e26d..e060a94e2d0cd 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/__mock__/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/__mock__/index.tsx @@ -4,110 +4,40 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Connector, - CasesConfigurationMapping, -} from '../../../../../containers/case/configure/types'; -import { State } from '../reducer'; +import { Connector } from '../../../../../containers/case/configure/types'; import { ReturnConnectors } from '../../../../../containers/case/configure/use_connectors'; +import { connectorsMock } from '../../../../../containers/case/configure/mock'; import { ReturnUseCaseConfigure } from '../../../../../containers/case/configure/use_configure'; import { createUseKibanaMock } from '../../../../../mock/kibana_react'; - +export { mapping } from '../../../../../containers/case/configure/mock'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { actionTypeRegistryMock } from '../../../../../../../../../plugins/triggers_actions_ui/public/application/action_type_registry.mock'; -export const connectors: Connector[] = [ - { - id: '123', - actionTypeId: '.servicenow', - name: 'My Connector', - isPreconfigured: false, - config: { - apiUrl: 'https://instance1.service-now.com', - casesConfiguration: { - mapping: [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'append', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, - ], - }, - }, - }, - { - id: '456', - actionTypeId: '.servicenow', - name: 'My Connector 2', - isPreconfigured: false, - config: { - apiUrl: 'https://instance2.service-now.com', - casesConfiguration: { - mapping: [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'overwrite', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, - ], - }, - }, - }, -]; - -export const mapping: CasesConfigurationMapping[] = [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'append', - }, - { - source: 'comments', - target: 'comments', - actionType: 'append', - }, -]; +export const connectors: Connector[] = connectorsMock; export const searchURL = '?timerange=(global:(linkTo:!(),timerange:(from:1585487656371,fromStr:now-24h,kind:relative,to:1585574056371,toStr:now)),timeline:(linkTo:!(),timerange:(from:1585227005527,kind:absolute,to:1585313405527)))'; -export const initialState: State = { - connectorId: 'none', - closureType: 'close-by-user', - mapping: null, - currentConfiguration: { connectorId: 'none', closureType: 'close-by-user' }, -}; - export const useCaseConfigureResponse: ReturnUseCaseConfigure = { + closureType: 'close-by-user', + connectorId: 'none', + connectorName: 'none', + currentConfiguration: { + connectorId: 'none', + closureType: 'close-by-user', + connectorName: 'none', + }, + firstLoad: false, loading: false, + mapping: null, + persistCaseConfigure: jest.fn(), persistLoading: false, refetchCaseConfigure: jest.fn(), - persistCaseConfigure: jest.fn(), + setClosureType: jest.fn(), + setConnector: jest.fn(), + setCurrentConfiguration: jest.fn(), + setMapping: jest.fn(), + version: '', }; export const useConnectorsResponse: ReturnConnectors = { diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx index 5ea3f500c0349..2f9761d733b5b 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx @@ -4,9 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { ReactWrapper, mount } from 'enzyme'; +import { ConfigureCases } from './'; +import { TestProviders } from '../../../../mock'; +import { Connectors } from './connectors'; +import { ClosureOptions } from './closure_options'; +import { Mapping } from './mapping'; +import { + ActionsConnectorsContextProvider, + ConnectorAddFlyout, + ConnectorEditFlyout, +} from '../../../../../../../../plugins/triggers_actions_ui/public'; +import { EuiBottomBar } from '@elastic/eui'; + import { useKibana } from '../../../../lib/kibana'; import { useConnectors } from '../../../../containers/case/configure/use_connectors'; import { useCaseConfigure } from '../../../../containers/case/configure/use_configure'; @@ -18,6 +30,7 @@ import { useCaseConfigureResponse, useConnectorsResponse, kibanaMockImplementationArgs, + mapping, } from './__mock__'; jest.mock('../../../../lib/kibana'); @@ -29,720 +42,741 @@ const useKibanaMock = useKibana as jest.Mock; const useConnectorsMock = useConnectors as jest.Mock; const useCaseConfigureMock = useCaseConfigure as jest.Mock; const useGetUrlSearchMock = useGetUrlSearch as jest.Mock; - -import { ConfigureCases } from './'; -import { TestProviders } from '../../../../mock'; -import { Connectors } from './connectors'; -import { ClosureOptions } from './closure_options'; -import { Mapping } from './mapping'; -import { - ActionsConnectorsContextProvider, - ConnectorAddFlyout, - ConnectorEditFlyout, -} from '../../../../../../../../plugins/triggers_actions_ui/public'; -import { EuiBottomBar } from '@elastic/eui'; - -describe('rendering', () => { - let wrapper: ReactWrapper; - beforeEach(() => { - jest.resetAllMocks(); - useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); - useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); - useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders the Connectors', () => { - expect(wrapper.find('[data-test-subj="case-connectors-form-group"]').exists()).toBeTruthy(); - }); - - test('it renders the ClosureType', () => { - expect( - wrapper.find('[data-test-subj="case-closure-options-form-group"]').exists() - ).toBeTruthy(); - }); - - test('it renders the Mapping', () => { - expect(wrapper.find('[data-test-subj="case-mapping-form-group"]').exists()).toBeTruthy(); - }); - - test('it renders the ActionsConnectorsContextProvider', () => { - // Components from triggers_actions_ui do not have a data-test-subj - expect(wrapper.find(ActionsConnectorsContextProvider).exists()).toBeTruthy(); - }); - - test('it renders the ConnectorAddFlyout', () => { - // Components from triggers_actions_ui do not have a data-test-subj - expect(wrapper.find(ConnectorAddFlyout).exists()).toBeTruthy(); - }); - - test('it does NOT render the ConnectorEditFlyout', () => { - // Components from triggers_actions_ui do not have a data-test-subj - expect(wrapper.find(ConnectorEditFlyout).exists()).toBeFalsy(); - }); - - test('it does NOT render the EuiCallOut', () => { - expect(wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists()).toBeFalsy(); - }); - - test('it does NOT render the EuiBottomBar', () => { - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); - }); -}); - -describe('ConfigureCases - Unhappy path', () => { - beforeEach(() => { - jest.resetAllMocks(); - useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); - useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); - useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); - useGetUrlSearchMock.mockImplementation(() => searchURL); - }); - - test('it shows the warning callout when configuration is invalid', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('not-id'), []); - return useCaseConfigureResponse; - } - ); - - const wrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists() - ).toBeTruthy(); - }); -}); - -describe('ConfigureCases - Happy path', () => { - let wrapper: ReactWrapper; - - beforeEach(() => { - jest.resetAllMocks(); - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('123'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return useCaseConfigureResponse; - } - ); - useConnectorsMock.mockImplementation(() => useConnectorsResponse); - useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); - useGetUrlSearchMock.mockImplementation(() => searchURL); - - wrapper = mount(, { wrappingComponent: TestProviders }); - }); - - test('it renders the ConnectorEditFlyout', () => { - expect(wrapper.find(ConnectorEditFlyout).exists()).toBeTruthy(); - }); - - test('it renders with correct props', () => { - // Connector - expect(wrapper.find(Connectors).prop('connectors')).toEqual(connectors); - expect(wrapper.find(Connectors).prop('disabled')).toBe(false); - expect(wrapper.find(Connectors).prop('isLoading')).toBe(false); - expect(wrapper.find(Connectors).prop('selectedConnector')).toBe('123'); - - // ClosureOptions - expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(false); - expect(wrapper.find(ClosureOptions).prop('closureTypeSelected')).toBe('close-by-user'); - - // Mapping - expect(wrapper.find(Mapping).prop('disabled')).toBe(true); - expect(wrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(false); - expect(wrapper.find(Mapping).prop('mapping')).toEqual( - connectors[0].config.casesConfiguration.mapping - ); - - // Flyouts - expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false); - expect(wrapper.find(ConnectorAddFlyout).prop('actionTypes')).toEqual([ - { - id: '.servicenow', - name: 'ServiceNow', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'platinum', - }, - ]); - - expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(false); - expect(wrapper.find(ConnectorEditFlyout).prop('initialConnector')).toEqual(connectors[0]); - }); - - test('it disables correctly when the user cannot crud', () => { - const newWrapper = mount(, { - wrappingComponent: TestProviders, +describe('ConfigureCases', () => { + describe('rendering', () => { + let wrapper: ReactWrapper; + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); + useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + + wrapper = mount(, { wrappingComponent: TestProviders }); }); - expect(newWrapper.find(Connectors).prop('disabled')).toBe(true); - expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true); - expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); - expect(newWrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(true); - }); - - test('it disables correctly Connector when loading connectors', () => { - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect(newWrapper.find(Connectors).prop('disabled')).toBe(true); - }); - - test('it disables correctly Connector when saving configuration', () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - persistLoading: true, - })); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect(newWrapper.find(Connectors).prop('disabled')).toBe(true); - }); + test('it renders the Connectors', () => { + expect(wrapper.find('[data-test-subj="case-connectors-form-group"]').exists()).toBeTruthy(); + }); - test('it pass the correct value to isLoading attribute on Connector', () => { - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); + test('it renders the ClosureType', () => { + expect( + wrapper.find('[data-test-subj="case-closure-options-form-group"]').exists() + ).toBeTruthy(); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it renders the Mapping', () => { + expect(wrapper.find('[data-test-subj="case-mapping-form-group"]').exists()).toBeTruthy(); + }); - expect(newWrapper.find(Connectors).prop('isLoading')).toBe(true); - }); + test('it renders the ActionsConnectorsContextProvider', () => { + // Components from triggers_actions_ui do not have a data-test-subj + expect(wrapper.find(ActionsConnectorsContextProvider).exists()).toBeTruthy(); + }); - test('it set correctly the selected connector', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - return useCaseConfigureResponse; - } - ); + test('it renders the ConnectorAddFlyout', () => { + // Components from triggers_actions_ui do not have a data-test-subj + expect(wrapper.find(ConnectorAddFlyout).exists()).toBeTruthy(); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it does NOT render the ConnectorEditFlyout', () => { + // Components from triggers_actions_ui do not have a data-test-subj + expect(wrapper.find(ConnectorEditFlyout).exists()).toBeFalsy(); + }); - expect(newWrapper.find(Connectors).prop('selectedConnector')).toBe('456'); - }); + test('it does NOT render the EuiCallOut', () => { + expect( + wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists() + ).toBeFalsy(); + }); - test('it show the add flyout when pressing the add connector button', () => { - wrapper.find('button[data-test-subj="case-configure-add-connector-button"]').simulate('click'); - wrapper.update(); + test('it does NOT render the EuiBottomBar', () => { + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); + }); - expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true); - expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy(); + test('it disables correctly ClosureOptions when the connector is set to none', () => { + expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true); + }); }); - test('it disables correctly ClosureOptions when loading connectors', () => { - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); + describe('Unhappy path', () => { + let wrapper: ReactWrapper; + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + closureType: 'close-by-user', + connectorId: 'not-id', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: 'not-id', + closureType: 'close-by-user', + }, + })); + useConnectorsMock.mockImplementation(() => ({ ...useConnectorsResponse, connectors: [] })); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + wrapper = mount(, { wrappingComponent: TestProviders }); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it shows the warning callout when configuration is invalid', () => { + expect( + wrapper.find('[data-test-subj="configure-cases-warning-callout"]').exists() + ).toBeTruthy(); + }); - expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true); + test('it disables the update connector button when the connectorId is invalid', () => { + expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + }); }); - test('it disables correctly ClosureOptions when saving configuration', () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - persistLoading: true, - })); + describe('Happy path', () => { + let wrapper: ReactWrapper; + + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '123', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + })); + useConnectorsMock.mockImplementation(() => useConnectorsResponse); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + + wrapper = mount(, { wrappingComponent: TestProviders }); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it renders the ConnectorEditFlyout', () => { + expect(wrapper.find(ConnectorEditFlyout).exists()).toBeTruthy(); + }); - expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true); - }); + test('it renders with correct props', () => { + // Connector + expect(wrapper.find(Connectors).prop('connectors')).toEqual(connectors); + expect(wrapper.find(Connectors).prop('disabled')).toBe(false); + expect(wrapper.find(Connectors).prop('isLoading')).toBe(false); + expect(wrapper.find(Connectors).prop('selectedConnector')).toBe('123'); + + // ClosureOptions + expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(false); + expect(wrapper.find(ClosureOptions).prop('closureTypeSelected')).toBe('close-by-user'); + + // Mapping + expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + expect(wrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(false); + expect(wrapper.find(Mapping).prop('mapping')).toEqual( + connectors[0].config.casesConfiguration.mapping + ); + + // Flyouts + expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false); + expect(wrapper.find(ConnectorAddFlyout).prop('actionTypes')).toEqual([ + { + id: '.servicenow', + name: 'ServiceNow', + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'platinum', + }, + ]); + + expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(false); + expect(wrapper.find(ConnectorEditFlyout).prop('initialConnector')).toEqual(connectors[0]); + }); - test('it disables correctly ClosureOptions when the connector is set to none', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('none'), []); - return useCaseConfigureResponse; - } - ); + test('it does not shows the action bar when there is no change', () => { + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it disables the mapping permanently', () => { + expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + }); - expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true); - }); + test('it sets the mapping of a connector correctly', () => { + expect(wrapper.find(Mapping).prop('mapping')).toEqual( + connectors[0].config.casesConfiguration.mapping + ); + }); - test('it disables the mapping permanently', () => { - expect(wrapper.find(Mapping).prop('disabled')).toBe(true); - }); + // TODO: When mapping is enabled the test.todo should be implemented. + test.todo('the mapping is changed successfully when changing the third party'); + test.todo('the mapping is changed successfully when changing the action type'); + test.todo('it disables the update connector button when loading the configuration'); - test('it disables the update connector button when loading the connectors', () => { - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); + test('it disables correctly when the user cannot crud', () => { + const newWrapper = mount(, { + wrappingComponent: TestProviders, + }); - expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + expect(newWrapper.find(Connectors).prop('disabled')).toBe(true); + expect(newWrapper.find(ClosureOptions).prop('disabled')).toBe(true); + expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); + expect(newWrapper.find(Mapping).prop('updateConnectorDisabled')).toBe(true); + }); }); - test('it disables the update connector button when loading the configuration', () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - loading: true, - })); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); + describe('loading connectors', () => { + let wrapper: ReactWrapper; + + beforeEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); + useCaseConfigureMock.mockImplementation(() => useCaseConfigureResponse); + useConnectorsMock.mockImplementation(() => ({ + ...useConnectorsResponse, + loading: true, + })); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + wrapper = mount(, { wrappingComponent: TestProviders }); + }); - expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); - }); + test('it disables correctly Connector when loading connectors', () => { + expect(wrapper.find(Connectors).prop('disabled')).toBe(true); + }); - test('it disables the update connector button when saving the configuration', () => { - useCaseConfigureMock.mockImplementation(() => ({ - ...useCaseConfigureResponse, - persistLoading: true, - })); + test('it pass the correct value to isLoading attribute on Connector', () => { + expect(wrapper.find(Connectors).prop('isLoading')).toBe(true); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it disables correctly ClosureOptions when loading connectors', () => { + expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true); + }); - expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); + test('it disables the update connector button when loading the connectors', () => { + expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + }); + test('it disables the buttons of action bar when loading connectors', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + })); + const newWrapper = mount(, { + wrappingComponent: TestProviders, + }); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + }); }); - test('it disables the update connector button when the connectorId is invalid', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('not-id'), []); - return useCaseConfigureResponse; - } - ); + describe('saving configuration', () => { + let wrapper: ReactWrapper; - const newWrapper = mount(, { wrappingComponent: TestProviders }); + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + persistLoading: true, + })); - expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); - }); - - test('it disables the update connector button when the connectorId is set to none', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('none'), []); - return useCaseConfigureResponse; - } - ); + useConnectorsMock.mockImplementation(() => useConnectorsResponse); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + wrapper = mount(, { wrappingComponent: TestProviders }); + }); - const newWrapper = mount(, { wrappingComponent: TestProviders }); + test('it disables correctly Connector when saving configuration', () => { + expect(wrapper.find(Connectors).prop('disabled')).toBe(true); + }); - expect(newWrapper.find(Mapping).prop('disabled')).toBe(true); - }); + test('it disables correctly ClosureOptions when saving configuration', () => { + expect(wrapper.find(ClosureOptions).prop('disabled')).toBe(true); + }); - test('it show the edit flyout when pressing the update connector button', () => { - wrapper.find('button[data-test-subj="case-mapping-update-connector-button"]').simulate('click'); - wrapper.update(); + test('it disables the update connector button when saving the configuration', () => { + expect(wrapper.find(Mapping).prop('disabled')).toBe(true); + }); - expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true); - expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy(); - }); + test('it disables the buttons of action bar when saving configuration', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + persistLoading: true, + })); + + const newWrapper = mount(, { + wrappingComponent: TestProviders, + }); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + }); - test('it sets the mapping of a connector correctly', () => { - expect(wrapper.find(Mapping).prop('mapping')).toEqual( - connectors[0].config.casesConfiguration.mapping - ); + test('it shows the loading spinner when saving configuration', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + persistLoading: true, + })); + + const newWrapper = mount(, { + wrappingComponent: TestProviders, + }); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') + .first() + .prop('isLoading') + ).toBe(true); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') + .first() + .prop('isLoading') + ).toBe(true); + }); }); - // TODO: When mapping is enabled the test.todo should be implemented. - test.todo('the mapping is changed successfully when changing the third party'); - test.todo('the mapping is changed successfully when changing the action type'); - - test('it does not shows the action bar when there is no change', () => { - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); - }); + describe('update connector', () => { + let wrapper: ReactWrapper; + const persistCaseConfigure = jest.fn(); - test('it shows the action bar when the connector is changed', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); - wrapper.update(); + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + persistCaseConfigure, + })); + useConnectorsMock.mockImplementation(() => useConnectorsResponse); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + + wrapper = mount(, { wrappingComponent: TestProviders }); + }); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeTruthy(); - expect( + test('it submits the configuration correctly', () => { wrapper - .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') .first() - .text() - ).toBe('1 unsaved changes'); - }); - - test('it shows the action bar when the closure type is changed', () => { - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); + .simulate('click'); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeTruthy(); - expect( - wrapper - .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') - .first() - .text() - ).toBe('1 unsaved changes'); - }); + wrapper.update(); - test('it tracks the changes successfully', () => { - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); - wrapper.update(); - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); - - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeTruthy(); - expect( - wrapper - .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') - .first() - .text() - ).toBe('2 unsaved changes'); - }); + expect(persistCaseConfigure).toHaveBeenCalled(); + expect(persistCaseConfigure).toHaveBeenCalledWith({ + connectorId: '456', + connectorName: 'My Connector 2', + closureType: 'close-by-user', + }); + }); - test('it tracks and reverts the changes successfully ', () => { - // change settings - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); - wrapper.update(); - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); - - // revert back to initial settings - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-123"]').simulate('click'); - wrapper.update(); - wrapper.find('input[id="close-by-user"]').simulate('change'); - wrapper.update(); - - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); + test('it has the correct url on cancel button', () => { + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') + .first() + .prop('href') + ).toBe(`#/link-to/case${searchURL}`); + }); + test('it disables the buttons of action bar when loading configuration', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-user', + }, + loading: true, + })); + const newWrapper = mount(, { + wrappingComponent: TestProviders, + }); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + + expect( + newWrapper + .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') + .first() + .prop('isDisabled') + ).toBe(true); + }); }); - test('it close and restores the action bar when the add connector button is pressed', () => { - // Change closure type - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); + describe('user interactions', () => { + beforeEach(() => { + jest.resetAllMocks(); + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '456', + closureType: 'close-by-user', + }, + })); + useConnectorsMock.mockImplementation(() => useConnectorsResponse); + useKibanaMock.mockImplementation(() => kibanaMockImplementationArgs); + useGetUrlSearchMock.mockImplementation(() => searchURL); + }); - // Press add connector button - wrapper.find('button[data-test-subj="case-configure-add-connector-button"]').simulate('click'); - wrapper.update(); + test('it show the add flyout when pressing the add connector button', () => { + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper + .find('button[data-test-subj="case-configure-add-connector-button"]') + .simulate('click'); + wrapper.update(); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); + expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true); + expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy(); + }); - expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true); + test('it show the edit flyout when pressing the update connector button', () => { + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper + .find('button[data-test-subj="case-mapping-update-connector-button"]') + .simulate('click'); + wrapper.update(); - // Close the add flyout - wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click'); - wrapper.update(); + expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true); + expect(wrapper.find(EuiBottomBar).exists()).toBeFalsy(); + }); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeTruthy(); + test('it tracks the changes successfully', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'unchanged', + currentConfiguration: { + connectorName: 'unchanged', + connectorId: '123', + closureType: 'close-by-pushing', + }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); + wrapper.update(); + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .first() + .text() + ).toBe('2 unsaved changes'); + }); + test('it tracks the changes successfully when name changes', () => { + useCaseConfigureMock.mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + connectorName: 'nameChange', + currentConfiguration: { + connectorId: '123', + closureType: 'close-by-pushing', + connectorName: 'before', + }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); + wrapper.update(); + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .first() + .text() + ).toBe('2 unsaved changes'); + }); - expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false); + test('it tracks and reverts the changes successfully ', () => { + const wrapper = mount(, { wrappingComponent: TestProviders }); + // change settings + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); + wrapper.update(); + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + // revert back to initial settings + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-123"]').simulate('click'); + wrapper.update(); + wrapper.find('input[id="close-by-user"]').simulate('change'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); + }); - expect( + test('it close and restores the action bar when the add connector button is pressed', () => { + useCaseConfigureMock + .mockImplementationOnce(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })) + .mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-pushing', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + // Change closure type + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); + + // Press add connector button wrapper - .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') - .first() - .text() - ).toBe('1 unsaved changes'); - }); + .find('button[data-test-subj="case-configure-add-connector-button"]') + .simulate('click'); + wrapper.update(); - test('it close and restores the action bar when the update connector button is pressed', () => { - // Change closure type - wrapper.find('input[id="close-by-pushing"]').simulate('change'); - wrapper.update(); + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); - // Press update connector button - wrapper.find('button[data-test-subj="case-mapping-update-connector-button"]').simulate('click'); - wrapper.update(); + expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(true); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); + // Close the add flyout + wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click'); + wrapper.update(); - expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true); + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); - // Close the edit flyout - wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click'); - wrapper.update(); + expect(wrapper.find(ConnectorAddFlyout).prop('addFlyoutVisible')).toBe(false); - expect( - wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeTruthy(); - - expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(false); + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .first() + .text() + ).toBe('1 unsaved changes'); + }); - expect( + test('it close and restores the action bar when the update connector button is pressed', () => { + useCaseConfigureMock + .mockImplementationOnce(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })) + .mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-pushing', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + + // Change closure type + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + // Press update connector button wrapper - .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') - .first() - .text() - ).toBe('1 unsaved changes'); - }); + .find('button[data-test-subj="case-mapping-update-connector-button"]') + .simulate('click'); + wrapper.update(); - test('it disables the buttons of action bar when loading connectors', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return useCaseConfigureResponse; - } - ); - - useConnectorsMock.mockImplementation(() => ({ - ...useConnectorsResponse, - loading: true, - })); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') - .first() - .prop('isDisabled') - ).toBe(true); + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') - .first() - .prop('isDisabled') - ).toBe(true); - }); + expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(true); - test('it disables the buttons of action bar when loading configuration', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return { ...useCaseConfigureResponse, loading: true }; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') - .first() - .prop('isDisabled') - ).toBe(true); + // Close the edit flyout + wrapper.find('button[data-test-subj="euiFlyoutCloseButton"]').simulate('click'); + wrapper.update(); - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') - .first() - .prop('isDisabled') - ).toBe(true); - }); + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); - test('it disables the buttons of action bar when saving configuration', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return { ...useCaseConfigureResponse, persistLoading: true }; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') - .first() - .prop('isDisabled') - ).toBe(true); + expect(wrapper.find(ConnectorEditFlyout).prop('editFlyoutVisible')).toBe(false); - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') - .first() - .prop('isDisabled') - ).toBe(true); - }); + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .first() + .text() + ).toBe('1 unsaved changes'); + }); - test('it shows the loading spinner when saving configuration', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return { ...useCaseConfigureResponse, persistLoading: true }; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') - .first() - .prop('isLoading') - ).toBe(true); + test('it shows the action bar when the connector is changed', () => { + useCaseConfigureMock + .mockImplementationOnce(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '123', + currentConfiguration: { connectorId: '123', closureType: 'close-by-user' }, + })) + .mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + currentConfiguration: { connectorId: '123', closureType: 'close-by-user' }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-456"]').simulate('click'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="case-configure-action-bottom-bar-total-changes"]') + .first() + .text() + ).toBe('1 unsaved changes'); + }); + + test('it closes the action bar when pressing save', () => { + useCaseConfigureMock + .mockImplementationOnce(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-user', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })) + .mockImplementation(() => ({ + ...useCaseConfigureResponse, + mapping, + closureType: 'close-by-pushing', + connectorId: '456', + currentConfiguration: { connectorId: '456', closureType: 'close-by-user' }, + })); + const wrapper = mount(, { wrappingComponent: TestProviders }); + wrapper.find('input[id="close-by-pushing"]').simulate('change'); + wrapper.update(); + + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeTruthy(); - expect( - newWrapper + wrapper .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') .first() - .prop('isLoading') - ).toBe(true); - }); + .simulate('click'); - test('it closes the action bar when pressing save', () => { - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return useCaseConfigureResponse; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') - .first() - .simulate('click'); - - newWrapper.update(); - - expect( - newWrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() - ).toBeFalsy(); - }); - - test('it submits the configuration correctly', () => { - const persistCaseConfigure = jest.fn(); + wrapper.update(); - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-pushing', - }), - [] - ); - return { ...useCaseConfigureResponse, persistCaseConfigure }; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-save-button"]') - .first() - .simulate('click'); - - newWrapper.update(); - - expect(persistCaseConfigure).toHaveBeenCalled(); - expect(persistCaseConfigure).toHaveBeenCalledWith({ - connectorId: '456', - connectorName: 'My Connector 2', - closureType: 'close-by-user', + expect( + wrapper.find('[data-test-subj="case-configure-action-bottom-bar"]').exists() + ).toBeFalsy(); }); }); - - test('it has the correct url on cancel button', () => { - const persistCaseConfigure = jest.fn(); - - useCaseConfigureMock.mockImplementation( - ({ setConnector, setClosureType, setCurrentConfiguration }) => { - useEffect(() => setConnector('456'), []); - useEffect(() => setClosureType('close-by-user'), []); - useEffect( - () => - setCurrentConfiguration({ - connectorId: '123', - closureType: 'close-by-user', - }), - [] - ); - return { ...useCaseConfigureResponse, persistCaseConfigure }; - } - ); - - const newWrapper = mount(, { wrappingComponent: TestProviders }); - - expect( - newWrapper - .find('[data-test-subj="case-configure-action-bottom-bar-cancel-button"]') - .first() - .prop('href') - ).toBe(`#/link-to/case${searchURL}`); - }); }); diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx index 241dcef14a145..cdb8966d81342 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/index.tsx @@ -4,14 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { - useReducer, - useCallback, - useEffect, - useState, - Dispatch, - SetStateAction, -} from 'react'; +import React, { useCallback, useEffect, useState, Dispatch, SetStateAction } from 'react'; import styled, { css } from 'styled-components'; import { @@ -38,17 +31,12 @@ import { import { ActionConnectorTableItem } from '../../../../../../../../plugins/triggers_actions_ui/public/types'; import { getCaseUrl } from '../../../../components/link_to'; import { useGetUrlSearch } from '../../../../components/navigation/use_get_url_search'; -import { - ClosureType, - CasesConfigurationMapping, - CCMapsCombinedActionAttributes, -} from '../../../../containers/case/configure/types'; +import { CCMapsCombinedActionAttributes } from '../../../../containers/case/configure/types'; import { Connectors } from '../configure_cases/connectors'; import { ClosureOptions } from '../configure_cases/closure_options'; import { Mapping } from '../configure_cases/mapping'; import { SectionWrapper } from '../wrappers'; import { navTabs } from '../../../../pages/home/home_navigations'; -import { configureCasesReducer, State, CurrentConfiguration } from './reducer'; import * as i18n from './translations'; const FormWrapper = styled.div` @@ -66,13 +54,6 @@ const FormWrapper = styled.div` `} `; -const initialState: State = { - connectorId: 'none', - closureType: 'close-by-user', - mapping: null, - currentConfiguration: { connectorId: 'none', closureType: 'close-by-user' }, -}; - const actionTypes: ActionType[] = [ { id: '.servicenow', @@ -102,44 +83,18 @@ const ConfigureCasesComponent: React.FC = ({ userC const [actionBarVisible, setActionBarVisible] = useState(false); const [totalConfigurationChanges, setTotalConfigurationChanges] = useState(0); - const [{ connectorId, closureType, mapping, currentConfiguration }, dispatch] = useReducer( - configureCasesReducer(), - initialState - ); - - const setCurrentConfiguration = useCallback((configuration: CurrentConfiguration) => { - dispatch({ - type: 'setCurrentConfiguration', - currentConfiguration: { ...configuration }, - }); - }, []); - - const setConnectorId = useCallback((newConnectorId: string) => { - dispatch({ - type: 'setConnectorId', - connectorId: newConnectorId, - }); - }, []); - - const setClosureType = useCallback((newClosureType: ClosureType) => { - dispatch({ - type: 'setClosureType', - closureType: newClosureType, - }); - }, []); - - const setMapping = useCallback((newMapping: CasesConfigurationMapping[]) => { - dispatch({ - type: 'setMapping', - mapping: newMapping, - }); - }, []); - - const { loading: loadingCaseConfigure, persistLoading, persistCaseConfigure } = useCaseConfigure({ - setConnector: setConnectorId, + const { + connectorId, + closureType, + mapping, + currentConfiguration, + loading: loadingCaseConfigure, + persistLoading, + persistCaseConfigure, + setConnector, setClosureType, - setCurrentConfiguration, - }); + setMapping, + } = useCaseConfigure(); const { loading: isLoadingConnectors, connectors, refetchConnectors } = useConnectors(); @@ -173,17 +128,15 @@ const ConfigureCasesComponent: React.FC = ({ userC }, []); const handleActionBar = useCallback(() => { - const unsavedChanges = difference(Object.values(currentConfiguration), [ + const currentConfigurationMinusName = { + connectorId: currentConfiguration.connectorId, + closureType: currentConfiguration.closureType, + }; + const unsavedChanges = difference(Object.values(currentConfigurationMinusName), [ connectorId, closureType, ]).length; - - if (unsavedChanges === 0) { - setActionBarVisible(false); - } else { - setActionBarVisible(true); - } - + setActionBarVisible(!(unsavedChanges === 0)); setTotalConfigurationChanges(unsavedChanges); }, [currentConfiguration, connectorId, closureType]); @@ -246,7 +199,13 @@ const ConfigureCasesComponent: React.FC = ({ userC useEffect(() => { handleActionBar(); - }, [connectors, connectorId, closureType, currentConfiguration]); + }, [ + connectors, + connectorId, + closureType, + currentConfiguration.connectorId, + currentConfiguration.closureType, + ]); return ( @@ -267,7 +226,7 @@ const ConfigureCasesComponent: React.FC = ({ userC connectors={connectors ?? []} disabled={persistLoading || isLoadingConnectors || !userCanCrud} isLoading={isLoadingConnectors} - onChangeConnector={setConnectorId} + onChangeConnector={setConnector} handleShowAddFlyout={onClickAddConnector} selectedConnector={connectorId} /> diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.test.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.test.ts deleted file mode 100644 index df958b75dc6b8..0000000000000 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { configureCasesReducer, Action, State } from './reducer'; -import { initialState, mapping } from './__mock__'; - -describe('Reducer', () => { - let reducer: (state: State, action: Action) => State; - - beforeAll(() => { - reducer = configureCasesReducer(); - }); - - test('it should set the correct configuration', () => { - const action: Action = { - type: 'setCurrentConfiguration', - currentConfiguration: { connectorId: '123', closureType: 'close-by-user' }, - }; - const state = reducer(initialState, action); - - expect(state).toEqual({ - ...state, - currentConfiguration: action.currentConfiguration, - }); - }); - - test('it should set the correct connector id', () => { - const action: Action = { - type: 'setConnectorId', - connectorId: '456', - }; - const state = reducer(initialState, action); - - expect(state).toEqual({ - ...state, - connectorId: action.connectorId, - }); - }); - - test('it should set the closure type', () => { - const action: Action = { - type: 'setClosureType', - closureType: 'close-by-pushing', - }; - const state = reducer(initialState, action); - - expect(state).toEqual({ - ...state, - closureType: action.closureType, - }); - }); - - test('it should set the mapping', () => { - const action: Action = { - type: 'setMapping', - mapping, - }; - const state = reducer(initialState, action); - - expect(state).toEqual({ - ...state, - mapping: action.mapping, - }); - }); -}); diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.ts b/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.ts deleted file mode 100644 index f6b9d38a76de3..0000000000000 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/configure_cases/reducer.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - ClosureType, - CasesConfigurationMapping, -} from '../../../../containers/case/configure/types'; - -export interface State { - mapping: CasesConfigurationMapping[] | null; - connectorId: string; - closureType: ClosureType; - currentConfiguration: CurrentConfiguration; -} - -export interface CurrentConfiguration { - connectorId: State['connectorId']; - closureType: State['closureType']; -} - -export type Action = - | { - type: 'setCurrentConfiguration'; - currentConfiguration: CurrentConfiguration; - } - | { - type: 'setConnectorId'; - connectorId: string; - } - | { - type: 'setClosureType'; - closureType: ClosureType; - } - | { - type: 'setMapping'; - mapping: CasesConfigurationMapping[]; - }; - -export const configureCasesReducer = () => (state: State, action: Action) => { - switch (action.type) { - case 'setCurrentConfiguration': { - return { - ...state, - currentConfiguration: { ...action.currentConfiguration }, - }; - } - case 'setConnectorId': { - return { - ...state, - connectorId: action.connectorId, - }; - } - case 'setClosureType': { - return { - ...state, - closureType: action.closureType, - }; - } - case 'setMapping': { - return { - ...state, - mapping: action.mapping, - }; - } - default: - return state; - } -}; diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx index 5092cba6872e3..6109fd05096b9 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/use_push_to_service/index.tsx @@ -6,7 +6,7 @@ import { EuiButton, EuiLink, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useCallback, useState, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useCaseConfigure } from '../../../../containers/case/configure/use_configure'; import { Case } from '../../../../containers/case/types'; @@ -27,11 +27,6 @@ export interface UsePushToService { userCanCrud: boolean; } -interface Connector { - connectorId: string; - connectorName: string; -} - export interface ReturnUsePushToService { pushButton: JSX.Element; pushCallouts: JSX.Element | null; @@ -45,40 +40,30 @@ export const usePushToService = ({ userCanCrud, }: UsePushToService): ReturnUsePushToService => { const urlSearch = useGetUrlSearch(navTabs.case); - const [connector, setConnector] = useState(null); const { isLoading, postPushToService } = usePostPushToService(); - const handleSetConnector = useCallback((connectorId: string, connectorName?: string) => { - setConnector({ connectorId, connectorName: connectorName ?? '' }); - }, []); - - const { loading: loadingCaseConfigure } = useCaseConfigure({ - setConnector: handleSetConnector, - }); + const { connectorId, connectorName, loading: loadingCaseConfigure } = useCaseConfigure(); const { isLoading: loadingLicense, actionLicense } = useGetActionLicense(); const handlePushToService = useCallback(() => { - if (connector != null) { + if (connectorId != null) { postPushToService({ caseId, - ...connector, + connectorId, + connectorName, updateCase, }); } - }, [caseId, connector, postPushToService, updateCase]); + }, [caseId, connectorId, connectorName, postPushToService, updateCase]); const errorsMsg = useMemo(() => { let errors: Array<{ title: string; description: JSX.Element }> = []; if (actionLicense != null && !actionLicense.enabledInLicense) { errors = [...errors, getLicenseError()]; } - if ( - (connector == null || (connector != null && connector.connectorId === 'none')) && - !loadingCaseConfigure && - !loadingLicense - ) { + if (connectorId === 'none' && !loadingCaseConfigure && !loadingLicense) { errors = [ ...errors, { @@ -117,7 +102,7 @@ export const usePushToService = ({ errors = [...errors, getKibanaConfigError()]; } return errors; - }, [actionLicense, caseStatus, connector, loadingCaseConfigure, loadingLicense, urlSearch]); + }, [actionLicense, caseStatus, connectorId, loadingCaseConfigure, loadingLicense, urlSearch]); const pushToServiceButton = useMemo( () => ( diff --git a/x-pack/package.json b/x-pack/package.json index d0025ff436649..ca73884b8c7c7 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -121,7 +121,7 @@ "cheerio": "0.22.0", "commander": "3.0.2", "copy-webpack-plugin": "^5.0.4", - "cypress": "^4.2.0", + "cypress": "^4.4.1", "cypress-multi-reporters": "^1.2.3", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.2", diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index d6c85606edc2c..decd170ca5dd6 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -143,7 +143,8 @@ This is the primary function for an action type. Whenever the action needs to ex | actionId | The action saved object id that the action type is executing for. | | config | The decrypted configuration given to an action. This comes from the action saved object that is partially or fully encrypted within the data store. If you would like to validate the config before being passed to the executor, define `validate.config` within the action type. | | params | Parameters for the execution. These will be given at execution time by either an alert or manually provided when calling the plugin provided execute function. | -| services.callCluster(path, opts) | Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana.

**NOTE**: This currently authenticates as the Kibana internal user, but will change in a future PR. | +| services.callCluster(path, opts) | Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but runs in the context of the user who is calling the action when security is enabled.| +| services.getScopedCallCluster | This function scopes an instance of CallCluster by returning a `callCluster(path, opts)` function that runs in the context of the user who is calling the action when security is enabled. This must only be called with instances of CallCluster provided by core.| | services.savedObjectsClient | This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

The scope of the saved objects client is tied to the user in context calling the execute API or the API key provided to the execute plugin function (only when security isenabled). | | services.log(tags, [data], [timestamp]) | Use this to create server logs. (This is the same function as server.log) | diff --git a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts index 265ff267f222e..18b434e980eb9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/email.test.ts @@ -9,13 +9,13 @@ jest.mock('./lib/send_email', () => ({ })); import { Logger } from '../../../../../src/core/server'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { ActionType, ActionTypeExecutorOptions } from '../types'; import { actionsConfigMock } from '../actions_config.mock'; import { validateConfig, validateSecrets, validateParams } from '../lib'; import { createActionTypeRegistry } from './index.test'; import { sendEmail } from './lib/send_email'; +import { actionsMock } from '../mocks'; import { ActionParamsType, ActionTypeConfigType, @@ -26,13 +26,8 @@ import { const sendEmailMock = sendEmail as jest.Mock; const ACTION_TYPE_ID = '.email'; -const NO_OP_FN = () => {}; -const services = { - log: NO_OP_FN, - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services = actionsMock.createServices(); let actionType: ActionType; let mockedLogger: jest.Mocked; diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts index ed57e44c3f0b3..be60f4c2f28af 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.test.ts @@ -10,18 +10,13 @@ jest.mock('./lib/send_email', () => ({ import { ActionType, ActionTypeExecutorOptions } from '../types'; import { validateConfig, validateParams } from '../lib'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { createActionTypeRegistry } from './index.test'; import { ActionParamsType, ActionTypeConfigType } from './es_index'; +import { actionsMock } from '../mocks'; const ACTION_TYPE_ID = '.index'; -const NO_OP_FN = () => {}; -const services = { - log: NO_OP_FN, - callCluster: jest.fn(), - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services = actionsMock.createServices(); let actionType: ActionType; @@ -196,9 +191,9 @@ describe('execute()', () => { await actionType.executor(executorOptions); const calls = services.callCluster.mock.calls; - const timeValue = calls[0][1].body[1].field_to_use_for_time; + const timeValue = calls[0][1]?.body[1].field_to_use_for_time; expect(timeValue).toBeInstanceOf(Date); - delete calls[0][1].body[1].field_to_use_for_time; + delete calls[0][1]?.body[1].field_to_use_for_time; expect(calls).toMatchInlineSnapshot(` Array [ Array [ diff --git a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts index 32f5e23015700..899684367d52d 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/es_index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/es_index.ts @@ -72,7 +72,7 @@ async function executor( bulkBody.push(document); } - const bulkParams: unknown = { + const bulkParams = { index, body: bulkBody, refresh: config.refresh, diff --git a/x-pack/plugins/actions/server/builtin_action_types/pagerduty.test.ts b/x-pack/plugins/actions/server/builtin_action_types/pagerduty.test.ts index e54c8179ae7b4..1bca7c18e4e1b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/pagerduty.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/pagerduty.test.ts @@ -11,20 +11,17 @@ jest.mock('./lib/post_pagerduty', () => ({ import { getActionType } from './pagerduty'; import { ActionType, Services, ActionTypeExecutorOptions } from '../types'; import { validateConfig, validateSecrets, validateParams } from '../lib'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { postPagerduty } from './lib/post_pagerduty'; import { createActionTypeRegistry } from './index.test'; import { Logger } from '../../../../../src/core/server'; import { actionsConfigMock } from '../actions_config.mock'; +import { actionsMock } from '../mocks'; const postPagerdutyMock = postPagerduty as jest.Mock; const ACTION_TYPE_ID = '.pagerduty'; -const services: Services = { - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services: Services = actionsMock.createServices(); let actionType: ActionType; let mockedLogger: jest.Mocked; diff --git a/x-pack/plugins/actions/server/builtin_action_types/server_log.test.ts b/x-pack/plugins/actions/server/builtin_action_types/server_log.test.ts index 3ce01c59596f6..d5a9c0cc1ccd2 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/server_log.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/server_log.test.ts @@ -7,8 +7,8 @@ import { ActionType } from '../types'; import { validateParams } from '../lib'; import { Logger } from '../../../../../src/core/server'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { createActionTypeRegistry } from './index.test'; +import { actionsMock } from '../mocks'; const ACTION_TYPE_ID = '.server-log'; @@ -90,10 +90,7 @@ describe('execute()', () => { const actionId = 'some-id'; await actionType.executor({ actionId, - services: { - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), - }, + services: actionsMock.createServices(), params: { message: 'message text here', level: 'info' }, config: {}, secrets: {}, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts index 08b837cf8d0a5..a6c3ae88765ac 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts @@ -7,9 +7,9 @@ import { getActionType } from '.'; import { ActionType, Services, ActionTypeExecutorOptions } from '../../types'; import { validateConfig, validateSecrets, validateParams } from '../../lib'; -import { savedObjectsClientMock } from '../../../../../../src/core/server/mocks'; import { createActionTypeRegistry } from '../index.test'; import { actionsConfigMock } from '../../actions_config.mock'; +import { actionsMock } from '../../mocks'; import { ACTION_TYPE_ID } from './constants'; import * as i18n from './translations'; @@ -21,10 +21,7 @@ jest.mock('./action_handlers'); const handleIncidentMock = handleIncident as jest.Mock; -const services: Services = { - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services: Services = actionsMock.createServices(); let actionType: ActionType; diff --git a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts index 22c4b63474fdc..cbcd4b2954518 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/slack.test.ts @@ -10,17 +10,14 @@ import { ActionTypeExecutorOptions, ActionTypeExecutorResult, } from '../types'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { validateParams, validateSecrets } from '../lib'; import { getActionType } from './slack'; import { actionsConfigMock } from '../actions_config.mock'; +import { actionsMock } from '../mocks'; const ACTION_TYPE_ID = '.slack'; -const services: Services = { - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services: Services = actionsMock.createServices(); let actionType: ActionType; diff --git a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts index 1beaf92f3f48b..d28856954cca5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/webhook.test.ts @@ -11,20 +11,17 @@ jest.mock('axios', () => ({ import { getActionType } from './webhook'; import { ActionType, Services } from '../types'; import { validateConfig, validateSecrets, validateParams } from '../lib'; -import { savedObjectsClientMock } from '../../../../../src/core/server/mocks'; import { actionsConfigMock } from '../actions_config.mock'; import { createActionTypeRegistry } from './index.test'; import { Logger } from '../../../../../src/core/server'; +import { actionsMock } from '../mocks'; import axios from 'axios'; const axiosRequestMock = axios.request as jest.Mock; const ACTION_TYPE_ID = '.webhook'; -const services: Services = { - callCluster: async (path: string, opts: unknown) => {}, - savedObjectsClient: savedObjectsClientMock.create(), -}; +const services: Services = actionsMock.createServices(); let actionType: ActionType; let mockedLogger: jest.Mocked; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index d6719dc08225e..4594fc1ddf6d9 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -9,21 +9,15 @@ import { schema } from '@kbn/config-schema'; import { ActionExecutor } from './action_executor'; import { actionTypeRegistryMock } from '../action_type_registry.mock'; import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks'; -import { savedObjectsClientMock, loggingServiceMock } from '../../../../../src/core/server/mocks'; +import { loggingServiceMock } from '../../../../../src/core/server/mocks'; import { eventLoggerMock } from '../../../event_log/server/mocks'; import { spacesServiceMock } from '../../../spaces/server/spaces_service/spaces_service.mock'; import { ActionType } from '../types'; +import { actionsMock } from '../mocks'; const actionExecutor = new ActionExecutor({ isESOUsingEphemeralEncryptionKey: false }); -const savedObjectsClient = savedObjectsClientMock.create(); - -function getServices() { - return { - savedObjectsClient, - log: jest.fn(), - callCluster: jest.fn(), - }; -} +const services = actionsMock.createServices(); +const savedObjectsClient = services.savedObjectsClient; const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -39,7 +33,7 @@ const spacesMock = spacesServiceMock.createSetupContract(); actionExecutor.initialize({ logger: loggingServiceMock.create().get(), spaces: spacesMock, - getServices, + getServices: () => services, actionTypeRegistry, encryptedSavedObjectsPlugin, eventLogger: eventLoggerMock.create(), @@ -273,7 +267,7 @@ test('throws an error when passing isESOUsingEphemeralEncryptionKey with value o customActionExecutor.initialize({ logger: loggingServiceMock.create().get(), spaces: spacesMock, - getServices, + getServices: () => services, actionTypeRegistry, encryptedSavedObjectsPlugin, eventLogger: eventLoggerMock.create(), diff --git a/x-pack/plugins/actions/server/mocks.ts b/x-pack/plugins/actions/server/mocks.ts index 95c8b094dfd70..4160ace50f491 100644 --- a/x-pack/plugins/actions/server/mocks.ts +++ b/x-pack/plugins/actions/server/mocks.ts @@ -6,6 +6,11 @@ import { actionsClientMock } from './actions_client.mock'; import { PluginSetupContract, PluginStartContract } from './plugin'; +import { Services } from './types'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, +} from '../../../../src/core/server/mocks'; export { actionsClientMock }; @@ -27,7 +32,19 @@ const createStartMock = () => { return mock; }; +const createServicesMock = () => { + const mock: jest.Mocked; + }> = { + callCluster: elasticsearchServiceMock.createScopedClusterClient().callAsCurrentUser, + getScopedCallCluster: jest.fn(), + savedObjectsClient: savedObjectsClientMock.create(), + }; + return mock; +}; + export const actionsMock = { + createServices: createServicesMock, createSetup: createSetupMock, createStart: createStartMock, }; diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 4c2c8d214f976..10e4d64584340 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -18,6 +18,7 @@ import { IContextProvider, SavedObjectsServiceStart, ElasticsearchServiceStart, + IClusterClient, } from '../../../../src/core/server'; import { @@ -302,6 +303,9 @@ export class ActionsPlugin implements Plugin, Plugi return request => ({ callCluster: elasticsearch.legacy.client.asScoped(request).callAsCurrentUser, savedObjectsClient: savedObjects.getScopedClient(request), + getScopedCallCluster(clusterClient: IClusterClient) { + return clusterClient.asScoped(request).callAsCurrentUser; + }, }); } diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index 9dcfdb81f5ebb..093d22c2c1a71 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -4,15 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - SavedObjectsClientContract, - SavedObjectAttributes, - KibanaRequest, -} from '../../../../src/core/server'; import { ActionTypeRegistry } from './action_type_registry'; import { PluginSetupContract, PluginStartContract } from './plugin'; import { ActionsClient } from './actions_client'; import { LicenseType } from '../../licensing/common/types'; +import { + IClusterClient, + IScopedClusterClient, + KibanaRequest, + SavedObjectsClientContract, + SavedObjectAttributes, +} from '../../../../src/core/server'; export type WithoutQueryAndParams = Pick>; export type GetServicesFunction = (request: KibanaRequest) => Services; @@ -21,8 +23,9 @@ export type GetBasePathFunction = (spaceId?: string) => string; export type SpaceIdToNamespaceFunction = (spaceId?: string) => string | undefined; export interface Services { - callCluster(path: string, opts: unknown): Promise; + callCluster: IScopedClusterClient['callAsCurrentUser']; savedObjectsClient: SavedObjectsClientContract; + getScopedCallCluster(clusterClient: IClusterClient): IScopedClusterClient['callAsCurrentUser']; } declare module 'src/core/server' { diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 177e42de5a95b..62c2caed669af 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -101,6 +101,7 @@ This is the primary function for an alert type. Whenever the alert needs to exec |---|---| |services.callCluster(path, opts)|Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but in the context of the user who created the alert when security is enabled.| |services.savedObjectsClient|This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

The scope of the saved objects client is tied to the user who created the alert (only when security isenabled).| +|services.getScopedCallCluster|This function scopes an instance of CallCluster by returning a `callCluster(path, opts)` function that runs in the context of the user who created the alert when security is enabled. This must only be called with instances of CallCluster provided by core.| |services.log(tags, [data], [timestamp])|Use this to create server logs. (This is the same function as server.log)| |startedAt|The date and time the alert type started execution.| |previousStartedAt|The previous date and time the alert type started a successful execution.| diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index a9e224142a632..c94a7aba46cfa 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -6,8 +6,11 @@ import { alertsClientMock } from './alerts_client.mock'; import { PluginSetupContract, PluginStartContract } from './plugin'; -import { savedObjectsClientMock } from '../../../../src/core/server/mocks'; import { AlertInstance } from './alert_instance'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, +} from '../../../../src/core/server/mocks'; export { alertsClientMock }; @@ -55,7 +58,8 @@ const createAlertServicesMock = () => { alertInstanceFactory: jest .fn, [string]>() .mockReturnValue(alertInstanceFactoryMock), - callCluster: jest.fn(), + callCluster: elasticsearchServiceMock.createScopedClusterClient().callAsCurrentUser, + getScopedCallCluster: jest.fn(), savedObjectsClient: savedObjectsClientMock.create(), }; }; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 35ebafce9dc67..c03d3506a051d 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -29,6 +29,7 @@ import { RequestHandler, SharedGlobalConfig, ElasticsearchServiceStart, + IClusterClient, } from '../../../../src/core/server'; import { @@ -270,6 +271,9 @@ export class AlertingPlugin { return request => ({ callCluster: elasticsearch.legacy.client.asScoped(request).callAsCurrentUser, savedObjectsClient: savedObjects.getScopedClient(request), + getScopedCallCluster(clusterClient: IClusterClient) { + return clusterClient.asScoped(request).callAsCurrentUser; + }, }); } diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index 0f600c7df7bf7..8b14199b7276a 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -11,9 +11,10 @@ import { ConcreteTaskInstance, TaskStatus } from '../../../../plugins/task_manag import { TaskRunnerContext } from './task_runner_factory'; import { TaskRunner } from './task_runner'; import { encryptedSavedObjectsMock } from '../../../../plugins/encrypted_saved_objects/server/mocks'; -import { savedObjectsClientMock, loggingServiceMock } from '../../../../../src/core/server/mocks'; +import { loggingServiceMock } from '../../../../../src/core/server/mocks'; import { PluginStartContract as ActionsPluginStart } from '../../../actions/server'; import { actionsMock } from '../../../actions/server/mocks'; +import { alertsMock } from '../mocks'; import { eventLoggerMock } from '../../../event_log/server/event_logger.mock'; import { IEventLogger } from '../../../event_log/server'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; @@ -52,13 +53,9 @@ describe('Task Runner', () => { afterAll(() => fakeTimer.restore()); - const savedObjectsClient = savedObjectsClientMock.create(); const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); - const services = { - log: jest.fn(), - callCluster: jest.fn(), - savedObjectsClient, - }; + const services = alertsMock.createAlertServices(); + const savedObjectsClient = services.savedObjectsClient; const taskRunnerFactoryInitializerParams: jest.Mocked & { actionsPlugin: jest.Mocked; diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index 1d220f97f127a..563664d3544ac 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -8,8 +8,9 @@ import sinon from 'sinon'; import { ConcreteTaskInstance, TaskStatus } from '../../../../plugins/task_manager/server'; import { TaskRunnerContext, TaskRunnerFactory } from './task_runner_factory'; import { encryptedSavedObjectsMock } from '../../../../plugins/encrypted_saved_objects/server/mocks'; -import { savedObjectsClientMock, loggingServiceMock } from '../../../../../src/core/server/mocks'; +import { loggingServiceMock } from '../../../../../src/core/server/mocks'; import { actionsMock } from '../../../actions/server/mocks'; +import { alertsMock } from '../mocks'; import { eventLoggerMock } from '../../../event_log/server/event_logger.mock'; const alertType = { @@ -48,13 +49,8 @@ describe('Task Runner Factory', () => { afterAll(() => fakeTimer.restore()); - const savedObjectsClient = savedObjectsClientMock.create(); const encryptedSavedObjectsPlugin = encryptedSavedObjectsMock.createStart(); - const services = { - log: jest.fn(), - callCluster: jest.fn(), - savedObjectsClient, - }; + const services = alertsMock.createAlertServices(); const taskRunnerFactoryInitializerParams: jest.Mocked = { getServices: jest.fn().mockReturnValue(services), diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index bc98cae65b4e6..b733b23dd71e6 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -7,14 +7,16 @@ import { AlertInstance } from './alert_instance'; import { AlertTypeRegistry as OrigAlertTypeRegistry } from './alert_type_registry'; import { PluginSetupContract, PluginStartContract } from './plugin'; +import { Alert, AlertActionParams, ActionGroup } from '../common'; +import { AlertsClient } from './alerts_client'; +export * from '../common'; import { + IClusterClient, + IScopedClusterClient, + KibanaRequest, SavedObjectAttributes, SavedObjectsClientContract, - KibanaRequest, } from '../../../../src/core/server'; -import { Alert, AlertActionParams, ActionGroup } from '../common'; -import { AlertsClient } from './alerts_client'; -export * from '../common'; // This will have to remain `any` until we can extend Alert Executors with generics // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -36,10 +38,9 @@ declare module 'src/core/server' { } export interface Services { - // This will have to remain `any` until we can extend Alert Services with generics - // eslint-disable-next-line @typescript-eslint/no-explicit-any - callCluster(path: string, opts: any): Promise; + callCluster: IScopedClusterClient['callAsCurrentUser']; savedObjectsClient: SavedObjectsClientContract; + getScopedCallCluster(clusterClient: IClusterClient): IScopedClusterClient['callAsCurrentUser']; } export interface AlertServices extends Services { diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js index f4bda2af653aa..0e4586f707f42 100644 --- a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { API_BASE_PATH } from '../../../common/constants'; import { FollowerIndexForm } from '../../app/components/follower_index_form/follower_index_form'; import './mocks'; import { FOLLOWER_INDEX_EDIT } from './helpers/constants'; @@ -12,7 +13,7 @@ import { setupEnvironment, pageHelpers, nextTick } from './helpers'; const { setup } = pageHelpers.followerIndexEdit; const { setup: setupFollowerIndexAdd } = pageHelpers.followerIndexAdd; -describe('Edit Auto-follow pattern', () => { +describe('Edit follower index', () => { let server; let httpRequestsMockHelpers; @@ -88,6 +89,53 @@ describe('Edit Auto-follow pattern', () => { }); }); + describe('API', () => { + const remoteClusters = [{ name: 'new-york', seeds: ['localhost:123'], isConnected: true }]; + let testBed; + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadRemoteClustersResponse(remoteClusters); + httpRequestsMockHelpers.setGetFollowerIndexResponse(FOLLOWER_INDEX_EDIT); + + testBed = await setup(); + await testBed.waitFor('followerIndexForm'); + }); + + test('is consumed correctly', async () => { + const { actions, form, component, find, waitFor } = testBed; + + form.setInputValue('maxRetryDelayInput', '10s'); + + actions.clickSaveForm(); + component.update(); // The modal to confirm the update opens + await waitFor('confirmModalTitleText'); + find('confirmModalConfirmButton').simulate('click'); + + await nextTick(); // Make sure the Request went through + + const latestRequest = server.requests[server.requests.length - 1]; + const requestBody = JSON.parse(JSON.parse(latestRequest.requestBody).body); + + // Verify the API endpoint called: method, path and payload + expect(latestRequest.method).toBe('PUT'); + expect(latestRequest.url).toBe( + `${API_BASE_PATH}/follower_indices/${FOLLOWER_INDEX_EDIT.name}` + ); + expect(requestBody).toEqual({ + maxReadRequestOperationCount: 7845, + maxOutstandingReadRequests: 16, + maxReadRequestSize: '64mb', + maxWriteRequestOperationCount: 2456, + maxWriteRequestSize: '1048b', + maxOutstandingWriteRequests: 69, + maxWriteBufferCount: 123456, + maxWriteBufferSize: '256mb', + maxRetryDelay: '10s', + readPollTimeout: '2m', + }); + }); + }); + describe('when the remote cluster is disconnected', () => { let find; let exists; diff --git a/x-pack/plugins/endpoint/common/generate_data.ts b/x-pack/plugins/endpoint/common/generate_data.ts index 1978d780f54f5..4f5a6eaeb0a5e 100644 --- a/x-pack/plugins/endpoint/common/generate_data.ts +++ b/x-pack/plugins/endpoint/common/generate_data.ts @@ -6,7 +6,16 @@ import uuid from 'uuid'; import seedrandom from 'seedrandom'; -import { AlertEvent, EndpointEvent, HostMetadata, OSFields, HostFields, PolicyData } from './types'; +import { + AlertEvent, + EndpointEvent, + HostFields, + HostMetadata, + OSFields, + PolicyData, + HostPolicyResponse, + HostPolicyResponseActionStatus, +} from './types'; import { factory as policyFactory } from './models/policy_config'; export type Event = AlertEvent | EndpointEvent; @@ -486,6 +495,112 @@ export class EndpointDocGenerator { }; } + /** + * Generates a Host Policy response message + */ + generatePolicyResponse(): HostPolicyResponse { + return { + '@timestamp': new Date().toISOString(), + elastic: { + agent: { + id: 'c2a9093e-e289-4c0a-aa44-8c32a414fa7a', + }, + }, + ecs: { + version: '1.0.0', + }, + event: { + created: '2015-01-01T12:10:30Z', + kind: 'policy_response', + }, + agent: { + version: '6.0.0-rc2', + id: '8a4f500d', + }, + endpoint: { + artifacts: { + 'global-manifest': { + version: '1.2.3', + sha256: 'abcdef', + }, + 'endpointpe-v4-windows': { + version: '1.2.3', + sha256: 'abcdef', + }, + 'user-whitelist-windows': { + version: '1.2.3', + sha256: 'abcdef', + }, + 'global-whitelist-windows': { + version: '1.2.3', + sha256: 'abcdef', + }, + }, + policy: { + applied: { + version: '1.0.0', + id: '17d4b81d-9940-4b64-9de5-3e03ef1fb5cf', + status: HostPolicyResponseActionStatus.success, + response: { + configurations: { + malware: { + status: HostPolicyResponseActionStatus.success, + concerned_actions: ['download_model', 'workflow', 'a_custom_future_action'], + }, + events: { + status: HostPolicyResponseActionStatus.success, + concerned_actions: ['ingest_events_config', 'workflow'], + }, + logging: { + status: HostPolicyResponseActionStatus.success, + concerned_actions: ['configure_elasticsearch_connection'], + }, + streaming: { + status: HostPolicyResponseActionStatus.success, + concerned_actions: [ + 'detect_file_open_events', + 'download_global_artifacts', + 'a_custom_future_action', + ], + }, + }, + actions: { + download_model: { + status: HostPolicyResponseActionStatus.success, + message: 'model downloaded', + }, + ingest_events_config: { + status: HostPolicyResponseActionStatus.success, + message: 'no action taken', + }, + workflow: { + status: HostPolicyResponseActionStatus.success, + message: 'the flow worked well', + }, + a_custom_future_action: { + status: HostPolicyResponseActionStatus.success, + message: 'future message', + }, + configure_elasticsearch_connection: { + status: HostPolicyResponseActionStatus.success, + message: 'some message', + }, + detect_file_open_events: { + status: HostPolicyResponseActionStatus.success, + message: 'some message', + }, + download_global_artifacts: { + status: HostPolicyResponseActionStatus.success, + message: 'some message', + }, + }, + }, + }, + }, + }, + }; + } + private randomN(n: number): number { return Math.floor(this.random() * n); } diff --git a/x-pack/plugins/endpoint/common/types.ts b/x-pack/plugins/endpoint/common/types.ts index 49f8ebbd580d8..4da4f9bc797ca 100644 --- a/x-pack/plugins/endpoint/common/types.ts +++ b/x-pack/plugins/endpoint/common/types.ts @@ -573,3 +573,103 @@ export type NewPolicyData = NewDatasource & { } ]; }; + +/** + * the possible status for actions, configurations and overall Policy Response + */ +export enum HostPolicyResponseActionStatus { + success = 'success', + failure = 'failure', + warning = 'warning', +} + +/** + * The details of a given action + */ +interface HostPolicyResponseActionDetails { + status: HostPolicyResponseActionStatus; + message: string; +} + +/** + * A known list of possible Endpoint actions + */ +interface HostPolicyResponseActions { + download_model: HostPolicyResponseActionDetails; + ingest_events_config: HostPolicyResponseActionDetails; + workflow: HostPolicyResponseActionDetails; + configure_elasticsearch_connection: HostPolicyResponseActionDetails; + configure_kernel: HostPolicyResponseActionDetails; + configure_logging: HostPolicyResponseActionDetails; + configure_malware: HostPolicyResponseActionDetails; + connect_kernel: HostPolicyResponseActionDetails; + detect_file_open_events: HostPolicyResponseActionDetails; + detect_file_write_events: HostPolicyResponseActionDetails; + detect_image_load_events: HostPolicyResponseActionDetails; + detect_process_events: HostPolicyResponseActionDetails; + download_global_artifacts: HostPolicyResponseActionDetails; + load_config: HostPolicyResponseActionDetails; + load_malware_model: HostPolicyResponseActionDetails; + read_elasticsearch_config: HostPolicyResponseActionDetails; + read_events_config: HostPolicyResponseActionDetails; + read_kernel_config: HostPolicyResponseActionDetails; + read_logging_config: HostPolicyResponseActionDetails; + read_malware_config: HostPolicyResponseActionDetails; + // The list of possible Actions will change rapidly, so the below entry will allow + // them without us defining them here statically + [key: string]: HostPolicyResponseActionDetails; +} + +interface HostPolicyResponseConfigurationStatus { + status: HostPolicyResponseActionStatus; + concerned_actions: Array; +} + +/** + * Information about the applying of a policy to a given host + */ +export interface HostPolicyResponse { + '@timestamp': string; + elastic: { + agent: { + id: string; + }; + }; + ecs: { + version: string; + }; + event: { + created: string; + kind: string; + }; + agent: { + version: string; + id: string; + }; + endpoint: { + artifacts: {}; + policy: { + applied: { + version: string; + id: string; + status: HostPolicyResponseActionStatus; + response: { + configurations: { + malware: HostPolicyResponseConfigurationStatus; + events: HostPolicyResponseConfigurationStatus; + logging: HostPolicyResponseConfigurationStatus; + streaming: HostPolicyResponseConfigurationStatus; + }; + actions: Partial; + }; + }; + }; + }; +} + +/** + * REST API response for retrieving a host's Policy Response status + */ +export interface GetHostPolicyResponse { + policy_response: HostPolicyResponse; +} diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/action.ts index 56a49df3bdab4..16a1f96c926b8 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/action.ts @@ -5,7 +5,7 @@ */ import { ServerApiError } from '../../types'; -import { HostResultList, HostInfo } from '../../../../../common/types'; +import { HostResultList, HostInfo, GetHostPolicyResponse } from '../../../../../common/types'; interface ServerReturnedHostList { type: 'serverReturnedHostList'; @@ -27,8 +27,14 @@ interface ServerFailedToReturnHostDetails { payload: ServerApiError; } +interface ServerReturnedHostPolicyResponse { + type: 'serverReturnedHostPolicyResponse'; + payload: GetHostPolicyResponse; +} + export type HostAction = | ServerReturnedHostList | ServerFailedToReturnHostList | ServerReturnedHostDetails - | ServerFailedToReturnHostDetails; + | ServerFailedToReturnHostDetails + | ServerReturnedHostPolicyResponse; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/index.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/index.test.ts index 515c54eab3280..863ffc50d0155 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/index.test.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/index.test.ts @@ -57,7 +57,7 @@ describe('HostList store concerns', () => { }); const currentState = store.getState(); - expect(currentState.hosts).toEqual(payload.hosts.map(hostInfo => hostInfo.metadata)); + expect(currentState.hosts).toEqual(payload.hosts); expect(currentState.pageSize).toEqual(payload.request_page_size); expect(currentState.pageIndex).toEqual(payload.request_page_index); expect(currentState.total).toEqual(payload.total); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.test.ts index 1af83a975d1d8..2064c76f7dfb5 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.test.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.test.ts @@ -62,6 +62,6 @@ describe('host list middleware', () => { paging_properties: [{ page_index: '0' }, { page_size: '10' }], }), }); - expect(listData(getState())).toEqual(apiResponse.hosts.map(hostInfo => hostInfo.metadata)); + expect(listData(getState())).toEqual(apiResponse.hosts); }); }); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts index bb1cfc4dd10af..d1b9a2cde4b31 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/middleware.ts @@ -8,6 +8,7 @@ import { HostResultList } from '../../../../../common/types'; import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors'; import { HostState } from '../../types'; import { ImmutableMiddlewareFactory } from '../../types'; +import { HostPolicyResponse } from '../../../../../common/types'; export const hostMiddlewareFactory: ImmutableMiddlewareFactory = coreStart => { return ({ getState, dispatch }) => next => async action => { @@ -69,6 +70,21 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory = core type: 'serverReturnedHostDetails', payload: response, }); + // FIXME: once we have the API implementation in place, we should call it parallel with the above api call and then dispatch this with the results of the second call + dispatch({ + type: 'serverReturnedHostPolicyResponse', + payload: { + policy_response: ({ + endpoint: { + policy: { + applied: { + status: 'success', + }, + }, + }, + } as unknown) as HostPolicyResponse, // Temporary until we get API + }, + }); } catch (error) { dispatch({ type: 'serverFailedToReturnHostDetails', diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/reducer.ts index adf18fa50c24f..93e995194353b 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/reducer.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/reducer.ts @@ -20,6 +20,7 @@ const initialState = (): HostState => { details: undefined, detailsLoading: false, detailsError: undefined, + policyResponse: undefined, location: undefined, }; }; @@ -37,7 +38,7 @@ export const hostListReducer: ImmutableReducer = ( } = action.payload; return { ...state, - hosts: hosts.map(hostInfo => hostInfo.metadata), + hosts, total, pageSize, pageIndex, @@ -63,6 +64,11 @@ export const hostListReducer: ImmutableReducer = ( detailsError: action.payload, detailsLoading: false, }; + } else if (action.type === 'serverReturnedHostPolicyResponse') { + return { + ...state, + policyResponse: action.payload.policy_response, + }; } else if (action.type === 'userChangedUrl') { const newState: Immutable = { ...state, diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts index b0f949ebbe757..b0711baf9cdff 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/hosts/selectors.ts @@ -86,3 +86,13 @@ export const showView: (state: HostState) => 'policy_response' | 'details' = cre return searchParams.show === 'policy_response' ? 'policy_response' : 'details'; } ); + +/** + * Returns the Policy Response overall status + */ +export const policyResponseStatus: (state: Immutable) => string = createSelector( + state => state.policyResponse, + policyResponse => { + return (policyResponse && policyResponse?.endpoint?.policy?.applied?.status) || ''; + } +); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index e5e600f6c6288..82b812b79670f 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -22,6 +22,8 @@ import { MalwareFields, UIPolicyConfig, PolicyData, + HostPolicyResponse, + HostInfo, } from '../../../common/types'; import { EndpointPluginStartDependencies } from '../../plugin'; import { AppAction } from './store/action'; @@ -90,7 +92,7 @@ export type SubstateMiddlewareFactory = ( export interface HostState { /** list of host **/ - hosts: HostMetadata[]; + hosts: HostInfo[]; /** number of items per page */ pageSize: number; /** which page to show */ @@ -107,6 +109,8 @@ export interface HostState { detailsLoading: boolean; /** api error from retrieving host details */ detailsError?: ServerApiError; + /** Holds the Policy Response for the Host currently being displayed in the details */ + policyResponse?: HostPolicyResponse; /** current location info */ location?: Immutable; } diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx index e4da39d50304a..7d948f54bd0bc 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/details/host_details.tsx @@ -16,12 +16,12 @@ import { import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { HostMetadata } from '../../../../../../common/types'; +import { HostMetadata, HostPolicyResponseActionStatus } from '../../../../../../common/types'; import { FormattedDateAndTime } from '../../formatted_date_time'; import { LinkToApp } from '../../components/link_to_app'; import { useHostSelector, useHostLogsUrl } from '../hooks'; import { urlFromQueryParams } from '../url_from_query_params'; -import { uiQueryParams } from '../../../store/hosts/selectors'; +import { policyResponseStatus, uiQueryParams } from '../../../store/hosts/selectors'; import { useNavigateByRouterEventHandler } from '../../hooks/use_navigate_by_router_event_handler'; const HostIds = styled(EuiListGroupItem)` @@ -31,9 +31,20 @@ const HostIds = styled(EuiListGroupItem)` } `; +const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze< + { [key in keyof typeof HostPolicyResponseActionStatus]: string } +>({ + success: 'success', + warning: 'warning', + failure: 'danger', +}); + export const HostDetails = memo(({ details }: { details: HostMetadata }) => { const { appId, appPath, url } = useHostLogsUrl(details.host.id); const queryParams = useHostSelector(uiQueryParams); + const policyStatus = useHostSelector( + policyResponseStatus + ) as keyof typeof POLICY_STATUS_TO_HEALTH_COLOR; const detailsResultsUpper = useMemo(() => { return [ { @@ -79,7 +90,10 @@ export const HostDetails = memo(({ details }: { details: HostMetadata }) => { defaultMessage: 'Policy Status', }), description: ( - + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} { onClick={policyStatusClickHandler} > @@ -126,6 +141,7 @@ export const HostDetails = memo(({ details }: { details: HostMetadata }) => { details.host.ip, policyResponseUri.search, policyStatusClickHandler, + policyStatus, ]); return ( diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx index 11dbed716c527..5a8765110c909 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.test.tsx @@ -14,9 +14,11 @@ import { mockHostResultList, } from '../../store/hosts/mock_host_result_list'; import { AppContextTestRender, createAppRootMockRenderer } from '../../mocks'; -import { HostInfo } from '../../../../../common/types'; +import { HostInfo, HostStatus, HostPolicyResponseActionStatus } from '../../../../../common/types'; +import { EndpointDocGenerator } from '../../../../../common/generate_data'; describe('when on the hosts page', () => { + const docGenerator = new EndpointDocGenerator(); let render: () => ReturnType; let history: AppContextTestRender['history']; let store: AppContextTestRender['store']; @@ -46,21 +48,50 @@ describe('when on the hosts page', () => { describe('when list data loads', () => { beforeEach(() => { reactTestingLibrary.act(() => { + const hostListData = mockHostResultList({ total: 3 }); + [HostStatus.ERROR, HostStatus.ONLINE, HostStatus.OFFLINE].forEach((status, index) => { + hostListData.hosts[index] = { + metadata: hostListData.hosts[index].metadata, + host_status: status, + }; + }); const action: AppAction = { type: 'serverReturnedHostList', - payload: mockHostResultList(), + payload: hostListData, }; store.dispatch(action); }); }); - it('should render the host summary row in the table', async () => { + it('should display rows in the table', async () => { const renderResult = render(); const rows = await renderResult.findAllByRole('row'); - expect(rows).toHaveLength(2); + expect(rows).toHaveLength(4); + }); + it('should show total', async () => { + const renderResult = render(); + const total = await renderResult.findByTestId('hostListTableTotal'); + expect(total.textContent).toEqual('3 Hosts'); + }); + it('should display correct status', async () => { + const renderResult = render(); + const hostStatuses = await renderResult.findAllByTestId('rowHostStatus'); + + expect(hostStatuses[0].textContent).toEqual('Error'); + expect(hostStatuses[0].querySelector('[data-euiicon-type][color="danger"]')).not.toBeNull(); + + expect(hostStatuses[1].textContent).toEqual('Online'); + expect( + hostStatuses[1].querySelector('[data-euiicon-type][color="success"]') + ).not.toBeNull(); + + expect(hostStatuses[2].textContent).toEqual('Offline'); + expect( + hostStatuses[2].querySelector('[data-euiicon-type][color="subdued"]') + ).not.toBeNull(); }); - describe('when the user clicks the hostname in the table', () => { + describe('when the user clicks the first hostname in the table', () => { let renderResult: reactTestingLibrary.RenderResult; beforeEach(async () => { const hostDetailsApiResponse = mockHostDetailsApiResult(); @@ -74,9 +105,9 @@ describe('when on the hosts page', () => { }); renderResult = render(); - const detailsLink = await renderResult.findByTestId('hostnameCellLink'); - if (detailsLink) { - reactTestingLibrary.fireEvent.click(detailsLink); + const hostNameLinks = await renderResult.findAllByTestId('hostnameCellLink'); + if (hostNameLinks.length) { + reactTestingLibrary.fireEvent.click(hostNameLinks[0]); } }); @@ -91,6 +122,19 @@ describe('when on the hosts page', () => { describe('when there is a selected host in the url', () => { let hostDetails: HostInfo; + const dispatchServerReturnedHostPolicyResponse = ( + overallStatus: HostPolicyResponseActionStatus = HostPolicyResponseActionStatus.success + ) => { + const policyResponse = docGenerator.generatePolicyResponse(); + policyResponse.endpoint.policy.applied.status = overallStatus; + store.dispatch({ + type: 'serverReturnedHostPolicyResponse', + payload: { + policy_response: policyResponse, + }, + }); + }; + beforeEach(() => { const { host_status, @@ -137,7 +181,6 @@ describe('when on the hosts page', () => { const renderResult = render(); const policyStatusLink = await renderResult.findByTestId('policyStatusValue'); expect(policyStatusLink).not.toBeNull(); - expect(policyStatusLink.textContent).toEqual('Successful'); expect(policyStatusLink.getAttribute('href')).toEqual( '?page_index=0&page_size=10&selected_host=1&show=policy_response' ); @@ -154,6 +197,58 @@ describe('when on the hosts page', () => { '?page_index=0&page_size=10&selected_host=1&show=policy_response' ); }); + it('should display Success overall policy status', async () => { + const renderResult = render(); + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(HostPolicyResponseActionStatus.success); + }); + const policyStatusLink = await renderResult.findByTestId('policyStatusValue'); + expect(policyStatusLink.textContent).toEqual('Success'); + + const policyStatusHealth = await renderResult.findByTestId('policyStatusHealth'); + expect( + policyStatusHealth.querySelector('[data-euiicon-type][color="success"]') + ).not.toBeNull(); + }); + it('should display Warning overall policy status', async () => { + const renderResult = render(); + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(HostPolicyResponseActionStatus.warning); + }); + const policyStatusLink = await renderResult.findByTestId('policyStatusValue'); + expect(policyStatusLink.textContent).toEqual('Warning'); + + const policyStatusHealth = await renderResult.findByTestId('policyStatusHealth'); + expect( + policyStatusHealth.querySelector('[data-euiicon-type][color="warning"]') + ).not.toBeNull(); + }); + it('should display Failed overall policy status', async () => { + const renderResult = render(); + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse(HostPolicyResponseActionStatus.failure); + }); + const policyStatusLink = await renderResult.findByTestId('policyStatusValue'); + expect(policyStatusLink.textContent).toEqual('Failed'); + + const policyStatusHealth = await renderResult.findByTestId('policyStatusHealth'); + expect( + policyStatusHealth.querySelector('[data-euiicon-type][color="danger"]') + ).not.toBeNull(); + }); + it('should display Unknown overall policy status', async () => { + const renderResult = render(); + reactTestingLibrary.act(() => { + dispatchServerReturnedHostPolicyResponse('' as HostPolicyResponseActionStatus); + }); + const policyStatusLink = await renderResult.findByTestId('policyStatusValue'); + expect(policyStatusLink.textContent).toEqual('Unknown'); + + const policyStatusHealth = await renderResult.findByTestId('policyStatusHealth'); + expect( + policyStatusHealth.querySelector('[data-euiicon-type][color="subdued"]') + ).not.toBeNull(); + }); it('should include the link to logs', async () => { const renderResult = render(); const linkToLogs = await renderResult.findByTestId('hostDetailsLinkToLogs'); @@ -176,7 +271,7 @@ describe('when on the hosts page', () => { expect(coreStart.application.navigateToApp.mock.calls).toHaveLength(1); }); }); - describe('when showing host Policy Response', () => { + describe('when showing host Policy Response panel', () => { let renderResult: ReturnType; beforeEach(async () => { renderResult = render(); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.tsx index 5c2922162ce0c..026ba2ff15126 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/hosts/index.tsx @@ -16,10 +16,20 @@ import * as selectors from '../../store/hosts/selectors'; import { useHostSelector } from './hooks'; import { CreateStructuredSelector } from '../../types'; import { urlFromQueryParams } from './url_from_query_params'; -import { HostMetadata, Immutable } from '../../../../../common/types'; +import { HostInfo, HostStatus, Immutable } from '../../../../../common/types'; import { PageView } from '../components/page_view'; import { useNavigateByRouterEventHandler } from '../hooks/use_navigate_by_router_event_handler'; +const HOST_STATUS_TO_HEALTH_COLOR = Object.freeze< + { + [key in HostStatus]: string; + } +>({ + [HostStatus.ERROR]: 'danger', + [HostStatus.ONLINE]: 'success', + [HostStatus.OFFLINE]: 'subdued', +}); + const HostLink = memo<{ name: string; href: string; @@ -73,20 +83,40 @@ export const HostList = () => { [history, queryParams] ); - const columns: Array>> = useMemo(() => { + const columns: Array>> = useMemo(() => { return [ { - field: '', + field: 'metadata.host', name: i18n.translate('xpack.endpoint.host.list.hostname', { defaultMessage: 'Hostname', }), - render: ({ host: { hostname, id } }: { host: { hostname: string; id: string } }) => { + render: ({ hostname, id }: HostInfo['metadata']['host']) => { const newQueryParams = urlFromQueryParams({ ...queryParams, selected_host: id }); return ( ); }, }, + { + field: 'host_status', + name: i18n.translate('xpack.endpoint.host.list.hostStatus', { + defaultMessage: 'Host Status', + }), + render: (hostStatus: HostInfo['host_status']) => { + return ( + + + + ); + }, + }, { field: '', name: i18n.translate('xpack.endpoint.host.list.policy', { @@ -117,26 +147,23 @@ export const HostList = () => { }, }, { - field: 'host.os.name', + field: 'metadata.host.os.name', name: i18n.translate('xpack.endpoint.host.list.os', { defaultMessage: 'Operating System', }), }, { - field: 'host.ip', + field: 'metadata.host.ip', name: i18n.translate('xpack.endpoint.host.list.ip', { defaultMessage: 'IP Address', }), truncateText: true, }, { - field: '', - name: i18n.translate('xpack.endpoint.host.list.sensorVersion', { - defaultMessage: 'Sensor Version', + field: 'metadata.agent.version', + name: i18n.translate('xpack.endpoint.host.list.endpointVersion', { + defaultMessage: 'Version', }), - render: () => { - return 'version'; - }, }, { field: '', @@ -158,7 +185,7 @@ export const HostList = () => { headerLeft={i18n.translate('xpack.endpoint.host.hosts', { defaultMessage: 'Hosts' })} > {hasSelectedHost && } - + { + const [popoverOpen, setPopoverOpen] = useState(false); + const [flyoutVisible, setFlyoutVisible] = useState(false); + const manageAlertsLinkProps = useLinkProps( + { + app: 'kibana', + hash: 'management/kibana/triggersActions/alerts', + }, + { + hrefOnly: true, + } + ); + + const closePopover = useCallback(() => { + setPopoverOpen(false); + }, [setPopoverOpen]); + + const openPopover = useCallback(() => { + setPopoverOpen(true); + }, [setPopoverOpen]); + + const menuItems = useMemo(() => { + return [ + setFlyoutVisible(true)}> + + , + + + , + ]; + }, [manageAlertsLinkProps]); + + return ( + <> + + + + } + isOpen={popoverOpen} + closePopover={closePopover} + > + + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/alert_flyout.tsx b/x-pack/plugins/infra/public/components/alerting/logs/alert_flyout.tsx new file mode 100644 index 0000000000000..b18c2e5b8d69c --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/alert_flyout.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext } from 'react'; +import { AlertsContextProvider, AlertAdd } from '../../../../../triggers_actions_ui/public'; +import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { LOG_DOCUMENT_COUNT_ALERT_TYPE_ID } from '../../../../common/alerting/logs/types'; + +interface Props { + visible?: boolean; + setVisible: React.Dispatch>; +} + +export const AlertFlyout = (props: Props) => { + const { triggersActionsUI } = useContext(TriggerActionsContext); + const { services } = useKibana(); + + return ( + <> + {triggersActionsUI && ( + + + + )} + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criteria.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criteria.tsx new file mode 100644 index 0000000000000..a9b45a117c281 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criteria.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { IFieldType } from 'src/plugins/data/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types'; +import { Criterion } from './criterion'; +import { + LogDocumentCountAlertParams, + Criterion as CriterionType, +} from '../../../../../common/alerting/logs/types'; + +interface Props { + fields: IFieldType[]; + criteria?: LogDocumentCountAlertParams['criteria']; + updateCriterion: (idx: number, params: Partial) => void; + removeCriterion: (idx: number) => void; + errors: IErrorObject; +} + +export const Criteria: React.FC = ({ + fields, + criteria, + updateCriterion, + removeCriterion, + errors, +}) => { + if (!criteria) return null; + return ( + + + {criteria.map((criterion, idx) => { + return ( + 1} + errors={errors[idx.toString()] as IErrorObject} + /> + ); + })} + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criterion.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criterion.tsx new file mode 100644 index 0000000000000..e8cafecd94db1 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/criterion.tsx @@ -0,0 +1,269 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState, useMemo, useCallback } from 'react'; +import { + EuiPopoverTitle, + EuiFlexItem, + EuiFlexGroup, + EuiPopover, + EuiSelect, + EuiFieldNumber, + EuiExpression, + EuiFieldText, + EuiButtonIcon, + EuiFormRow, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { IFieldType } from 'src/plugins/data/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types'; +import { + Comparator, + Criterion as CriterionType, + ComparatorToi18nMap, +} from '../../../../../common/alerting/logs/types'; + +const firstCriterionFieldPrefix = i18n.translate( + 'xpack.infra.logs.alertFlyout.firstCriterionFieldPrefix', + { + defaultMessage: 'with', + } +); + +const successiveCriterionFieldPrefix = i18n.translate( + 'xpack.infra.logs.alertFlyout.successiveCriterionFieldPrefix', + { + defaultMessage: 'and', + } +); + +const criterionFieldTitle = i18n.translate('xpack.infra.logs.alertFlyout.criterionFieldTitle', { + defaultMessage: 'Field', +}); + +const criterionComparatorValueTitle = i18n.translate( + 'xpack.infra.logs.alertFlyout.criterionComparatorValueTitle', + { + defaultMessage: 'Comparison : Value', + } +); + +const getCompatibleComparatorsForField = (fieldInfo: IFieldType | undefined) => { + if (fieldInfo?.type === 'number') { + return [ + { value: Comparator.GT, text: ComparatorToi18nMap[Comparator.GT] }, + { value: Comparator.GT_OR_EQ, text: ComparatorToi18nMap[Comparator.GT_OR_EQ] }, + { value: Comparator.LT, text: ComparatorToi18nMap[Comparator.LT] }, + { value: Comparator.LT_OR_EQ, text: ComparatorToi18nMap[Comparator.LT_OR_EQ] }, + { value: Comparator.EQ, text: ComparatorToi18nMap[`${Comparator.EQ}:number`] }, + { value: Comparator.NOT_EQ, text: ComparatorToi18nMap[`${Comparator.NOT_EQ}:number`] }, + ]; + } else if (fieldInfo?.aggregatable) { + return [ + { value: Comparator.EQ, text: ComparatorToi18nMap[Comparator.EQ] }, + { value: Comparator.NOT_EQ, text: ComparatorToi18nMap[Comparator.NOT_EQ] }, + ]; + } else { + return [ + { value: Comparator.MATCH, text: ComparatorToi18nMap[Comparator.MATCH] }, + { value: Comparator.NOT_MATCH, text: ComparatorToi18nMap[Comparator.NOT_MATCH] }, + { value: Comparator.MATCH_PHRASE, text: ComparatorToi18nMap[Comparator.MATCH_PHRASE] }, + { + value: Comparator.NOT_MATCH_PHRASE, + text: ComparatorToi18nMap[Comparator.NOT_MATCH_PHRASE], + }, + ]; + } +}; + +const getFieldInfo = (fields: IFieldType[], fieldName: string): IFieldType | undefined => { + return fields.find(field => { + return field.name === fieldName; + }); +}; + +interface Props { + idx: number; + fields: IFieldType[]; + criterion: CriterionType; + updateCriterion: (idx: number, params: Partial) => void; + removeCriterion: (idx: number) => void; + canDelete: boolean; + errors: IErrorObject; +} + +export const Criterion: React.FC = ({ + idx, + fields, + criterion, + updateCriterion, + removeCriterion, + canDelete, + errors, +}) => { + const [isFieldPopoverOpen, setIsFieldPopoverOpen] = useState(false); + const [isComparatorPopoverOpen, setIsComparatorPopoverOpen] = useState(false); + + const fieldOptions = useMemo(() => { + return fields.map(field => { + return { value: field.name, text: field.name }; + }); + }, [fields]); + + const fieldInfo: IFieldType | undefined = useMemo(() => { + return getFieldInfo(fields, criterion.field); + }, [fields, criterion]); + + const compatibleComparatorOptions = useMemo(() => { + return getCompatibleComparatorsForField(fieldInfo); + }, [fieldInfo]); + + const handleFieldChange = useCallback( + e => { + const fieldName = e.target.value; + const nextFieldInfo = getFieldInfo(fields, fieldName); + // If the field information we're dealing with has changed, reset the comparator and value. + if ( + fieldInfo && + nextFieldInfo && + (fieldInfo.type !== nextFieldInfo.type || + fieldInfo.aggregatable !== nextFieldInfo.aggregatable) + ) { + const compatibleComparators = getCompatibleComparatorsForField(nextFieldInfo); + updateCriterion(idx, { + field: fieldName, + comparator: compatibleComparators[0].value, + value: undefined, + }); + } else { + updateCriterion(idx, { field: fieldName }); + } + }, + [fieldInfo, fields, idx, updateCriterion] + ); + + return ( + + + + + setIsFieldPopoverOpen(true)} + /> + } + isOpen={isFieldPopoverOpen} + closePopover={() => setIsFieldPopoverOpen(false)} + ownFocus + panelPaddingSize="s" + anchorPosition="downLeft" + > +
+ {criterionFieldTitle} + 0} error={errors.field}> + + +
+
+
+ + setIsComparatorPopoverOpen(true)} + /> + } + isOpen={isComparatorPopoverOpen} + closePopover={() => setIsComparatorPopoverOpen(false)} + ownFocus + panelPaddingSize="s" + anchorPosition="downLeft" + > +
+ {criterionComparatorValueTitle} + + + 0} error={errors.comparator}> + + updateCriterion(idx, { comparator: e.target.value as Comparator }) + } + options={compatibleComparatorOptions} + /> + + + + 0} error={errors.value}> + {fieldInfo?.type === 'number' ? ( + { + const number = parseInt(e.target.value, 10); + updateCriterion(idx, { value: number ? number : undefined }); + }} + /> + ) : ( + updateCriterion(idx, { value: e.target.value })} + /> + )} + + + +
+
+
+
+
+ {canDelete && ( + + removeCriterion(idx)} + /> + + )} +
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/document_count.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/document_count.tsx new file mode 100644 index 0000000000000..308165ce08a9b --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/document_count.tsx @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiPopoverTitle, + EuiFlexItem, + EuiFlexGroup, + EuiPopover, + EuiSelect, + EuiFieldNumber, + EuiExpression, + EuiFormRow, +} from '@elastic/eui'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types'; +import { + Comparator, + ComparatorToi18nMap, + LogDocumentCountAlertParams, +} from '../../../../../common/alerting/logs/types'; + +const documentCountPrefix = i18n.translate('xpack.infra.logs.alertFlyout.documentCountPrefix', { + defaultMessage: 'when', +}); + +const getComparatorOptions = (): Array<{ + value: Comparator; + text: string; +}> => { + return [ + { value: Comparator.LT, text: ComparatorToi18nMap[Comparator.LT] }, + { value: Comparator.LT_OR_EQ, text: ComparatorToi18nMap[Comparator.LT_OR_EQ] }, + { value: Comparator.GT, text: ComparatorToi18nMap[Comparator.GT] }, + { value: Comparator.GT_OR_EQ, text: ComparatorToi18nMap[Comparator.GT_OR_EQ] }, + ]; +}; + +interface Props { + comparator?: Comparator; + value?: number; + updateCount: (params: Partial) => void; + errors: IErrorObject; +} + +export const DocumentCount: React.FC = ({ comparator, value, updateCount, errors }) => { + const [isComparatorPopoverOpen, setComparatorPopoverOpenState] = useState(false); + const [isValuePopoverOpen, setIsValuePopoverOpen] = useState(false); + + const documentCountValue = i18n.translate('xpack.infra.logs.alertFlyout.documentCountValue', { + defaultMessage: '{value, plural, one {log entry} other {log entries}}', + values: { value }, + }); + + return ( + + + setComparatorPopoverOpenState(true)} + /> + } + isOpen={isComparatorPopoverOpen} + closePopover={() => setComparatorPopoverOpenState(false)} + ownFocus + panelPaddingSize="s" + anchorPosition="downLeft" + > +
+ {documentCountPrefix} + updateCount({ comparator: e.target.value as Comparator })} + options={getComparatorOptions()} + /> +
+
+
+ + + setIsValuePopoverOpen(true)} + color={errors.value.length === 0 ? 'secondary' : 'danger'} + /> + } + isOpen={isValuePopoverOpen} + closePopover={() => setIsValuePopoverOpen(false)} + ownFocus + panelPaddingSize="s" + anchorPosition="downLeft" + > +
+ {documentCountValue} + 0} error={errors.value}> + { + const number = parseInt(e.target.value, 10); + updateCount({ value: number ? number : undefined }); + }} + /> + +
+
+
+
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx new file mode 100644 index 0000000000000..3aed0db53bf2c --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useCallback, useMemo, useEffect, useState } from 'react'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + ForLastExpression, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../../triggers_actions_ui/public/common'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types'; +import { useSource } from '../../../../containers/source'; +import { + LogDocumentCountAlertParams, + Comparator, + TimeUnit, +} from '../../../../../common/alerting/logs/types'; +import { DocumentCount } from './document_count'; +import { Criteria } from './criteria'; + +export interface ExpressionCriteria { + field?: string; + comparator?: Comparator; + value?: string | number; +} + +interface Props { + errors: IErrorObject; + alertParams: Partial; + setAlertParams(key: string, value: any): void; + setAlertProperty(key: string, value: any): void; +} + +const DEFAULT_CRITERIA = { field: 'log.level', comparator: Comparator.EQ, value: 'error' }; + +const DEFAULT_EXPRESSION = { + count: { + value: 75, + comparator: Comparator.GT, + }, + criteria: [DEFAULT_CRITERIA], + timeSize: 5, + timeUnit: 'm', +}; + +export const ExpressionEditor: React.FC = props => { + const { setAlertParams, alertParams, errors } = props; + const { createDerivedIndexPattern } = useSource({ sourceId: 'default' }); + const [timeSize, setTimeSize] = useState(1); + const [timeUnit, setTimeUnit] = useState('m'); + const [hasSetDefaults, setHasSetDefaults] = useState(false); + const derivedIndexPattern = useMemo(() => createDerivedIndexPattern('logs'), [ + createDerivedIndexPattern, + ]); + + const supportedFields = useMemo(() => { + if (derivedIndexPattern?.fields) { + return derivedIndexPattern.fields.filter(field => { + return (field.type === 'string' || field.type === 'number') && field.searchable; + }); + } else { + return []; + } + }, [derivedIndexPattern]); + + // Set the default expression (disables exhaustive-deps as we only want to run this once on mount) + useEffect(() => { + for (const [key, value] of Object.entries(DEFAULT_EXPRESSION)) { + setAlertParams(key, value); + setHasSetDefaults(true); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const updateCount = useCallback( + countParams => { + const nextCountParams = { ...alertParams.count, ...countParams }; + setAlertParams('count', nextCountParams); + }, + [alertParams.count, setAlertParams] + ); + + const updateCriterion = useCallback( + (idx, criterionParams) => { + const nextCriteria = alertParams.criteria?.map((criterion, index) => { + return idx === index ? { ...criterion, ...criterionParams } : criterion; + }); + setAlertParams('criteria', nextCriteria ? nextCriteria : []); + }, + [alertParams, setAlertParams] + ); + + const updateTimeSize = useCallback( + (ts: number | undefined) => { + setTimeSize(ts || undefined); + setAlertParams('timeSize', ts); + }, + [setTimeSize, setAlertParams] + ); + + const updateTimeUnit = useCallback( + (tu: string) => { + setTimeUnit(tu as TimeUnit); + setAlertParams('timeUnit', tu); + }, + [setAlertParams] + ); + + const addCriterion = useCallback(() => { + const nextCriteria = alertParams?.criteria + ? [...alertParams.criteria, DEFAULT_CRITERIA] + : [DEFAULT_CRITERIA]; + setAlertParams('criteria', nextCriteria); + }, [alertParams, setAlertParams]); + + const removeCriterion = useCallback( + idx => { + const nextCriteria = alertParams?.criteria?.filter((criterion, index) => { + return index !== idx; + }); + setAlertParams('criteria', nextCriteria); + }, + [alertParams, setAlertParams] + ); + + // Wait until field info has loaded + if (supportedFields.length === 0) return null; + // Wait until the alert param defaults have been set + if (!hasSetDefaults) return null; + + return ( + <> + + + + + + +
+ + + +
+ + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/index.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/index.tsx new file mode 100644 index 0000000000000..8b0fd5eb721b3 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/index.tsx @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './editor'; diff --git a/x-pack/plugins/infra/public/components/alerting/logs/log_threshold_alert_type.ts b/x-pack/plugins/infra/public/components/alerting/logs/log_threshold_alert_type.ts new file mode 100644 index 0000000000000..18126ec583696 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/log_threshold_alert_type.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AlertTypeModel } from '../../../../../triggers_actions_ui/public/types'; +import { LOG_DOCUMENT_COUNT_ALERT_TYPE_ID } from '../../../../common/alerting/logs/types'; +import { ExpressionEditor } from './expression_editor'; +import { validateExpression } from './validation'; + +export function getAlertType(): AlertTypeModel { + return { + id: LOG_DOCUMENT_COUNT_ALERT_TYPE_ID, + name: i18n.translate('xpack.infra.logs.alertFlyout.alertName', { + defaultMessage: 'Log threshold', + }), + iconClass: 'bell', + alertParamsExpression: ExpressionEditor, + validate: validateExpression, + defaultActionMessage: i18n.translate( + 'xpack.infra.logs.alerting.threshold.defaultActionMessage', + { + defaultMessage: `\\{\\{context.matchingDocuments\\}\\} log entries have matched the following conditions: \\{\\{context.conditions\\}\\}`, + } + ), + }; +} diff --git a/x-pack/plugins/infra/public/components/alerting/logs/validation.ts b/x-pack/plugins/infra/public/components/alerting/logs/validation.ts new file mode 100644 index 0000000000000..c8c513f57a9d7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/logs/validation.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ValidationResult } from '../../../../../triggers_actions_ui/public/types'; +import { LogDocumentCountAlertParams } from '../../../../common/alerting/logs/types'; + +export function validateExpression({ + count, + criteria, + timeSize, + timeUnit, +}: Partial): ValidationResult { + const validationResult = { errors: {} }; + + // NOTE: In the case of components provided by the Alerting framework the error property names + // must match what they expect. + const errors: { + count: { + value: string[]; + }; + criteria: { + [id: string]: { + field: string[]; + comparator: string[]; + value: string[]; + }; + }; + timeWindowSize: string[]; + timeSizeUnit: string[]; + } = { + count: { + value: [], + }, + criteria: {}, + timeSizeUnit: [], + timeWindowSize: [], + }; + + validationResult.errors = errors; + + // Document count validation + if (typeof count?.value !== 'number') { + errors.count.value.push( + i18n.translate('xpack.infra.logs.alertFlyout.error.documentCountRequired', { + defaultMessage: 'Document count is Required.', + }) + ); + } + + // Time validation + if (!timeSize) { + errors.timeWindowSize.push( + i18n.translate('xpack.infra.logs.alertFlyout.error.timeSizeRequired', { + defaultMessage: 'Time size is Required.', + }) + ); + } + + if (criteria && criteria.length > 0) { + // Criteria validation + criteria.forEach((criterion, idx: number) => { + const id = idx.toString(); + + errors.criteria[id] = { + field: [], + comparator: [], + value: [], + }; + + if (!criterion.field) { + errors.criteria[id].field.push( + i18n.translate('xpack.infra.logs.alertFlyout.error.criterionFieldRequired', { + defaultMessage: 'Field is required.', + }) + ); + } + + if (!criterion.comparator) { + errors.criteria[id].comparator.push( + i18n.translate('xpack.infra.logs.alertFlyout.error.criterionComparatorRequired', { + defaultMessage: 'Comparator is required.', + }) + ); + } + + if (!criterion.value) { + errors.criteria[id].value.push( + i18n.translate('xpack.infra.logs.alertFlyout.error.criterionValueRequired', { + defaultMessage: 'Value is required.', + }) + ); + } + }); + } + + return validationResult; +} diff --git a/x-pack/plugins/infra/public/hooks/use_link_props.tsx b/x-pack/plugins/infra/public/hooks/use_link_props.tsx index 8c522bb7fa764..dec8eaae56f41 100644 --- a/x-pack/plugins/infra/public/hooks/use_link_props.tsx +++ b/x-pack/plugins/infra/public/hooks/use_link_props.tsx @@ -26,12 +26,20 @@ interface LinkProps { onClick?: (e: React.MouseEvent | React.MouseEvent) => void; } -export const useLinkProps = ({ app, pathname, hash, search }: LinkDescriptor): LinkProps => { +interface Options { + hrefOnly?: boolean; +} + +export const useLinkProps = ( + { app, pathname, hash, search }: LinkDescriptor, + options: Options = {} +): LinkProps => { validateParams({ app, pathname, hash, search }); const { prompt } = useNavigationWarningPrompt(); const prefixer = usePrefixPathWithBasepath(); const navigateToApp = useKibana().services.application?.navigateToApp; + const { hrefOnly } = options; const encodedSearch = useMemo(() => { return search ? encodeSearch(search) : undefined; @@ -86,7 +94,10 @@ export const useLinkProps = ({ app, pathname, hash, search }: LinkDescriptor): L return { href, - onClick, + // Sometimes it may not be desirable to have onClick call "navigateToApp". + // E.g. the management section of Kibana cannot be successfully deeplinked to via + // "navigateToApp". In those cases we can choose to defer to legacy behaviour. + onClick: hrefOnly ? undefined : onClick, }; }; diff --git a/x-pack/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/page_content.tsx index ed6f06deeef64..dc210406275d8 100644 --- a/x-pack/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/page_content.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { Route, Switch } from 'react-router-dom'; @@ -21,6 +22,7 @@ import { LogEntryCategoriesPage } from './log_entry_categories'; import { LogEntryRatePage } from './log_entry_rate'; import { LogsSettingsPage } from './settings'; import { StreamPage } from './stream'; +import { AlertDropdown } from '../../components/alerting/logs/alert_dropdown'; export const LogsPageContent: React.FunctionComponent = () => { const uiCapabilities = useKibana().services.application?.capabilities; @@ -65,13 +67,20 @@ export const LogsPageContent: React.FunctionComponent = () => { readOnlyBadge={!uiCapabilities?.logs?.save} /> - + + + + + + + + diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 3b6647b9bfbbe..40366b2a54f24 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -21,7 +21,8 @@ import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/p import { DataEnhancedSetup, DataEnhancedStart } from '../../data_enhanced/public'; import { TriggersAndActionsUIPublicPluginSetup } from '../../../plugins/triggers_actions_ui/public'; -import { getAlertType } from './components/alerting/metrics/metric_threshold_alert_type'; +import { getAlertType as getMetricsAlertType } from './components/alerting/metrics/metric_threshold_alert_type'; +import { getAlertType as getLogsAlertType } from './components/alerting/logs/log_threshold_alert_type'; export type ClientSetup = void; export type ClientStart = void; @@ -52,7 +53,8 @@ export class Plugin setup(core: CoreSetup, pluginsSetup: ClientPluginsSetup) { registerFeatures(pluginsSetup.home); - pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getAlertType()); + pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getMetricsAlertType()); + pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getLogsAlertType()); core.application.register({ id: 'logs', diff --git a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts index 1fe1431392a38..f880eca933241 100644 --- a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts +++ b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts @@ -93,7 +93,10 @@ export const createSourcesResolvers = ( } => ({ Query: { async source(root, args, { req }) { - const requestedSourceConfiguration = await libs.sources.getSourceConfiguration(req, args.id); + const requestedSourceConfiguration = await libs.sources.getSourceConfiguration( + req.core.savedObjects.client, + args.id + ); return requestedSourceConfiguration; }, diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts new file mode 100644 index 0000000000000..cdec04ab81a8e --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { AlertExecutorOptions, AlertServices } from '../../../../../alerting/server'; +import { + AlertStates, + Comparator, + LogDocumentCountAlertParams, + Criterion, +} from '../../../../common/alerting/logs/types'; +import { InfraBackendLibs } from '../../infra_types'; +import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; +import { InfraSource } from '../../../../common/http_api/source_api'; + +const checkValueAgainstComparatorMap: { + [key: string]: (a: number, b: number) => boolean; +} = { + [Comparator.GT]: (a: number, b: number) => a > b, + [Comparator.GT_OR_EQ]: (a: number, b: number) => a >= b, + [Comparator.LT]: (a: number, b: number) => a < b, + [Comparator.LT_OR_EQ]: (a: number, b: number) => a <= b, +}; + +export const createLogThresholdExecutor = (alertUUID: string, libs: InfraBackendLibs) => + async function({ services, params }: AlertExecutorOptions) { + const { count, criteria } = params as LogDocumentCountAlertParams; + const { alertInstanceFactory, savedObjectsClient, callCluster } = services; + const { sources } = libs; + + const sourceConfiguration = await sources.getSourceConfiguration(savedObjectsClient, 'default'); + const indexPattern = sourceConfiguration.configuration.logAlias; + + const alertInstance = alertInstanceFactory(alertUUID); + + try { + const query = getESQuery( + params as LogDocumentCountAlertParams, + sourceConfiguration.configuration + ); + const result = await getResults(query, indexPattern, callCluster); + + if (checkValueAgainstComparatorMap[count.comparator](result.count, count.value)) { + alertInstance.scheduleActions(FIRED_ACTIONS.id, { + matchingDocuments: result.count, + conditions: createConditionsMessage(criteria), + }); + + alertInstance.replaceState({ + alertState: AlertStates.ALERT, + }); + } else { + alertInstance.replaceState({ + alertState: AlertStates.OK, + }); + } + } catch (e) { + alertInstance.replaceState({ + alertState: AlertStates.ERROR, + }); + + throw new Error(e); + } + }; + +const getESQuery = ( + params: LogDocumentCountAlertParams, + sourceConfiguration: InfraSource['configuration'] +): object => { + const { timeSize, timeUnit, criteria } = params; + const interval = `${timeSize}${timeUnit}`; + const intervalAsSeconds = getIntervalInSeconds(interval); + const to = Date.now(); + const from = to - intervalAsSeconds * 1000; + + const rangeFilters = [ + { + range: { + [sourceConfiguration.fields.timestamp]: { + gte: from, + lte: to, + format: 'epoch_millis', + }, + }, + }, + ]; + + const positiveComparators = getPositiveComparators(); + const negativeComparators = getNegativeComparators(); + const positiveCriteria = criteria.filter(criterion => + positiveComparators.includes(criterion.comparator) + ); + const negativeCriteria = criteria.filter(criterion => + negativeComparators.includes(criterion.comparator) + ); + // Positive assertions (things that "must" match) + const mustFilters = buildFiltersForCriteria(positiveCriteria); + // Negative assertions (things that "must not" match) + const mustNotFilters = buildFiltersForCriteria(negativeCriteria); + + const query = { + query: { + bool: { + filter: [...rangeFilters], + ...(mustFilters.length > 0 && { must: mustFilters }), + ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), + }, + }, + }; + + return query; +}; + +type SupportedESQueryTypes = 'term' | 'match' | 'match_phrase' | 'range'; +type Filter = { + [key in SupportedESQueryTypes]?: object; +}; + +const buildFiltersForCriteria = (criteria: LogDocumentCountAlertParams['criteria']) => { + let filters: Filter[] = []; + + criteria.forEach(criterion => { + const criterionQuery = buildCriterionQuery(criterion); + if (criterionQuery) { + filters = [...filters, criterionQuery]; + } + }); + return filters; +}; + +const buildCriterionQuery = (criterion: Criterion): Filter | undefined => { + const { field, value, comparator } = criterion; + + const queryType = getQueryMappingForComparator(comparator); + + switch (queryType) { + case 'term': + return { + term: { + [field]: { + value, + }, + }, + }; + break; + case 'match': { + return { + match: { + [field]: value, + }, + }; + } + case 'match_phrase': { + return { + match_phrase: { + [field]: value, + }, + }; + } + case 'range': { + const comparatorToRangePropertyMapping: { + [key: string]: string; + } = { + [Comparator.LT]: 'lt', + [Comparator.LT_OR_EQ]: 'lte', + [Comparator.GT]: 'gt', + [Comparator.GT_OR_EQ]: 'gte', + }; + + const rangeProperty = comparatorToRangePropertyMapping[comparator]; + + return { + range: { + [field]: { + [rangeProperty]: value, + }, + }, + }; + } + default: { + return undefined; + } + } +}; + +const getPositiveComparators = () => { + return [ + Comparator.GT, + Comparator.GT_OR_EQ, + Comparator.LT, + Comparator.LT_OR_EQ, + Comparator.EQ, + Comparator.MATCH, + Comparator.MATCH_PHRASE, + ]; +}; + +const getNegativeComparators = () => { + return [Comparator.NOT_EQ, Comparator.NOT_MATCH, Comparator.NOT_MATCH_PHRASE]; +}; + +const queryMappings: { + [key: string]: string; +} = { + [Comparator.GT]: 'range', + [Comparator.GT_OR_EQ]: 'range', + [Comparator.LT]: 'range', + [Comparator.LT_OR_EQ]: 'range', + [Comparator.EQ]: 'term', + [Comparator.MATCH]: 'match', + [Comparator.MATCH_PHRASE]: 'match_phrase', + [Comparator.NOT_EQ]: 'term', + [Comparator.NOT_MATCH]: 'match', + [Comparator.NOT_MATCH_PHRASE]: 'match_phrase', +}; + +const getQueryMappingForComparator = (comparator: Comparator) => { + return queryMappings[comparator]; +}; + +const getResults = async ( + query: object, + index: string, + callCluster: AlertServices['callCluster'] +) => { + return await callCluster('count', { + body: query, + index, + }); +}; + +const createConditionsMessage = (criteria: LogDocumentCountAlertParams['criteria']) => { + const parts = criteria.map((criterion, index) => { + const { field, comparator, value } = criterion; + return `${index === 0 ? '' : 'and'} ${field} ${comparator} ${value}`; + }); + return parts.join(' '); +}; + +// When the Alerting plugin implements support for multiple action groups, add additional +// action groups here to send different messages, e.g. a recovery notification +export const FIRED_ACTIONS = { + id: 'logs.threshold.fired', + name: i18n.translate('xpack.infra.logs.alerting.threshold.fired', { + defaultMessage: 'Fired', + }), +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts new file mode 100644 index 0000000000000..04207a4233dfd --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import uuid from 'uuid'; +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { PluginSetupContract } from '../../../../../alerting/server'; +import { createLogThresholdExecutor, FIRED_ACTIONS } from './log_threshold_executor'; +import { + LOG_DOCUMENT_COUNT_ALERT_TYPE_ID, + Comparator, +} from '../../../../common/alerting/logs/types'; +import { InfraBackendLibs } from '../../infra_types'; + +const documentCountActionVariableDescription = i18n.translate( + 'xpack.infra.logs.alerting.threshold.documentCountActionVariableDescription', + { + defaultMessage: 'The number of log entries that matched the conditions provided', + } +); + +const conditionsActionVariableDescription = i18n.translate( + 'xpack.infra.logs.alerting.threshold.conditionsActionVariableDescription', + { + defaultMessage: 'The conditions that log entries needed to fulfill', + } +); + +const countSchema = schema.object({ + value: schema.number(), + comparator: schema.oneOf([ + schema.literal(Comparator.GT), + schema.literal(Comparator.LT), + schema.literal(Comparator.GT_OR_EQ), + schema.literal(Comparator.LT_OR_EQ), + schema.literal(Comparator.EQ), + ]), +}); + +const criteriaSchema = schema.object({ + field: schema.string(), + comparator: schema.oneOf([ + schema.literal(Comparator.GT), + schema.literal(Comparator.LT), + schema.literal(Comparator.GT_OR_EQ), + schema.literal(Comparator.LT_OR_EQ), + schema.literal(Comparator.EQ), + schema.literal(Comparator.NOT_EQ), + schema.literal(Comparator.MATCH), + schema.literal(Comparator.NOT_MATCH), + ]), + value: schema.oneOf([schema.number(), schema.string()]), +}); + +export async function registerLogThresholdAlertType( + alertingPlugin: PluginSetupContract, + libs: InfraBackendLibs +) { + if (!alertingPlugin) { + throw new Error( + 'Cannot register log threshold alert type. Both the actions and alerting plugins need to be enabled.' + ); + } + + const alertUUID = uuid.v4(); + + alertingPlugin.registerType({ + id: LOG_DOCUMENT_COUNT_ALERT_TYPE_ID, + name: 'Log threshold', + validate: { + params: schema.object({ + count: countSchema, + criteria: schema.arrayOf(criteriaSchema), + timeUnit: schema.string(), + timeSize: schema.number(), + }), + }, + defaultActionGroupId: FIRED_ACTIONS.id, + actionGroups: [FIRED_ACTIONS], + executor: createLogThresholdExecutor(alertUUID, libs), + actionVariables: { + context: [ + { name: 'matchingDocuments', description: documentCountActionVariableDescription }, + { name: 'conditions', description: conditionsActionVariableDescription }, + ], + }, + }); +} diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index a52659dae01f1..24b6ba2ec378b 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -20,7 +20,7 @@ const executor = createMetricThresholdExecutor('test') as (opts: { }) => Promise; const services: AlertServicesMock = alertsMock.createAlertServices(); -services.callCluster.mockImplementation((_: string, { body, index }: any) => { +services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; const metric = body.query.bool.filter[1]?.exists.field; if (body.aggs.groupings) { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts index b697af4fa4c3b..3415ae9873bfb 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { PluginSetupContract } from '../../../../../alerting/server'; import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metrics_explorer'; import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; +import { InfraBackendLibs } from '../../infra_types'; import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; const oneOfLiterals = (arrayOfLiterals: Readonly) => @@ -17,7 +18,10 @@ const oneOfLiterals = (arrayOfLiterals: Readonly) => arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`, }); -export async function registerMetricThresholdAlertType(alertingPlugin: PluginSetupContract) { +export async function registerMetricThresholdAlertType( + alertingPlugin: PluginSetupContract, + libs: InfraBackendLibs +) { if (!alertingPlugin) { throw new Error( 'Cannot register metric threshold alert type. Both the actions and alerting plugins need to be enabled.' diff --git a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts index 6ec6f31256b78..9760873ff7478 100644 --- a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts @@ -6,13 +6,15 @@ import { PluginSetupContract } from '../../../../alerting/server'; import { registerMetricThresholdAlertType } from './metric_threshold/register_metric_threshold_alert_type'; +import { registerLogThresholdAlertType } from './log_threshold/register_log_threshold_alert_type'; +import { InfraBackendLibs } from '../infra_types'; -const registerAlertTypes = (alertingPlugin: PluginSetupContract) => { +const registerAlertTypes = (alertingPlugin: PluginSetupContract, libs: InfraBackendLibs) => { if (alertingPlugin) { - const registerFns = [registerMetricThresholdAlertType]; + const registerFns = [registerMetricThresholdAlertType, registerLogThresholdAlertType]; registerFns.forEach(fn => { - fn(alertingPlugin); + fn(alertingPlugin, libs); }); } }; diff --git a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts index d2e151ca2c3f5..b6837e5b769a6 100644 --- a/x-pack/plugins/infra/server/lib/domains/fields_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/fields_domain.ts @@ -21,7 +21,7 @@ export class InfraFieldsDomain { indexType: InfraIndexType ): Promise { const { configuration } = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const includeMetricIndices = [InfraIndexType.ANY, InfraIndexType.METRICS].includes(indexType); diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index 1e84a8c016c87..07bc965dda77a 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -113,7 +113,7 @@ export class InfraLogEntriesDomain { params: LogEntriesParams ): Promise { const { configuration } = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); @@ -172,7 +172,7 @@ export class InfraLogEntriesDomain { filterQuery?: LogEntryQuery ): Promise { const { configuration } = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const dateRangeBuckets = await this.adapter.getContainedLogSummaryBuckets( @@ -196,7 +196,7 @@ export class InfraLogEntriesDomain { filterQuery?: LogEntryQuery ): Promise { const { configuration } = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const messageFormattingRules = compileFormattingRules( diff --git a/x-pack/plugins/infra/server/lib/source_status.ts b/x-pack/plugins/infra/server/lib/source_status.ts index 1f0845b6b223f..9bb953845e5a1 100644 --- a/x-pack/plugins/infra/server/lib/source_status.ts +++ b/x-pack/plugins/infra/server/lib/source_status.ts @@ -18,7 +18,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const indexNames = await this.adapter.getIndexNames( @@ -32,7 +32,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const indexNames = await this.adapter.getIndexNames( @@ -46,7 +46,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const hasAlias = await this.adapter.hasAlias( @@ -60,7 +60,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const hasAlias = await this.adapter.hasAlias( @@ -74,7 +74,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const hasIndices = await this.adapter.hasIndices( @@ -88,7 +88,7 @@ export class InfraSourceStatus { sourceId: string ): Promise { const sourceConfiguration = await this.libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const hasIndices = await this.adapter.hasIndices( diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index 4a83ca730ff83..57efb0f676b2f 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -29,7 +29,9 @@ describe('the InfraSources lib', () => { }, }); - expect(await sourcesLib.getSourceConfiguration(request, 'TEST_ID')).toMatchObject({ + expect( + await sourcesLib.getSourceConfiguration(request.core.savedObjects.client, 'TEST_ID') + ).toMatchObject({ id: 'TEST_ID', version: 'foo', updatedAt: 946684800000, @@ -74,7 +76,9 @@ describe('the InfraSources lib', () => { }, }); - expect(await sourcesLib.getSourceConfiguration(request, 'TEST_ID')).toMatchObject({ + expect( + await sourcesLib.getSourceConfiguration(request.core.savedObjects.client, 'TEST_ID') + ).toMatchObject({ id: 'TEST_ID', version: 'foo', updatedAt: 946684800000, @@ -104,7 +108,9 @@ describe('the InfraSources lib', () => { attributes: {}, }); - expect(await sourcesLib.getSourceConfiguration(request, 'TEST_ID')).toMatchObject({ + expect( + await sourcesLib.getSourceConfiguration(request.core.savedObjects.client, 'TEST_ID') + ).toMatchObject({ id: 'TEST_ID', version: 'foo', updatedAt: 946684800000, diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index 99e062aa49ccf..0368c7bfd6db8 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -9,7 +9,7 @@ import { failure } from 'io-ts/lib/PathReporter'; import { identity, constant } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; -import { RequestHandlerContext } from 'src/core/server'; +import { RequestHandlerContext, SavedObjectsClientContract } from 'src/core/server'; import { defaultSourceConfiguration } from './defaults'; import { NotFoundError } from './errors'; import { infraSourceConfigurationSavedObjectType } from './saved_object_mappings'; @@ -37,7 +37,7 @@ export class InfraSources { } public async getSourceConfiguration( - requestContext: RequestHandlerContext, + savedObjectsClient: SavedObjectsClientContract, sourceId: string ): Promise { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); @@ -55,7 +55,7 @@ export class InfraSources { })) .catch(err => err instanceof NotFoundError - ? this.getSavedSourceConfiguration(requestContext, sourceId).then(result => ({ + ? this.getSavedSourceConfiguration(savedObjectsClient, sourceId).then(result => ({ ...result, configuration: mergeSourceConfiguration( staticDefaultSourceConfiguration, @@ -65,7 +65,7 @@ export class InfraSources { : Promise.reject(err) ) .catch(err => - requestContext.core.savedObjects.client.errors.isNotFoundError(err) + savedObjectsClient.errors.isNotFoundError(err) ? Promise.resolve({ id: sourceId, version: undefined, @@ -136,7 +136,10 @@ export class InfraSources { ) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); - const { configuration, version } = await this.getSourceConfiguration(requestContext, sourceId); + const { configuration, version } = await this.getSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId + ); const updatedSourceConfigurationAttributes = mergeSourceConfiguration( configuration, @@ -199,10 +202,10 @@ export class InfraSources { } private async getSavedSourceConfiguration( - requestContext: RequestHandlerContext, + savedObjectsClient: SavedObjectsClientContract, sourceId: string ) { - const savedObject = await requestContext.core.savedObjects.client.get( + const savedObject = await savedObjectsClient.get( infraSourceConfigurationSavedObjectType, sourceId ); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index e3804078604cc..d4dfa60ac67a0 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -147,7 +147,7 @@ export class InfraServerPlugin { ]); initInfraServer(this.libs); - registerAlertTypes(plugins.alerting); + registerAlertTypes(plugins.alerting, this.libs); // Telemetry UsageCollector.registerUsageCollector(plugins.usageCollection); diff --git a/x-pack/plugins/infra/server/routes/inventory_metadata/index.ts b/x-pack/plugins/infra/server/routes/inventory_metadata/index.ts index 7e9b7ada28c8e..687e368736a41 100644 --- a/x-pack/plugins/infra/server/routes/inventory_metadata/index.ts +++ b/x-pack/plugins/infra/server/routes/inventory_metadata/index.ts @@ -39,7 +39,7 @@ export const initInventoryMetaRoute = (libs: InfraBackendLibs) => { ); const { configuration } = await libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const awsMetadata = await getCloudMetadata( diff --git a/x-pack/plugins/infra/server/routes/log_entries/item.ts b/x-pack/plugins/infra/server/routes/log_entries/item.ts index 3a6bdaf3804e3..85dba8f598a89 100644 --- a/x-pack/plugins/infra/server/routes/log_entries/item.ts +++ b/x-pack/plugins/infra/server/routes/log_entries/item.ts @@ -37,8 +37,9 @@ export const initLogEntriesItemRoute = ({ framework, sources, logEntries }: Infr ); const { id, sourceId } = payload; - const sourceConfiguration = (await sources.getSourceConfiguration(requestContext, sourceId)) - .configuration; + const sourceConfiguration = ( + await sources.getSourceConfiguration(requestContext.core.savedObjects.client, sourceId) + ).configuration; const logEntry = await logEntries.getLogItem(requestContext, id, sourceConfiguration); diff --git a/x-pack/plugins/infra/server/routes/metadata/index.ts b/x-pack/plugins/infra/server/routes/metadata/index.ts index c45f191b1130d..fe142aa93dcda 100644 --- a/x-pack/plugins/infra/server/routes/metadata/index.ts +++ b/x-pack/plugins/infra/server/routes/metadata/index.ts @@ -44,7 +44,7 @@ export const initMetadataRoute = (libs: InfraBackendLibs) => { ); const { configuration } = await libs.sources.getSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId ); const metricsMetadata = await getMetricMetadata( diff --git a/x-pack/plugins/infra/server/routes/node_details/index.ts b/x-pack/plugins/infra/server/routes/node_details/index.ts index 36906f6f4125b..a457ccac2416c 100644 --- a/x-pack/plugins/infra/server/routes/node_details/index.ts +++ b/x-pack/plugins/infra/server/routes/node_details/index.ts @@ -37,7 +37,10 @@ export const initNodeDetailsRoute = (libs: InfraBackendLibs) => { NodeDetailsRequestRT.decode(request.body), fold(throwErrors(Boom.badRequest), identity) ); - const source = await libs.sources.getSourceConfiguration(requestContext, sourceId); + const source = await libs.sources.getSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId + ); UsageCollector.countNode(nodeType); diff --git a/x-pack/plugins/infra/server/routes/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/index.ts index e45b9884967d0..d1dc03893a0d9 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/index.ts @@ -42,7 +42,10 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => { SnapshotRequestRT.decode(request.body), fold(throwErrors(Boom.badRequest), identity) ); - const source = await libs.sources.getSourceConfiguration(requestContext, sourceId); + const source = await libs.sources.getSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId + ); UsageCollector.countNode(nodeType); const options = { filterQuery: parseFilterQuery(filterQuery), diff --git a/x-pack/plugins/infra/server/routes/source/index.ts b/x-pack/plugins/infra/server/routes/source/index.ts index 2f29320d7bb81..62b7fd7ba902f 100644 --- a/x-pack/plugins/infra/server/routes/source/index.ts +++ b/x-pack/plugins/infra/server/routes/source/index.ts @@ -37,7 +37,10 @@ export const initSourceRoute = (libs: InfraBackendLibs) => { try { const { type, sourceId } = request.params; - const source = await libs.sources.getSourceConfiguration(requestContext, sourceId); + const source = await libs.sources.getSourceConfiguration( + requestContext.core.savedObjects.client, + sourceId + ); if (!source) { return response.notFound(); } diff --git a/x-pack/plugins/ingest_manager/common/constants/index.ts b/x-pack/plugins/ingest_manager/common/constants/index.ts index 45d315e6d5664..6a2e559bbbe4f 100644 --- a/x-pack/plugins/ingest_manager/common/constants/index.ts +++ b/x-pack/plugins/ingest_manager/common/constants/index.ts @@ -12,3 +12,4 @@ export * from './datasource'; export * from './epm'; export * from './output'; export * from './enrollment_api_key'; +export * from './settings'; diff --git a/x-pack/plugins/ingest_manager/common/constants/routes.ts b/x-pack/plugins/ingest_manager/common/constants/routes.ts index 98ca52651a2ae..35e3be98e3982 100644 --- a/x-pack/plugins/ingest_manager/common/constants/routes.ts +++ b/x-pack/plugins/ingest_manager/common/constants/routes.ts @@ -48,6 +48,19 @@ export const AGENT_CONFIG_API_ROUTES = { FULL_INFO_PATTERN: `${AGENT_CONFIG_API_ROOT}/{agentConfigId}/full`, }; +// Output API routes +export const OUTPUT_API_ROUTES = { + LIST_PATTERN: `${API_ROOT}/outputs`, + INFO_PATTERN: `${API_ROOT}/outputs/{outputId}`, + UPDATE_PATTERN: `${API_ROOT}/outputs/{outputId}`, +}; + +// Settings API routes +export const SETTINGS_API_ROUTES = { + INFO_PATTERN: `${API_ROOT}/settings`, + UPDATE_PATTERN: `${API_ROOT}/settings`, +}; + // Agent API routes export const AGENT_API_ROUTES = { LIST_PATTERN: `${FLEET_API_ROOT}/agents`, diff --git a/x-pack/plugins/ingest_manager/common/constants/settings.ts b/x-pack/plugins/ingest_manager/common/constants/settings.ts new file mode 100644 index 0000000000000..a9e7f1df4119c --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/constants/settings.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const GLOBAL_SETTINGS_SAVED_OBJECT_TYPE = 'ingest_manager_settings'; diff --git a/x-pack/plugins/ingest_manager/common/services/routes.ts b/x-pack/plugins/ingest_manager/common/services/routes.ts index 46b76d886f3cd..1a1bd7c65aa25 100644 --- a/x-pack/plugins/ingest_manager/common/services/routes.ts +++ b/x-pack/plugins/ingest_manager/common/services/routes.ts @@ -13,6 +13,8 @@ import { AGENT_API_ROUTES, ENROLLMENT_API_KEY_ROUTES, SETUP_API_ROUTE, + OUTPUT_API_ROUTES, + SETTINGS_API_ROUTES, } from '../constants'; export const epmRouteService = { @@ -112,6 +114,18 @@ export const agentRouteService = { getStatusPath: () => AGENT_API_ROUTES.STATUS_PATTERN, }; +export const outputRoutesService = { + getInfoPath: (outputId: string) => OUTPUT_API_ROUTES.INFO_PATTERN.replace('{outputId}', outputId), + getUpdatePath: (outputId: string) => + OUTPUT_API_ROUTES.UPDATE_PATTERN.replace('{outputId}', outputId), + getListPath: () => OUTPUT_API_ROUTES.LIST_PATTERN, +}; + +export const settingsRoutesService = { + getInfoPath: () => SETTINGS_API_ROUTES.INFO_PATTERN, + getUpdatePath: () => SETTINGS_API_ROUTES.UPDATE_PATTERN, +}; + export const enrollmentAPIKeyRouteService = { getListPath: () => ENROLLMENT_API_KEY_ROUTES.LIST_PATTERN, getCreatePath: () => ENROLLMENT_API_KEY_ROUTES.CREATE_PATTERN, diff --git a/x-pack/plugins/ingest_manager/common/types/models/index.ts b/x-pack/plugins/ingest_manager/common/types/models/index.ts index f73ab7af636a9..2310fdd54a719 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/index.ts @@ -11,3 +11,4 @@ export * from './data_stream'; export * from './output'; export * from './epm'; export * from './enrollment_api_key'; +export * from './settings'; diff --git a/x-pack/plugins/ingest_manager/common/types/models/settings.ts b/x-pack/plugins/ingest_manager/common/types/models/settings.ts new file mode 100644 index 0000000000000..2921808230b47 --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/types/models/settings.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SavedObjectAttributes } from 'src/core/public'; + +interface BaseSettings { + agent_auto_upgrade?: boolean; + package_auto_upgrade?: boolean; + kibana_url?: string; + kibana_ca_sha256?: string; +} + +export interface Settings extends BaseSettings { + id: string; +} + +export interface SettingsSOAttributes extends BaseSettings, SavedObjectAttributes {} diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/index.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/index.ts index c1805023f497a..763fb7d820b2a 100644 --- a/x-pack/plugins/ingest_manager/common/types/rest_spec/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/index.ts @@ -12,3 +12,5 @@ export * from './fleet_setup'; export * from './epm'; export * from './enrollment_api_key'; export * from './install_script'; +export * from './output'; +export * from './settings'; diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/output.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/output.ts new file mode 100644 index 0000000000000..4162060363381 --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/output.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Output } from '../models'; + +export interface GetOneOutputResponse { + item: Output; + success: boolean; +} + +export interface GetOneOutputRequest { + params: { + outputId: string; + }; +} + +export interface PutOutputRequest { + params: { + outputId: string; + }; + body: { + hosts?: string[]; + ca_sha256?: string; + }; +} + +export interface PutOutputResponse { + item: Output; + success: boolean; +} + +export interface GetOutputsResponse { + items: Output[]; + total: number; + page: number; + perPage: number; + success: boolean; +} diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/settings.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/settings.ts new file mode 100644 index 0000000000000..c02a5e5878ee9 --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/settings.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Settings } from '../models'; + +export interface GetSettingsResponse { + item: Settings; + success: boolean; +} + +export interface PutSettingsRequest { + body: Partial>; +} + +export interface PutSettingsResponse { + item: Settings; + success: boolean; +} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts index bdc8f350f7108..b0b4e79cece79 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts @@ -7,3 +7,4 @@ export { Loading } from './loading'; export { Error } from './error'; export { Header, HeaderProps } from './header'; export { AlphaMessaging } from './alpha_messaging'; +export * from './settings_flyout'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx new file mode 100644 index 0000000000000..92146e9ee5679 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/settings_flyout.tsx @@ -0,0 +1,240 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiSpacer, + EuiButton, + EuiFlyoutFooter, + EuiForm, + EuiFormRow, + EuiFieldText, + EuiRadioGroup, + EuiComboBox, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiText } from '@elastic/eui'; +import { useInput, useComboInput, useCore, useGetSettings, sendPutSettings } from '../hooks'; +import { useGetOutputs, sendPutOutput } from '../hooks/use_request/outputs'; + +interface Props { + onClose: () => void; +} + +function useSettingsForm(outputId: string | undefined) { + const { notifications } = useCore(); + const kibanaUrlInput = useInput(); + const elasticsearchUrlInput = useComboInput([]); + + return { + onSubmit: async () => { + try { + if (!outputId) { + throw new Error('Unable to load outputs'); + } + await sendPutOutput(outputId, { + hosts: elasticsearchUrlInput.value, + }); + await sendPutSettings({ + kibana_url: kibanaUrlInput.value, + }); + } catch (error) { + notifications.toasts.addError(error, { + title: 'Error', + }); + } + notifications.toasts.addSuccess( + i18n.translate('xpack.ingestManager.settings.success.message', { + defaultMessage: 'Settings saved', + }) + ); + }, + inputs: { + kibanaUrl: kibanaUrlInput, + elasticsearchUrl: elasticsearchUrlInput, + }, + }; +} + +export const SettingFlyout: React.FunctionComponent = ({ onClose }) => { + const core = useCore(); + const settingsRequest = useGetSettings(); + const settings = settingsRequest?.data?.item; + const outputsRequest = useGetOutputs(); + const output = outputsRequest.data?.items?.[0]; + const { inputs, onSubmit } = useSettingsForm(output?.id); + + useEffect(() => { + if (output) { + inputs.elasticsearchUrl.setValue(output.hosts || []); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [output]); + + useEffect(() => { + if (settings) { + inputs.kibanaUrl.setValue( + settings.kibana_url || `${window.location.origin}${core.http.basePath.get()}` + ); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [settings]); + + const body = ( + + {}} + legend={{ + children: ( + +

+ +

+
+ ), + }} + /> + + {}} + legend={{ + children: ( + +

+ +

+
+ ), + }} + /> + + +

+ +

+
+ + + + + + + + + + + + + + + + +
+ ); + + return ( + + + +

+ +

+
+
+ {body} + + + + + + + + + + + + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_input.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_input.ts index 4aa0ad7155d2f..c535dc899638d 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_input.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_input.ts @@ -20,5 +20,27 @@ export function useInput(defaultValue = '') { clear: () => { setValue(''); }, + setValue, + }; +} + +export function useComboInput(defaultValue = []) { + const [value, setValue] = React.useState(defaultValue); + + return { + props: { + selectedOptions: value.map((val: string) => ({ label: val })), + onCreateOption: (newVal: any) => { + setValue([...value, newVal]); + }, + onChange: (newVals: any[]) => { + setValue(newVals.map(val => val.label)); + }, + }, + value, + clear: () => { + setValue([]); + }, + setValue, }; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts index 084aba9a34309..c39d2a5860bf0 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/index.ts @@ -10,3 +10,5 @@ export * from './data_stream'; export * from './agents'; export * from './enrollment_api_keys'; export * from './epm'; +export * from './outputs'; +export * from './settings'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/outputs.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/outputs.ts new file mode 100644 index 0000000000000..e57256d33ab2f --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/outputs.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { sendRequest, useRequest } from './use_request'; +import { outputRoutesService } from '../../services'; +import { PutOutputRequest, GetOutputsResponse } from '../../types'; + +export function useGetOutputs() { + return useRequest({ + method: 'get', + path: outputRoutesService.getListPath(), + }); +} + +export function sendPutOutput(outputId: string, body: PutOutputRequest['body']) { + return sendRequest({ + method: 'put', + path: outputRoutesService.getUpdatePath(outputId), + body, + }); +} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/settings.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/settings.ts new file mode 100644 index 0000000000000..45e4eccf6625e --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_request/settings.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { sendRequest, useRequest } from './use_request'; +import { settingsRoutesService } from '../../services'; +import { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types'; + +export function useGetSettings() { + return useRequest({ + method: 'get', + path: settingsRoutesService.getInfoPath(), + }); +} + +export function sendPutSettings(body: PutSettingsRequest['body']) { + return sendRequest({ + method: 'put', + path: settingsRoutesService.getUpdatePath(), + body, + }); +} diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx index f1f9063de72f0..10245e73520f7 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx @@ -5,10 +5,10 @@ */ import React from 'react'; import styled from 'styled-components'; -import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Section } from '../sections'; -import { AlphaMessaging } from '../components'; +import { AlphaMessaging, SettingFlyout } from '../components'; import { useLink, useConfig } from '../hooks'; import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH, DATA_STREAM_PATH } from '../constants'; @@ -35,59 +35,79 @@ const Nav = styled.nav` export const DefaultLayout: React.FunctionComponent = ({ section, children }) => { const { epm, fleet } = useConfig(); + + const [isSettingsFlyoutOpen, setIsSettingsFlyoutOpen] = React.useState(false); + return ( - - + {children} + + + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts index 53dbe295718c5..e4791cc816d04 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/services/index.ts @@ -15,6 +15,8 @@ export { enrollmentAPIKeyRouteService, epmRouteService, setupRouteService, + outputRoutesService, + settingsRoutesService, packageToConfigDatasourceInputs, storedDatasourceToAgentDatasource, AgentStatusKueryHelper, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts index 8ca1495a94071..2f78ecd1b085e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/types/index.ts @@ -17,6 +17,7 @@ export { DatasourceInput, DatasourceInputStream, DatasourceConfigRecordEntry, + Output, DataStream, // API schemas - Agent Config GetAgentConfigsResponse, @@ -48,6 +49,14 @@ export { GetEnrollmentAPIKeysResponse, GetEnrollmentAPIKeysRequest, GetOneEnrollmentAPIKeyResponse, + // API schemas - Outputs + GetOutputsResponse, + PutOutputRequest, + PutOutputResponse, + // API schemas - Settings + GetSettingsResponse, + PutSettingsRequest, + PutSettingsResponse, // EPM types AssetReference, AssetsGroupedByServiceByType, diff --git a/x-pack/plugins/ingest_manager/server/constants/index.ts b/x-pack/plugins/ingest_manager/server/constants/index.ts index 9336b3f870e00..75c14ffc8fa84 100644 --- a/x-pack/plugins/ingest_manager/server/constants/index.ts +++ b/x-pack/plugins/ingest_manager/server/constants/index.ts @@ -19,7 +19,9 @@ export { FLEET_SETUP_API_ROUTES, ENROLLMENT_API_KEY_ROUTES, INSTALL_SCRIPT_API_ROUTES, + OUTPUT_API_ROUTES, SETUP_API_ROUTE, + SETTINGS_API_ROUTES, // Saved object types AGENT_SAVED_OBJECT_TYPE, AGENT_EVENT_SAVED_OBJECT_TYPE, @@ -30,6 +32,7 @@ export { PACKAGES_SAVED_OBJECT_TYPE, INDEX_PATTERN_SAVED_OBJECT_TYPE, ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, + GLOBAL_SETTINGS_SAVED_OBJECT_TYPE as GLOBAL_SETTINGS_SAVED_OBJET_TYPE, // Defaults DEFAULT_AGENT_CONFIG, DEFAULT_OUTPUT, diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index 4bf9785dcd306..097825e0b69e1 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -39,6 +39,8 @@ import { registerAgentRoutes, registerEnrollmentApiKeyRoutes, registerInstallScriptRoutes, + registerOutputRoutes, + registerSettingsRoutes, } from './routes'; import { IngestManagerConfigType } from '../common'; @@ -150,6 +152,8 @@ export class IngestManagerPlugin // Register routes registerAgentConfigRoutes(router); registerDatasourceRoutes(router); + registerOutputRoutes(router); + registerSettingsRoutes(router); registerDataStreamRoutes(router); // Conditional routes diff --git a/x-pack/plugins/ingest_manager/server/routes/index.ts b/x-pack/plugins/ingest_manager/server/routes/index.ts index 8a186c5485024..3ce34d15de46c 100644 --- a/x-pack/plugins/ingest_manager/server/routes/index.ts +++ b/x-pack/plugins/ingest_manager/server/routes/index.ts @@ -11,3 +11,5 @@ export { registerRoutes as registerSetupRoutes } from './setup'; export { registerRoutes as registerAgentRoutes } from './agent'; export { registerRoutes as registerEnrollmentApiKeyRoutes } from './enrollment_api_key'; export { registerRoutes as registerInstallScriptRoutes } from './install_script'; +export { registerRoutes as registerOutputRoutes } from './output'; +export { registerRoutes as registerSettingsRoutes } from './settings'; diff --git a/x-pack/plugins/ingest_manager/server/routes/output/handler.ts b/x-pack/plugins/ingest_manager/server/routes/output/handler.ts new file mode 100644 index 0000000000000..cd35b2a43426c --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/routes/output/handler.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RequestHandler } from 'src/core/server'; +import { TypeOf } from '@kbn/config-schema'; +import { GetOneOutputRequestSchema, PutOutputRequestSchema } from '../../types'; +import { GetOneOutputResponse, GetOutputsResponse } from '../../../common'; +import { outputService } from '../../services/output'; + +export const getOutputsHandler: RequestHandler = async (context, request, response) => { + const soClient = context.core.savedObjects.client; + try { + const outputs = await outputService.list(soClient); + + const body: GetOutputsResponse = { + items: outputs.items, + page: outputs.page, + perPage: outputs.perPage, + total: outputs.total, + success: true, + }; + + return response.ok({ body }); + } catch (e) { + return response.customError({ + statusCode: 500, + body: { message: e.message }, + }); + } +}; + +export const getOneOuputHandler: RequestHandler> = async (context, request, response) => { + const soClient = context.core.savedObjects.client; + try { + const output = await outputService.get(soClient, request.params.outputId); + + const body: GetOneOutputResponse = { + item: output, + success: true, + }; + + return response.ok({ body }); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return response.notFound({ + body: { message: `Output ${request.params.outputId} not found` }, + }); + } + + return response.customError({ + statusCode: 500, + body: { message: e.message }, + }); + } +}; + +export const putOuputHandler: RequestHandler< + TypeOf, + undefined, + TypeOf +> = async (context, request, response) => { + const soClient = context.core.savedObjects.client; + try { + await outputService.update(soClient, request.params.outputId, request.body); + const output = await outputService.get(soClient, request.params.outputId); + + const body: GetOneOutputResponse = { + item: output, + success: true, + }; + + return response.ok({ body }); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return response.notFound({ + body: { message: `Output ${request.params.outputId} not found` }, + }); + } + + return response.customError({ + statusCode: 500, + body: { message: e.message }, + }); + } +}; diff --git a/x-pack/plugins/ingest_manager/server/routes/output/index.ts b/x-pack/plugins/ingest_manager/server/routes/output/index.ts new file mode 100644 index 0000000000000..139d11dba951a --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/routes/output/index.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'src/core/server'; +import { PLUGIN_ID, OUTPUT_API_ROUTES } from '../../constants'; +import { getOneOuputHandler, getOutputsHandler, putOuputHandler } from './handler'; +import { + GetOneOutputRequestSchema, + GetOutputsRequestSchema, + PutOutputRequestSchema, +} from '../../types'; + +export const registerRoutes = (router: IRouter) => { + router.get( + { + path: OUTPUT_API_ROUTES.LIST_PATTERN, + validate: GetOutputsRequestSchema, + options: { tags: [`access:${PLUGIN_ID}-read`] }, + }, + getOutputsHandler + ); + router.get( + { + path: OUTPUT_API_ROUTES.INFO_PATTERN, + validate: GetOneOutputRequestSchema, + options: { tags: [`access:${PLUGIN_ID}-read`] }, + }, + getOneOuputHandler + ); + router.put( + { + path: OUTPUT_API_ROUTES.UPDATE_PATTERN, + validate: PutOutputRequestSchema, + options: { tags: [`access:${PLUGIN_ID}-read`] }, + }, + putOuputHandler + ); +}; diff --git a/x-pack/plugins/ingest_manager/server/routes/settings/index.ts b/x-pack/plugins/ingest_manager/server/routes/settings/index.ts new file mode 100644 index 0000000000000..56e666056e8d0 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/routes/settings/index.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { IRouter, RequestHandler } from 'src/core/server'; +import { TypeOf } from '@kbn/config-schema'; +import { PLUGIN_ID, SETTINGS_API_ROUTES } from '../../constants'; +import { PutSettingsRequestSchema, GetSettingsRequestSchema } from '../../types'; + +import { settingsService } from '../../services'; + +export const getSettingsHandler: RequestHandler = async (context, request, response) => { + const soClient = context.core.savedObjects.client; + + try { + const settings = await settingsService.getSettings(soClient); + const body = { + success: true, + item: settings, + }; + return response.ok({ body }); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return response.notFound({ + body: { message: `Setings not found` }, + }); + } + + return response.customError({ + statusCode: 500, + body: { message: e.message }, + }); + } +}; + +export const putSettingsHandler: RequestHandler< + undefined, + undefined, + TypeOf +> = async (context, request, response) => { + const soClient = context.core.savedObjects.client; + try { + const settings = await settingsService.saveSettings(soClient, request.body); + const body = { + success: true, + item: settings, + }; + return response.ok({ body }); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return response.notFound({ + body: { message: `Setings not found` }, + }); + } + + return response.customError({ + statusCode: 500, + body: { message: e.message }, + }); + } +}; + +export const registerRoutes = (router: IRouter) => { + router.get( + { + path: SETTINGS_API_ROUTES.INFO_PATTERN, + validate: GetSettingsRequestSchema, + options: { tags: [`access:${PLUGIN_ID}-read`] }, + }, + getSettingsHandler + ); + router.put( + { + path: SETTINGS_API_ROUTES.UPDATE_PATTERN, + validate: PutSettingsRequestSchema, + options: { tags: [`access:${PLUGIN_ID}-all`] }, + }, + putSettingsHandler + ); +}; diff --git a/x-pack/plugins/ingest_manager/server/saved_objects.ts b/x-pack/plugins/ingest_manager/server/saved_objects.ts index d827fb776b12c..0b130e7b70101 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects.ts @@ -15,6 +15,7 @@ import { AGENT_EVENT_SAVED_OBJECT_TYPE, AGENT_ACTION_SAVED_OBJECT_TYPE, ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, + GLOBAL_SETTINGS_SAVED_OBJET_TYPE, } from './constants'; /* @@ -22,7 +23,24 @@ import { * * Please update typings in `/common/types` if mappings are updated. */ + const savedObjectTypes: { [key: string]: SavedObjectsType } = { + [GLOBAL_SETTINGS_SAVED_OBJET_TYPE]: { + name: GLOBAL_SETTINGS_SAVED_OBJET_TYPE, + hidden: false, + namespaceType: 'agnostic', + management: { + importableAndExportable: false, + }, + mappings: { + properties: { + agent_auto_upgrade: { type: 'keyword' }, + package_auto_upgrade: { type: 'keyword' }, + kibana_url: { type: 'keyword' }, + kibana_ca_sha256: { type: 'keyword' }, + }, + }, + }, [AGENT_SAVED_OBJECT_TYPE]: { name: AGENT_SAVED_OBJECT_TYPE, hidden: false, diff --git a/x-pack/plugins/ingest_manager/server/services/index.ts b/x-pack/plugins/ingest_manager/server/services/index.ts index 5141c86516f13..483661b9de915 100644 --- a/x-pack/plugins/ingest_manager/server/services/index.ts +++ b/x-pack/plugins/ingest_manager/server/services/index.ts @@ -3,9 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { SavedObjectsClientContract } from 'kibana/server'; import { AgentStatus } from '../../common/types/models'; - +import * as settingsService from './settings'; export { ESIndexPatternSavedObjectService } from './es_index_pattern'; /** @@ -35,6 +36,7 @@ export interface AgentService { export { datasourceService } from './datasource'; export { agentConfigService } from './agent_config'; export { outputService } from './output'; +export { settingsService }; // Plugin services export { appContextService } from './app_context'; diff --git a/x-pack/plugins/ingest_manager/server/services/output.ts b/x-pack/plugins/ingest_manager/server/services/output.ts index 6c0dce79d550d..395c9af4a4ca2 100644 --- a/x-pack/plugins/ingest_manager/server/services/output.ts +++ b/x-pack/plugins/ingest_manager/server/services/output.ts @@ -95,6 +95,34 @@ class OutputService { ...outputSO.attributes, }; } + + public async update(soClient: SavedObjectsClientContract, id: string, data: Partial) { + const outputSO = await soClient.update(SAVED_OBJECT_TYPE, id, data); + + if (outputSO.error) { + throw new Error(outputSO.error.message); + } + } + + public async list(soClient: SavedObjectsClientContract) { + const outputs = await soClient.find({ + type: SAVED_OBJECT_TYPE, + page: 1, + perPage: 1000, + }); + + return { + items: outputs.saved_objects.map(outputSO => { + return { + id: outputSO.id, + ...outputSO.attributes, + }; + }), + total: outputs.total, + page: 1, + perPage: 1000, + }; + } } export const outputService = new OutputService(); diff --git a/x-pack/plugins/ingest_manager/server/services/settings.ts b/x-pack/plugins/ingest_manager/server/services/settings.ts new file mode 100644 index 0000000000000..f1c09746d9abd --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/settings.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import Boom from 'boom'; +import { SavedObjectsClientContract } from 'kibana/server'; +import { GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, SettingsSOAttributes, Settings } from '../../common'; + +export async function getSettings(soClient: SavedObjectsClientContract): Promise { + const res = await soClient.find({ + type: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + }); + + if (res.total === 0) { + throw Boom.notFound('Global settings not found'); + } + const settingsSo = res.saved_objects[0]; + return { + id: settingsSo.id, + ...settingsSo.attributes, + }; +} + +export async function saveSettings( + soClient: SavedObjectsClientContract, + newData: Partial> +): Promise { + try { + const settings = await getSettings(soClient); + + const res = await soClient.update( + GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + settings.id, + newData + ); + + return { + id: settings.id, + ...res.attributes, + }; + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + const res = await soClient.create( + GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + newData + ); + + return { + id: res.id, + ...res.attributes, + }; + } + + throw e; + } +} diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts index 167a24481aba5..206ad76703cf5 100644 --- a/x-pack/plugins/ingest_manager/server/services/setup.ts +++ b/x-pack/plugins/ingest_manager/server/services/setup.ts @@ -21,6 +21,8 @@ import { import { getPackageInfo } from './epm/packages'; import { datasourceService } from './datasource'; import { generateEnrollmentAPIKey } from './api_keys'; +import { settingsService } from '.'; +import { appContextService } from './app_context'; const FLEET_ENROLL_USERNAME = 'fleet_enroll'; const FLEET_ENROLL_ROLE = 'fleet_enroll'; @@ -34,6 +36,17 @@ export async function setupIngestManager( ensureInstalledDefaultPackages(soClient, callCluster), outputService.ensureDefaultOutput(soClient), agentConfigService.ensureDefaultAgentConfig(soClient), + settingsService.getSettings(soClient).catch((e: any) => { + if (e.isBoom && e.output.statusCode === 404) { + return settingsService.saveSettings(soClient, { + agent_auto_upgrade: true, + package_auto_upgrade: true, + kibana_url: appContextService.getConfig()?.fleet?.kibana?.host, + }); + } + + return Promise.reject(e); + }), ]); // ensure default packages are added to the default conifg diff --git a/x-pack/plugins/ingest_manager/server/types/index.tsx b/x-pack/plugins/ingest_manager/server/types/index.tsx index aa5496cc836b7..a7019ebc0a271 100644 --- a/x-pack/plugins/ingest_manager/server/types/index.tsx +++ b/x-pack/plugins/ingest_manager/server/types/index.tsx @@ -50,6 +50,8 @@ export { DefaultPackages, TemplateRef, IndexTemplateMappings, + Settings, + SettingsSOAttributes, } from '../../common'; export type CallESAsCurrentUser = ScopedClusterClient['callAsCurrentUser']; diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts index 42b607fa1c715..6976dae38d5f1 100644 --- a/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts +++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/index.ts @@ -10,3 +10,5 @@ export * from './datasource'; export * from './epm'; export * from './enrollment_api_key'; export * from './install_script'; +export * from './output'; +export * from './settings'; diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/output.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/output.ts new file mode 100644 index 0000000000000..79a7c444dacdb --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/output.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; + +export const GetOneOutputRequestSchema = { + params: schema.object({ + outputId: schema.string(), + }), +}; + +export const GetOutputsRequestSchema = {}; + +export const PutOutputRequestSchema = { + params: schema.object({ + outputId: schema.string(), + }), + body: schema.object({ + hosts: schema.maybe(schema.arrayOf(schema.string())), + ca_sha256: schema.maybe(schema.string()), + }), +}; diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/settings.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/settings.ts new file mode 100644 index 0000000000000..8b7500e4a9bd9 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/settings.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; + +export const GetSettingsRequestSchema = {}; + +export const PutSettingsRequestSchema = { + body: schema.object({ + agent_auto_upgrade: schema.maybe(schema.boolean()), + package_auto_upgrade: schema.maybe(schema.boolean()), + kibana_url: schema.maybe(schema.string()), + kibana_ca_sha256: schema.maybe(schema.string()), + }), +}; diff --git a/x-pack/plugins/maps/public/angular/get_initial_layers.js b/x-pack/plugins/maps/public/angular/get_initial_layers.js index 1eb5dac309f28..f02ded1704533 100644 --- a/x-pack/plugins/maps/public/angular/get_initial_layers.js +++ b/x-pack/plugins/maps/public/angular/get_initial_layers.js @@ -5,27 +5,18 @@ */ import _ from 'lodash'; // Import each layer type, even those not used, to init in registry - import '../layers/sources/wms_source'; - import '../layers/sources/ems_file_source'; - import '../layers/sources/es_search_source'; - -import '../layers/sources/es_pew_pew_source/es_pew_pew_source'; - +import '../layers/sources/es_pew_pew_source'; import '../layers/sources/kibana_regionmap_source'; - import '../layers/sources/es_geo_grid_source'; - import '../layers/sources/xyz_tms_source'; - import { KibanaTilemapSource } from '../layers/sources/kibana_tilemap_source'; - +import { TileLayer } from '../layers/tile_layer'; import { EMSTMSSource } from '../layers/sources/ems_tms_source'; - +import { VectorTileLayer } from '../layers/vector_tile_layer'; import { getInjectedVarFunc } from '../kibana_services'; - import { getKibanaTileMap } from '../meta'; export function getInitialLayers(layerListJSON, initialLayers = []) { @@ -35,18 +26,18 @@ export function getInitialLayers(layerListJSON, initialLayers = []) { const tilemapSourceFromKibana = getKibanaTileMap(); if (_.get(tilemapSourceFromKibana, 'url')) { - const sourceDescriptor = KibanaTilemapSource.createDescriptor(); - const source = new KibanaTilemapSource(sourceDescriptor); - const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor(), ...initialLayers]; + const layerDescriptor = TileLayer.createDescriptor({ + sourceDescriptor: KibanaTilemapSource.createDescriptor(), + }); + return [layerDescriptor, ...initialLayers]; } const isEmsEnabled = getInjectedVarFunc()('isEmsEnabled', true); if (isEmsEnabled) { - const descriptor = EMSTMSSource.createDescriptor({ isAutoSelect: true }); - const source = new EMSTMSSource(descriptor); - const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor(), ...initialLayers]; + const layerDescriptor = VectorTileLayer.createDescriptor({ + sourceDescriptor: EMSTMSSource.createDescriptor({ isAutoSelect: true }), + }); + return [layerDescriptor, ...initialLayers]; } return initialLayers; diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js index a4fa0d492bf3f..8ebb17ac4fff5 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js @@ -4,51 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; -import { EuiSpacer, EuiPanel, EuiButtonEmpty } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import React from 'react'; +import { EuiPanel } from '@elastic/eui'; import { uploadLayerWizardConfig } from '../../../layers/sources/client_file_source'; -export const ImportEditor = ({ clearSource, isIndexingTriggered, ...props }) => { - const editorProperties = getEditorProperties({ isIndexingTriggered, ...props }); +export const ImportEditor = props => { + const editorProperties = getEditorProperties(props); return ( - - {isIndexingTriggered ? null : ( - - - - - - - )} - - {uploadLayerWizardConfig.renderWizard(editorProperties)} - - + + {uploadLayerWizardConfig.renderWizard(editorProperties)} + ); }; function getEditorProperties({ - inspectorAdapters, + previewLayer, + mapColors, onRemove, - viewLayer, isIndexingTriggered, onIndexReady, importSuccessHandler, importErrorHandler, }) { return { - onPreviewSource: viewLayer, - inspectorAdapters, + previewLayer, + mapColors, onRemove, importSuccessHandler, importErrorHandler, isIndexingTriggered, - addAndViewSource: viewLayer, onIndexReady, }; } diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js index 24c1f5ced4fe6..a29898f8a2830 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js @@ -34,12 +34,12 @@ function mapStateToProps(state = {}) { function mapDispatchToProps(dispatch) { return { - viewLayer: async layer => { + previewLayer: async layerDescriptor => { await dispatch(setSelectedLayer(null)); await dispatch(removeTransientLayer()); - dispatch(addLayer(layer.toLayerDescriptor())); - dispatch(setSelectedLayer(layer.getId())); - dispatch(setTransientLayer(layer.getId())); + dispatch(addLayer(layerDescriptor)); + dispatch(setSelectedLayer(layerDescriptor.id)); + dispatch(setTransientLayer(layerDescriptor.id)); }, removeTransientLayer: () => { dispatch(setSelectedLayer(null)); diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js deleted file mode 100644 index 8937f32d3bf05..0000000000000 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { connect } from 'react-redux'; -import { SourceEditor } from './view'; - -import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; - -function mapStateToProps(state = {}) { - return { - inspectorAdapters: getInspectorAdapters(state), - }; -} - -const connectedFlyOut = connect(mapStateToProps)(SourceEditor); -export { connectedFlyOut as SourceEditor }; diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js deleted file mode 100644 index 50312b68277fa..0000000000000 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { Fragment } from 'react'; -import { EuiSpacer, EuiPanel, EuiButtonEmpty } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export const SourceEditor = ({ - clearSource, - layerWizard, - isIndexingTriggered, - inspectorAdapters, - previewLayer, -}) => { - if (!layerWizard) { - return null; - } - - return ( - - {isIndexingTriggered ? null : ( - - - - - - - )} - - {layerWizard.renderWizard({ onPreviewSource: previewLayer, inspectorAdapters })} - - - ); -}; diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js index 80b05a0fd015b..82df9237e6ed3 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js @@ -7,8 +7,7 @@ import React, { Fragment } from 'react'; import { getLayerWizards } from '../../../layers/layer_wizard_registry'; -import { EuiTitle, EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; import _ from 'lodash'; export function SourceSelect({ updateSourceSelection }) { @@ -38,17 +37,5 @@ export function SourceSelect({ updateSourceSelection }) { ); }); - return ( - - -

- -

-
- {sourceCards} -
- ); + return {sourceCards}; } diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js index 92fcf01f3901f..127b99d730db5 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js @@ -4,18 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { SourceSelect } from './source_select/source_select'; import { FlyoutFooter } from './flyout_footer'; -import { SourceEditor } from './source_editor'; import { ImportEditor } from './import_editor'; -import { EuiFlexGroup, EuiTitle, EuiFlyoutHeader } from '@elastic/eui'; +import { EuiButtonEmpty, EuiPanel, EuiTitle, EuiFlyoutHeader, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; export class AddLayerPanel extends Component { state = { layerWizard: null, - layer: null, + layerDescriptor: null, // TODO get this from redux store instead of storing locally + isIndexingSource: false, importView: false, layerImportAddReady: false, }; @@ -35,13 +36,9 @@ export class AddLayerPanel extends Component { } _getPanelDescription() { - const { layerWizard, importView, layerImportAddReady } = this.state; + const { importView, layerImportAddReady } = this.state; let panelDescription; - if (!layerWizard) { - panelDescription = i18n.translate('xpack.maps.addLayerPanel.selectSource', { - defaultMessage: 'Select source', - }); - } else if (layerImportAddReady || !importView) { + if (layerImportAddReady || !importView) { panelDescription = i18n.translate('xpack.maps.addLayerPanel.addLayer', { defaultMessage: 'Add layer', }); @@ -53,29 +50,21 @@ export class AddLayerPanel extends Component { return panelDescription; } - _viewLayer = async (source, options = {}) => { + _previewLayer = async (layerDescriptor, isIndexingSource) => { if (!this._isMounted) { return; } - if (!source) { - this.setState({ layer: null }); + if (!layerDescriptor) { + this.setState({ + layerDescriptor: null, + isIndexingSource: false, + }); this.props.removeTransientLayer(); return; } - const styleDescriptor = - this.state.layer && this.state.layer.getCurrentStyle() - ? this.state.layer.getCurrentStyle().getDescriptor() - : null; - const layerInitProps = { - ...options, - style: styleDescriptor, - }; - const newLayer = source.createDefaultLayer(layerInitProps, this.props.mapColors); - if (!this._isMounted) { - return; - } - this.setState({ layer: newLayer }, () => this.props.viewLayer(this.state.layer)); + this.setState({ layerDescriptor, isIndexingSource }); + this.props.previewLayer(layerDescriptor); }; _clearLayerData = ({ keepSourceType = false }) => { @@ -84,7 +73,8 @@ export class AddLayerPanel extends Component { } this.setState({ - layer: null, + layerDescriptor: null, + isIndexingSource: false, ...(!keepSourceType ? { layerWizard: null, importView: false } : {}), }); this.props.removeTransientLayer(); @@ -95,72 +85,75 @@ export class AddLayerPanel extends Component { }; _layerAddHandler = () => { - const { - isIndexingTriggered, - setIndexingTriggered, - selectLayerAndAdd, - resetIndexing, - } = this.props; - const layerSource = this.state.layer.getSource(); - const boolIndexLayer = layerSource.shouldBeIndexed(); - this.setState({ layer: null }); - if (boolIndexLayer && !isIndexingTriggered) { - setIndexingTriggered(); + if (this.state.isIndexingSource && !this.props.isIndexingTriggered) { + this.props.setIndexingTriggered(); } else { - selectLayerAndAdd(); + this.props.selectLayerAndAdd(); if (this.state.importView) { this.setState({ layerImportAddReady: false, }); - resetIndexing(); + this.props.resetIndexing(); } } }; - _renderAddLayerPanel() { - const { layerWizard, importView } = this.state; - if (!layerWizard) { + _renderPanelBody() { + if (!this.state.layerWizard) { return ; } - if (importView) { + + const backButton = this.props.isIndexingTriggered ? null : ( + + + + + + + ); + + if (this.state.importView) { return ( - this._clearLayerData({ keepSourceType: true })} - /> + + {backButton} + this._clearLayerData({ keepSourceType: true })} + /> + ); } - return ( - - ); - } - - _renderFooter(buttonDescription) { - const { importView, layer } = this.state; - const { isIndexingReady, isIndexingSuccess } = this.props; - - const buttonEnabled = importView ? isIndexingReady || isIndexingSuccess : !!layer; return ( - + + {backButton} + + {this.state.layerWizard.renderWizard({ + previewLayer: this._previewLayer, + mapColors: this.props.mapColors, + })} + + ); } - _renderFlyout() { + render() { + if (!this.props.flyoutVisible) { + return null; + } + const panelDescription = this._getPanelDescription(); + const isNextBtnEnabled = this.state.importView + ? this.props.isIndexingReady || this.props.isIndexingSuccess + : !!this.state.layerDescriptor; return ( - +

{panelDescription}

@@ -168,14 +161,16 @@ export class AddLayerPanel extends Component {
-
{this._renderAddLayerPanel()}
+
{this._renderPanelBody()}
- {this._renderFooter(panelDescription)} -
- ); - } - render() { - return this.props.flyoutVisible ? this._renderFlyout() : null; + + + ); } } diff --git a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts index 1fc3ad203706f..5c486200977d7 100644 --- a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts @@ -156,7 +156,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { static type = LAYER_TYPE.BLENDED_VECTOR; static createDescriptor( - options: VectorLayerDescriptor, + options: Partial, mapColors: string[] ): VectorLayerDescriptor { const layerDescriptor = VectorLayer.createDescriptor(options, mapColors); diff --git a/x-pack/plugins/maps/public/layers/layer.tsx b/x-pack/plugins/maps/public/layers/layer.tsx index ce48793e1481b..13fe447cec3da 100644 --- a/x-pack/plugins/maps/public/layers/layer.tsx +++ b/x-pack/plugins/maps/public/layers/layer.tsx @@ -62,7 +62,6 @@ export interface ILayer { isLayerLoading(): boolean; hasErrors(): boolean; getErrors(): string; - toLayerDescriptor(): LayerDescriptor; getMbLayerIds(): string[]; ownsMbLayerId(mbLayerId: string): boolean; ownsMbSourceId(mbSourceId: string): boolean; @@ -413,10 +412,6 @@ export class AbstractLayer implements ILayer { : ''; } - toLayerDescriptor(): LayerDescriptor { - return this._descriptor; - } - async syncData(syncContext: SyncContext) { // no-op by default } diff --git a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts index cb87aeaa9da3f..633e8c86d8c94 100644 --- a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts +++ b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts @@ -6,13 +6,17 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ import { ReactElement } from 'react'; -import { ISource } from './sources/source'; - -export type PreviewSourceHandler = (source: ISource | null) => void; +import { LayerDescriptor } from '../../common/descriptor_types'; export type RenderWizardArguments = { - onPreviewSource: PreviewSourceHandler; - inspectorAdapters: object; + previewLayer: (layerDescriptor: LayerDescriptor | null, isIndexingSource?: boolean) => void; + mapColors: string[]; + // upload arguments + isIndexingTriggered: boolean; + onRemove: () => void; + onIndexReady: () => void; + importSuccessHandler: (indexResponses: unknown) => void; + importErrorHandler: (indexResponses: unknown) => void; }; export type LayerWizard = { diff --git a/x-pack/plugins/maps/public/layers/load_layer_wizards.ts b/x-pack/plugins/maps/public/layers/load_layer_wizards.ts index 49d128257fe20..0b83f3bbdc613 100644 --- a/x-pack/plugins/maps/public/layers/load_layer_wizards.ts +++ b/x-pack/plugins/maps/public/layers/load_layer_wizards.ts @@ -12,7 +12,7 @@ import { esDocumentsLayerWizardConfig } from './sources/es_search_source'; // @ts-ignore import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from './sources/es_geo_grid_source'; // @ts-ignore -import { point2PointLayerWizardConfig } from './sources/es_pew_pew_source/es_pew_pew_source'; +import { point2PointLayerWizardConfig } from './sources/es_pew_pew_source'; // @ts-ignore import { emsBoundariesLayerWizardConfig } from './sources/ems_file_source'; // @ts-ignore diff --git a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js index 36f898f723757..3c9c71d2a1875 100644 --- a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js +++ b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js @@ -5,17 +5,7 @@ */ import { AbstractVectorSource } from '../vector_source'; -import React from 'react'; -import { - ES_GEO_FIELD_TYPE, - SOURCE_TYPES, - DEFAULT_MAX_RESULT_WINDOW, - SCALING_TYPES, -} from '../../../../common/constants'; -import { ClientFileCreateSourceEditor } from './create_client_file_source_editor'; -import { ESSearchSource } from '../es_search_source'; -import uuid from 'uuid/v4'; -import { i18n } from '@kbn/i18n'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; export class GeojsonFileSource extends AbstractVectorSource { @@ -66,103 +56,9 @@ export class GeojsonFileSource extends AbstractVectorSource { canFormatFeatureProperties() { return true; } - - shouldBeIndexed() { - return true; - } } -const viewIndexedData = ( - addAndViewSource, - inspectorAdapters, - importSuccessHandler, - importErrorHandler -) => { - return (indexResponses = {}) => { - const { indexDataResp, indexPatternResp } = indexResponses; - - const indexCreationFailed = !(indexDataResp && indexDataResp.success); - const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount; - const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success); - - if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) { - importErrorHandler(indexResponses); - return; - } - const { fields, id: indexPatternId } = indexPatternResp; - const geoField = fields.find(field => Object.values(ES_GEO_FIELD_TYPE).includes(field.type)); - if (!indexPatternId || !geoField) { - addAndViewSource(null); - } else { - const source = new ESSearchSource( - { - id: uuid(), - indexPatternId, - geoField: geoField.name, - // Only turn on bounds filter for large doc counts - filterByMapBounds: indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW, - scalingType: - geoField.type === ES_GEO_FIELD_TYPE.GEO_POINT - ? SCALING_TYPES.CLUSTERS - : SCALING_TYPES.LIMIT, - }, - inspectorAdapters - ); - addAndViewSource(source); - importSuccessHandler(indexResponses); - } - }; -}; - -const previewGeojsonFile = (onPreviewSource, inspectorAdapters) => { - return (geojsonFile, name) => { - if (!geojsonFile) { - onPreviewSource(null); - return; - } - const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name); - const source = new GeojsonFileSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; -}; - registerSource({ ConstructorFunction: GeojsonFileSource, type: SOURCE_TYPES.GEOJSON_FILE, }); - -export const uploadLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.geojsonFileDescription', { - defaultMessage: 'Index GeoJSON data in Elasticsearch', - }), - icon: 'importAction', - isIndexingSource: true, - renderWizard: ({ - onPreviewSource, - inspectorAdapters, - addAndViewSource, - isIndexingTriggered, - onRemove, - onIndexReady, - importSuccessHandler, - importErrorHandler, - }) => { - return ( - - ); - }, - title: i18n.translate('xpack.maps.source.geojsonFileTitle', { - defaultMessage: 'Upload GeoJSON', - }), -}; diff --git a/x-pack/plugins/maps/public/layers/sources/client_file_source/index.js b/x-pack/plugins/maps/public/layers/sources/client_file_source/index.js index a6a31def4b231..5c2a0afd31885 100644 --- a/x-pack/plugins/maps/public/layers/sources/client_file_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/client_file_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { GeojsonFileSource, uploadLayerWizardConfig } from './geojson_file_source'; +export { GeojsonFileSource } from './geojson_file_source'; +export { uploadLayerWizardConfig } from './upload_layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/sources/client_file_source/upload_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/client_file_source/upload_layer_wizard.tsx new file mode 100644 index 0000000000000..2f8aa67d74b52 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/client_file_source/upload_layer_wizard.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { IFieldType } from 'src/plugins/data/public'; +import { + ES_GEO_FIELD_TYPE, + DEFAULT_MAX_RESULT_WINDOW, + SCALING_TYPES, +} from '../../../../common/constants'; +// @ts-ignore +import { ESSearchSource, createDefaultLayerDescriptor } from '../es_search_source'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { ClientFileCreateSourceEditor } from './create_client_file_source_editor'; +// @ts-ignore +import { GeojsonFileSource } from './geojson_file_source'; +import { VectorLayer } from '../../vector_layer'; + +export const uploadLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.geojsonFileDescription', { + defaultMessage: 'Index GeoJSON data in Elasticsearch', + }), + icon: 'importAction', + isIndexingSource: true, + renderWizard: ({ + previewLayer, + mapColors, + isIndexingTriggered, + onRemove, + onIndexReady, + importSuccessHandler, + importErrorHandler, + }: RenderWizardArguments) => { + function previewGeojsonFile(geojsonFile: unknown, name: string) { + if (!geojsonFile) { + previewLayer(null); + return; + } + const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name); + const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors); + // TODO figure out a better way to handle passing this information back to layer_addpanel + previewLayer(layerDescriptor, true); + } + + function viewIndexedData(indexResponses: { + indexDataResp: unknown; + indexPatternResp: unknown; + }) { + const { indexDataResp, indexPatternResp } = indexResponses; + + // @ts-ignore + const indexCreationFailed = !(indexDataResp && indexDataResp.success); + // @ts-ignore + const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount; + // @ts-ignore + const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success); + + if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) { + importErrorHandler(indexResponses); + return; + } + // @ts-ignore + const { fields, id: indexPatternId } = indexPatternResp; + const geoField = fields.find((field: IFieldType) => + [ES_GEO_FIELD_TYPE.GEO_POINT as string, ES_GEO_FIELD_TYPE.GEO_SHAPE as string].includes( + field.type + ) + ); + if (!indexPatternId || !geoField) { + previewLayer(null); + } else { + const esSearchSourceConfig = { + indexPatternId, + geoField: geoField.name, + // Only turn on bounds filter for large doc counts + // @ts-ignore + filterByMapBounds: indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW, + scalingType: + geoField.type === ES_GEO_FIELD_TYPE.GEO_POINT + ? SCALING_TYPES.CLUSTERS + : SCALING_TYPES.LIMIT, + }; + previewLayer(createDefaultLayerDescriptor(esSearchSourceConfig, mapColors)); + importSuccessHandler(indexResponses); + } + } + + return ( + + ); + }, + title: i18n.translate('xpack.maps.source.geojsonFileTitle', { + defaultMessage: 'Upload GeoJSON', + }), +}; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx new file mode 100644 index 0000000000000..f31e770df2d95 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_boundaries_layer_wizard.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { VectorLayer } from '../../vector_layer'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { EMSFileCreateSourceEditor } from './create_source_editor'; +// @ts-ignore +import { EMSFileSource, sourceTitle } from './ems_file_source'; + +export const emsBoundariesLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.emsFileDescription', { + defaultMessage: 'Administrative boundaries from Elastic Maps Service', + }), + icon: 'emsApp', + renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + // @ts-ignore + const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig); + const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors); + previewLayer(layerDescriptor); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js index e8af17b911939..5802a223e4846 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js @@ -9,14 +9,13 @@ import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; import React from 'react'; import { SOURCE_TYPES, FIELD_ORIGIN } from '../../../../common/constants'; import { getEMSClient } from '../../../meta'; -import { EMSFileCreateSourceEditor } from './create_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { UpdateSourceEditor } from './update_source_editor'; import { EMSFileField } from '../../fields/ems_file_field'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', { defaultMessage: 'EMS Boundaries', }); @@ -161,19 +160,3 @@ registerSource({ ConstructorFunction: EMSFileSource, type: SOURCE_TYPES.EMS_FILE, }); - -export const emsBoundariesLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.emsFileDescription', { - defaultMessage: 'Administrative boundaries from Elastic Maps Service', - }), - icon: 'emsApp', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig); - const source = new EMSFileSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_file_source/index.js b/x-pack/plugins/maps/public/layers/sources/ems_file_source/index.js index 28fbc04a1a032..e9bf592c6d2b7 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_file_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_file_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EMSFileSource, emsBoundariesLayerWizardConfig } from './ems_file_source'; +export { emsBoundariesLayerWizardConfig } from './ems_boundaries_layer_wizard'; +export { EMSFileSource } from './ems_file_source'; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx new file mode 100644 index 0000000000000..ced33a0bcf84a --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_base_map_layer_wizard.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { EMSTMSSource, sourceTitle } from './ems_tms_source'; +// @ts-ignore +import { VectorTileLayer } from '../../vector_tile_layer'; +// @ts-ignore +import { TileServiceSelect } from './tile_service_select'; + +export const emsBaseMapLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.emsTileDescription', { + defaultMessage: 'Tile map service from Elastic Maps Service', + }), + icon: 'emsApp', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + const layerDescriptor = VectorTileLayer.createDescriptor({ + sourceDescriptor: EMSTMSSource.createDescriptor(sourceConfig), + }); + previewLayer(layerDescriptor); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js index 79121c4cdb31f..3bed9b2c09570 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js @@ -7,10 +7,8 @@ import _ from 'lodash'; import React from 'react'; import { AbstractTMSSource } from '../tms_source'; -import { VectorTileLayer } from '../../vector_tile_layer'; import { getEMSClient } from '../../../meta'; -import { TileServiceSelect } from './tile_service_select'; import { UpdateSourceEditor } from './update_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; @@ -18,7 +16,7 @@ import { SOURCE_TYPES } from '../../../../common/constants'; import { getInjectedVarFunc, getUiSettings } from '../../../kibana_services'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.emsTileTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.emsTileTitle', { defaultMessage: 'EMS Basemaps', }); @@ -84,20 +82,6 @@ export class EMSTMSSource extends AbstractTMSSource { return tmsService; } - _createDefaultLayerDescriptor(options) { - return VectorTileLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - } - - createDefaultLayer(options) { - return new VectorTileLayer({ - layerDescriptor: this._createDefaultLayerDescriptor(options), - source: this, - }); - } - async getDisplayName() { try { const emsTMSService = await this._getEMSTMSService(); @@ -150,20 +134,3 @@ registerSource({ ConstructorFunction: EMSTMSSource, type: SOURCE_TYPES.EMS_TMS, }); - -export const emsBaseMapLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.emsTileDescription', { - defaultMessage: 'Tile map service from Elastic Maps Service', - }), - icon: 'emsApp', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - const descriptor = EMSTMSSource.createDescriptor(sourceConfig); - const source = new EMSTMSSource(descriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/index.js b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/index.js index 60a4c9b1de891..704bcfd370a85 100644 --- a/x-pack/plugins/maps/public/layers/sources/ems_tms_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/ems_tms_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EMSTMSSource, emsBaseMapLayerWizardConfig } from './ems_tms_source'; +export { emsBaseMapLayerWizardConfig } from './ems_base_map_layer_wizard'; +export { EMSTMSSource } from './ems_tms_source'; diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/clusters_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/clusters_layer_wizard.tsx new file mode 100644 index 0000000000000..f9092e64833f1 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/clusters_layer_wizard.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; +// @ts-ignore +import { ESGeoGridSource, clustersTitle } from './es_geo_grid_source'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { VectorLayer } from '../../vector_layer'; +import { + ESGeoGridSourceDescriptor, + ColorDynamicOptions, + SizeDynamicOptions, +} from '../../../../common/descriptor_types'; +import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; +import { VectorStyle } from '../../styles/vector/vector_style'; +import { + COUNT_PROP_NAME, + COLOR_MAP_TYPE, + FIELD_ORIGIN, + RENDER_AS, + VECTOR_STYLES, + STYLE_TYPE, +} from '../../../../common/constants'; +// @ts-ignore +import { COLOR_GRADIENTS } from '../../styles/color_utils'; + +export const clustersLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.esGridClustersDescription', { + defaultMessage: 'Geospatial data grouped in grids with metrics for each gridded cell', + }), + icon: 'logoElasticsearch', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: Partial) => { + if (!sourceConfig) { + previewLayer(null); + return; + } + + const defaultDynamicProperties = getDefaultDynamicProperties(); + const layerDescriptor = VectorLayer.createDescriptor({ + sourceDescriptor: ESGeoGridSource.createDescriptor(sourceConfig), + style: VectorStyle.createDescriptor({ + // @ts-ignore + [VECTOR_STYLES.FILL_COLOR]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.FILL_COLOR]! + .options as ColorDynamicOptions), + field: { + name: COUNT_PROP_NAME, + origin: FIELD_ORIGIN.SOURCE, + }, + color: COLOR_GRADIENTS[0].value, + type: COLOR_MAP_TYPE.ORDINAL, + }, + }, + [VECTOR_STYLES.LINE_COLOR]: { + type: STYLE_TYPE.STATIC, + options: { + color: '#FFF', + }, + }, + [VECTOR_STYLES.LINE_WIDTH]: { + type: STYLE_TYPE.STATIC, + options: { + size: 0, + }, + }, + [VECTOR_STYLES.ICON_SIZE]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.ICON_SIZE]!.options as SizeDynamicOptions), + field: { + name: COUNT_PROP_NAME, + origin: FIELD_ORIGIN.SOURCE, + }, + }, + }, + [VECTOR_STYLES.LABEL_TEXT]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...defaultDynamicProperties[VECTOR_STYLES.LABEL_TEXT]!.options, + field: { + name: COUNT_PROP_NAME, + origin: FIELD_ORIGIN.SOURCE, + }, + }, + }, + }), + }); + previewLayer(layerDescriptor); + }; + + return ( + + ); + }, + title: clustersTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index b9ef13e520bf8..17fad2f2e6453 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -8,39 +8,27 @@ import React from 'react'; import uuid from 'uuid/v4'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; -import { HeatmapLayer } from '../../heatmap_layer'; -import { VectorLayer } from '../../vector_layer'; import { convertCompositeRespToGeoJson, convertRegularRespToGeoJson } from './convert_to_geojson'; -import { VectorStyle } from '../../styles/vector/vector_style'; -import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; -import { COLOR_GRADIENTS } from '../../styles/color_utils'; -import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { SOURCE_TYPES, DEFAULT_MAX_BUCKETS_LIMIT, - COUNT_PROP_NAME, - COLOR_MAP_TYPE, RENDER_AS, GRID_RESOLUTION, - VECTOR_STYLES, - FIELD_ORIGIN, } from '../../../../common/constants'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { AbstractESAggSource } from '../es_agg_source'; -import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; -import { StaticStyleProperty } from '../../styles/vector/properties/static_style_property'; import { DataRequestAbortError } from '../../util/data_request'; import { registerSource } from '../source_registry'; export const MAX_GEOTILE_LEVEL = 29; -const clustersTitle = i18n.translate('xpack.maps.source.esGridClustersTitle', { +export const clustersTitle = i18n.translate('xpack.maps.source.esGridClustersTitle', { defaultMessage: 'Clusters and grids', }); -const heatmapTitle = i18n.translate('xpack.maps.source.esGridHeatmapTitle', { +export const heatmapTitle = i18n.translate('xpack.maps.source.esGridHeatmapTitle', { defaultMessage: 'Heat map', }); @@ -320,87 +308,6 @@ export class ESGeoGridSource extends AbstractESAggSource { return true; } - _createHeatmapLayerDescriptor(options) { - return HeatmapLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - } - - _createVectorLayerDescriptor(options) { - const descriptor = VectorLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - - const defaultDynamicProperties = getDefaultDynamicProperties(); - - descriptor.style = VectorStyle.createDescriptor({ - [VECTOR_STYLES.FILL_COLOR]: { - type: DynamicStyleProperty.type, - options: { - ...defaultDynamicProperties[VECTOR_STYLES.FILL_COLOR].options, - field: { - name: COUNT_PROP_NAME, - origin: FIELD_ORIGIN.SOURCE, - }, - color: COLOR_GRADIENTS[0].value, - type: COLOR_MAP_TYPE.ORDINAL, - }, - }, - [VECTOR_STYLES.LINE_COLOR]: { - type: StaticStyleProperty.type, - options: { - color: '#FFF', - }, - }, - [VECTOR_STYLES.LINE_WIDTH]: { - type: StaticStyleProperty.type, - options: { - size: 0, - }, - }, - [VECTOR_STYLES.ICON_SIZE]: { - type: DynamicStyleProperty.type, - options: { - ...defaultDynamicProperties[VECTOR_STYLES.ICON_SIZE].options, - field: { - name: COUNT_PROP_NAME, - origin: FIELD_ORIGIN.SOURCE, - }, - }, - }, - [VECTOR_STYLES.LABEL_TEXT]: { - type: DynamicStyleProperty.type, - options: { - ...defaultDynamicProperties[VECTOR_STYLES.LABEL_TEXT].options, - field: { - name: COUNT_PROP_NAME, - origin: FIELD_ORIGIN.SOURCE, - }, - }, - }, - }); - return descriptor; - } - - createDefaultLayer(options) { - if (this._descriptor.requestType === RENDER_AS.HEATMAP) { - return new HeatmapLayer({ - layerDescriptor: this._createHeatmapLayerDescriptor(options), - source: this, - }); - } - - const layerDescriptor = this._createVectorLayerDescriptor(options); - const style = new VectorStyle(layerDescriptor.style, this); - return new VectorLayer({ - layerDescriptor, - source: this, - style, - }); - } - canFormatFeatureProperties() { return true; } @@ -422,57 +329,3 @@ registerSource({ ConstructorFunction: ESGeoGridSource, type: SOURCE_TYPES.ES_GEO_GRID, }); - -export const clustersLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.esGridClustersDescription', { - defaultMessage: 'Geospatial data grouped in grids with metrics for each gridded cell', - }), - icon: 'logoElasticsearch', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig); - const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ( - - ); - }, - title: clustersTitle, -}; - -export const heatmapLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.esGridHeatmapDescription', { - defaultMessage: 'Geospatial data grouped in grids to show density', - }), - icon: 'logoElasticsearch', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig); - const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ( - - ); - }, - title: heatmapTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/heatmap_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/heatmap_layer_wizard.tsx new file mode 100644 index 0000000000000..fee1a81a5c63a --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/heatmap_layer_wizard.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; +// @ts-ignore +import { ESGeoGridSource, heatmapTitle } from './es_geo_grid_source'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { HeatmapLayer } from '../../heatmap_layer'; +import { ESGeoGridSourceDescriptor } from '../../../../common/descriptor_types'; +import { RENDER_AS } from '../../../../common/constants'; + +export const heatmapLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.esGridHeatmapDescription', { + defaultMessage: 'Geospatial data grouped in grids to show density', + }), + icon: 'logoElasticsearch', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: Partial) => { + if (!sourceConfig) { + previewLayer(null); + return; + } + + const layerDescriptor = HeatmapLayer.createDescriptor({ + sourceDescriptor: ESGeoGridSource.createDescriptor(sourceConfig), + }); + previewLayer(layerDescriptor); + }; + + return ( + + ); + }, + title: heatmapTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/index.js b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/index.js index c2fa2356b1a3e..2db66ff411627 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/index.js @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export { - ESGeoGridSource, - clustersLayerWizardConfig, - heatmapLayerWizardConfig, -} from './es_geo_grid_source'; +export { clustersLayerWizardConfig } from './clusters_layer_wizard'; +export { ESGeoGridSource } from './es_geo_grid_source'; +export { heatmapLayerWizardConfig } from './heatmap_layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index 57e5afb99404b..0d15cff032410 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -8,29 +8,18 @@ import React from 'react'; import uuid from 'uuid/v4'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; -import { VectorLayer } from '../../vector_layer'; -import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; -import { VectorStyle } from '../../styles/vector/vector_style'; -import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; import { i18n } from '@kbn/i18n'; -import { - FIELD_ORIGIN, - SOURCE_TYPES, - COUNT_PROP_NAME, - VECTOR_STYLES, -} from '../../../../common/constants'; +import { SOURCE_TYPES } from '../../../../common/constants'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { convertToLines } from './convert_to_lines'; import { AbstractESAggSource } from '../es_agg_source'; -import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; -import { COLOR_GRADIENTS } from '../../styles/color_utils'; import { indexPatterns } from '../../../../../../../src/plugins/data/public'; import { registerSource } from '../source_registry'; const MAX_GEOTILE_LEVEL = 29; -const sourceTitle = i18n.translate('xpack.maps.source.pewPewTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.pewPewTitle', { defaultMessage: 'Point to point', }); @@ -109,43 +98,6 @@ export class ESPewPewSource extends AbstractESAggSource { ]; } - createDefaultLayer(options) { - const defaultDynamicProperties = getDefaultDynamicProperties(); - const styleDescriptor = VectorStyle.createDescriptor({ - [VECTOR_STYLES.LINE_COLOR]: { - type: DynamicStyleProperty.type, - options: { - ...defaultDynamicProperties[VECTOR_STYLES.LINE_COLOR].options, - field: { - name: COUNT_PROP_NAME, - origin: FIELD_ORIGIN.SOURCE, - }, - color: COLOR_GRADIENTS[0].value, - }, - }, - [VECTOR_STYLES.LINE_WIDTH]: { - type: DynamicStyleProperty.type, - options: { - ...defaultDynamicProperties[VECTOR_STYLES.LINE_WIDTH].options, - field: { - name: COUNT_PROP_NAME, - origin: FIELD_ORIGIN.SOURCE, - }, - }, - }, - }); - - return new VectorLayer({ - layerDescriptor: VectorLayer.createDescriptor({ - ...options, - sourceDescriptor: this._descriptor, - style: styleDescriptor, - }), - source: this, - style: new VectorStyle(styleDescriptor, this), - }); - } - getGeoGridPrecision(zoom) { const targetGeotileLevel = Math.ceil(zoom) + 2; return Math.min(targetGeotileLevel, MAX_GEOTILE_LEVEL); @@ -234,25 +186,3 @@ registerSource({ ConstructorFunction: ESPewPewSource, type: SOURCE_TYPES.ES_PEW_PEW, }); - -export const point2PointLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.pewPewDescription', { - defaultMessage: 'Aggregated data paths between the source and destination', - }), - icon: 'logoElasticsearch', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = ESPewPewSource.createDescriptor(sourceConfig); - const source = new ESPewPewSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/index.js b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/index.js new file mode 100644 index 0000000000000..fabde578085ab --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/index.js @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ESPewPewSource } from './es_pew_pew_source'; +export { point2PointLayerWizardConfig } from './point_2_point_layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx new file mode 100644 index 0000000000000..3ad6d64903d4a --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/es_pew_pew_source/point_2_point_layer_wizard.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; +import { VectorLayer } from '../../vector_layer'; +// @ts-ignore +import { ESPewPewSource, sourceTitle } from './es_pew_pew_source'; +import { VectorStyle } from '../../styles/vector/vector_style'; +import { + FIELD_ORIGIN, + COUNT_PROP_NAME, + VECTOR_STYLES, + STYLE_TYPE, +} from '../../../../common/constants'; +// @ts-ignore +import { COLOR_GRADIENTS } from '../../styles/color_utils'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { ColorDynamicOptions, SizeDynamicOptions } from '../../../../common/descriptor_types'; + +export const point2PointLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.pewPewDescription', { + defaultMessage: 'Aggregated data paths between the source and destination', + }), + icon: 'logoElasticsearch', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + if (!sourceConfig) { + previewLayer(null); + return; + } + + const defaultDynamicProperties = getDefaultDynamicProperties(); + const layerDescriptor = VectorLayer.createDescriptor({ + sourceDescriptor: ESPewPewSource.createDescriptor(sourceConfig), + style: VectorStyle.createDescriptor({ + [VECTOR_STYLES.LINE_COLOR]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.LINE_COLOR]! + .options as ColorDynamicOptions), + field: { + name: COUNT_PROP_NAME, + origin: FIELD_ORIGIN.SOURCE, + }, + color: COLOR_GRADIENTS[0].value, + }, + }, + [VECTOR_STYLES.LINE_WIDTH]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.LINE_WIDTH]! + .options as SizeDynamicOptions), + field: { + name: COUNT_PROP_NAME, + origin: FIELD_ORIGIN.SOURCE, + }, + }, + }, + }), + }); + previewLayer(layerDescriptor); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_documents_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_documents_layer_wizard.tsx new file mode 100644 index 0000000000000..4a775dd78f787 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_documents_layer_wizard.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { ESSearchSource, sourceTitle } from './es_search_source'; +import { BlendedVectorLayer } from '../../blended_vector_layer'; +import { VectorLayer } from '../../vector_layer'; +import { SCALING_TYPES } from '../../../../common/constants'; + +export function createDefaultLayerDescriptor(sourceConfig: unknown, mapColors: string[]) { + const sourceDescriptor = ESSearchSource.createDescriptor(sourceConfig); + + return sourceDescriptor.scalingType === SCALING_TYPES.CLUSTERS + ? BlendedVectorLayer.createDescriptor({ sourceDescriptor }, mapColors) + : VectorLayer.createDescriptor({ sourceDescriptor }, mapColors); +} + +export const esDocumentsLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.esSearchDescription', { + defaultMessage: 'Vector data from a Kibana index pattern', + }), + icon: 'logoElasticsearch', + renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + if (!sourceConfig) { + previewLayer(null); + return; + } + + previewLayer(createDefaultLayerDescriptor(sourceConfig, mapColors)); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts index c904280a38c85..23e3c759d73c3 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts @@ -8,6 +8,8 @@ import { AbstractESSource } from '../es_source'; import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types'; export class ESSearchSource extends AbstractESSource { + static createDescriptor(sourceConfig: unknown): ESSearchSourceDescriptor; + constructor(sourceDescriptor: Partial, inspectorAdapters: unknown); getFieldNames(): string[]; } diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index bfbcca1eb3f61..a412c49faceac 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -6,15 +6,11 @@ import _ from 'lodash'; import React from 'react'; -import uuid from 'uuid/v4'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; import { AbstractESSource } from '../es_source'; import { getSearchService } from '../../../kibana_services'; -import { VectorStyle } from '../../styles/vector/vector_style'; -import { VectorLayer } from '../../vector_layer'; import { hitsToGeoJson } from '../../../elasticsearch_geo_utils'; -import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { SOURCE_TYPES, @@ -27,14 +23,14 @@ import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { getSourceFields } from '../../../index_pattern_util'; import { loadIndexSettings } from './load_index_settings'; -import { BlendedVectorLayer } from '../../blended_vector_layer'; +import uuid from 'uuid/v4'; import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants'; import { ESDocField } from '../../fields/es_doc_field'; import { getField, addFieldToDSL } from '../../util/es_agg_utils'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.esSearchTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.esSearchTitle', { defaultMessage: 'Documents', }); @@ -71,56 +67,31 @@ function getDocValueAndSourceFields(indexPattern, fieldNames) { export class ESSearchSource extends AbstractESSource { static type = SOURCE_TYPES.ES_SEARCH; + static createDescriptor(descriptor) { + return { + ...descriptor, + id: descriptor.id ? descriptor.id : uuid(), + type: ESSearchSource.type, + indexPatternId: descriptor.indexPatternId, + geoField: descriptor.geoField, + filterByMapBounds: _.get(descriptor, 'filterByMapBounds', DEFAULT_FILTER_BY_MAP_BOUNDS), + tooltipProperties: _.get(descriptor, 'tooltipProperties', []), + sortField: _.get(descriptor, 'sortField', ''), + sortOrder: _.get(descriptor, 'sortOrder', SORT_ORDER.DESC), + scalingType: _.get(descriptor, 'scalingType', SCALING_TYPES.LIMIT), + topHitsSplitField: descriptor.topHitsSplitField, + topHitsSize: _.get(descriptor, 'topHitsSize', 1), + }; + } + constructor(descriptor, inspectorAdapters) { - super( - { - ...descriptor, - id: descriptor.id, - type: ESSearchSource.type, - indexPatternId: descriptor.indexPatternId, - geoField: descriptor.geoField, - filterByMapBounds: _.get(descriptor, 'filterByMapBounds', DEFAULT_FILTER_BY_MAP_BOUNDS), - tooltipProperties: _.get(descriptor, 'tooltipProperties', []), - sortField: _.get(descriptor, 'sortField', ''), - sortOrder: _.get(descriptor, 'sortOrder', SORT_ORDER.DESC), - scalingType: _.get(descriptor, 'scalingType', SCALING_TYPES.LIMIT), - topHitsSplitField: descriptor.topHitsSplitField, - topHitsSize: _.get(descriptor, 'topHitsSize', 1), - }, - inspectorAdapters - ); + super(ESSearchSource.createDescriptor(descriptor), inspectorAdapters); this._tooltipFields = this._descriptor.tooltipProperties.map(property => this.createField({ fieldName: property }) ); } - createDefaultLayer(options, mapColors) { - if (this._descriptor.scalingType === SCALING_TYPES.CLUSTERS) { - const layerDescriptor = BlendedVectorLayer.createDescriptor( - { - sourceDescriptor: this._descriptor, - ...options, - }, - mapColors - ); - const style = new VectorStyle(layerDescriptor.style, this); - return new BlendedVectorLayer({ - layerDescriptor: layerDescriptor, - source: this, - style, - }); - } - - const layerDescriptor = this._createDefaultLayerDescriptor(options, mapColors); - const style = new VectorStyle(layerDescriptor.style, this); - return new VectorLayer({ - layerDescriptor: layerDescriptor, - source: this, - style, - }); - } - createField({ fieldName }) { return new ESDocField({ fieldName, @@ -586,29 +557,3 @@ registerSource({ ConstructorFunction: ESSearchSource, type: SOURCE_TYPES.ES_SEARCH, }); - -export const esDocumentsLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.esSearchDescription', { - defaultMessage: 'Vector data from a Kibana index pattern', - }), - icon: 'logoElasticsearch', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const source = new ESSearchSource( - { - id: uuid(), - ...sourceConfig, - }, - inspectorAdapters - ); - onPreviewSource(source); - }; - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts deleted file mode 100644 index 66cc2ddd85404..0000000000000 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -jest.mock('ui/new_platform'); -jest.mock('../../../kibana_services'); - -import { ESSearchSource } from './es_search_source'; -import { VectorLayer } from '../../vector_layer'; -import { SCALING_TYPES, SOURCE_TYPES } from '../../../../common/constants'; -import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types'; - -const descriptor: ESSearchSourceDescriptor = { - type: SOURCE_TYPES.ES_SEARCH, - id: '1234', - indexPatternId: 'myIndexPattern', - geoField: 'myLocation', - scalingType: SCALING_TYPES.LIMIT, -}; - -describe('ES Search Source', () => { - beforeEach(() => { - require('../../../kibana_services').getUiSettings = () => ({ - get: jest.fn(), - }); - }); - it('should create a vector layer', () => { - const source = new ESSearchSource(descriptor, null); - const layer = source.createDefaultLayer(); - expect(layer instanceof VectorLayer).toEqual(true); - }); -}); diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/index.js b/x-pack/plugins/maps/public/layers/sources/es_search_source/index.js index 2c401ac92567e..6ae327a18b7c2 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/index.js @@ -4,4 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ESSearchSource, esDocumentsLayerWizardConfig } from './es_search_source'; +export { ESSearchSource } from './es_search_source'; +export { + createDefaultLayerDescriptor, + esDocumentsLayerWizardConfig, +} from './es_documents_layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js index ccd8bc4a859db..87733e347aa2a 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js @@ -18,7 +18,6 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { copyPersistentState } from '../../../reducers/util'; -import { ES_GEO_FIELD_TYPE } from '../../../../common/constants'; import { DataRequestAbortError } from '../../util/data_request'; import { expandToTileBoundaries } from '../es_geo_grid_source/geo_tile_utils'; @@ -176,9 +175,11 @@ export class AbstractESSource extends AbstractVectorSource { }; } + const minLon = esBounds.top_left.lon; + const maxLon = esBounds.bottom_right.lon; return { - minLon: esBounds.top_left.lon, - maxLon: esBounds.bottom_right.lon, + minLon: minLon > maxLon ? minLon - 360 : minLon, + maxLon, minLat: esBounds.bottom_right.lat, maxLat: esBounds.top_left.lat, }; @@ -223,9 +224,7 @@ export class AbstractESSource extends AbstractVectorSource { async supportsFitToBounds() { try { const geoField = await this._getGeoField(); - // geo_bounds aggregation only supports geo_point - // there is currently no backend support for getting bounding box of geo_shape field - return geoField.type !== ES_GEO_FIELD_TYPE.GEO_SHAPE; + return geoField.aggregatable; } catch (error) { return false; } diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js index 00c3bfc5f17c6..6e9d7ad1a613b 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { KibanaRegionmapSource, kibanaRegionMapLayerWizardConfig } from './kibana_regionmap_source'; +export { kibanaRegionMapLayerWizardConfig } from './kibana_regionmap_layer_wizard'; +export { KibanaRegionmapSource } from './kibana_regionmap_source'; diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx new file mode 100644 index 0000000000000..4321501760faf --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_layer_wizard.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { KibanaRegionmapSource, sourceTitle } from './kibana_regionmap_source'; +import { VectorLayer } from '../../vector_layer'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; + +export const kibanaRegionMapLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.kbnRegionMapDescription', { + defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml', + }), + icon: 'logoKibana', + renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + const sourceDescriptor = KibanaRegionmapSource.createDescriptor(sourceConfig); + const layerDescriptor = VectorLayer.createDescriptor({ sourceDescriptor }, mapColors); + previewLayer(layerDescriptor); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js index be333f8ee85a4..fb5a2e4f42f1d 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js @@ -5,8 +5,6 @@ */ import { AbstractVectorSource } from '../vector_source'; -import React from 'react'; -import { CreateSourceEditor } from './create_source_editor'; import { getKibanaRegionList } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; @@ -14,7 +12,7 @@ import { FIELD_ORIGIN, SOURCE_TYPES } from '../../../../common/constants'; import { KibanaRegionField } from '../../fields/kibana_region_field'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.kbnRegionMapTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.kbnRegionMapTitle', { defaultMessage: 'Configured GeoJSON', }); @@ -101,20 +99,3 @@ registerSource({ ConstructorFunction: KibanaRegionmapSource, type: SOURCE_TYPES.REGIONMAP_FILE, }); - -export const kibanaRegionMapLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.kbnRegionMapDescription', { - defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml', - }), - icon: 'logoKibana', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - const sourceDescriptor = KibanaRegionmapSource.createDescriptor(sourceConfig); - const source = new KibanaRegionmapSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js index 9fd7f088032ca..cc89091605456 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { KibanaTilemapSource, kibanaBasemapLayerWizardConfig } from './kibana_tilemap_source'; +export { kibanaBasemapLayerWizardConfig } from './kibana_base_map_layer_wizard'; +export { KibanaTilemapSource } from './kibana_tilemap_source'; diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx new file mode 100644 index 0000000000000..aeea2d6084f84 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +// @ts-ignore +import { CreateSourceEditor } from './create_source_editor'; +// @ts-ignore +import { KibanaTilemapSource, sourceTitle } from './kibana_tilemap_source'; +import { TileLayer } from '../../tile_layer'; + +export const kibanaBasemapLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.kbnTMSDescription', { + defaultMessage: 'Tile map service configured in kibana.yml', + }), + icon: 'logoKibana', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = () => { + const layerDescriptor = TileLayer.createDescriptor({ + sourceDescriptor: KibanaTilemapSource.createDescriptor(), + }); + previewLayer(layerDescriptor); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js index bbb653eff32e2..7dc1d454a1c52 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js @@ -3,10 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; + import { AbstractTMSSource } from '../tms_source'; -import { TileLayer } from '../../tile_layer'; -import { CreateSourceEditor } from './create_source_editor'; import { getKibanaTileMap } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; @@ -14,7 +12,7 @@ import _ from 'lodash'; import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.kbnTMSTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.kbnTMSTitle', { defaultMessage: 'Configured Tile Map Service', }); @@ -42,20 +40,6 @@ export class KibanaTilemapSource extends AbstractTMSSource { ]; } - _createDefaultLayerDescriptor(options) { - return TileLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - } - - createDefaultLayer(options) { - return new TileLayer({ - layerDescriptor: this._createDefaultLayerDescriptor(options), - source: this, - }); - } - async getUrlTemplate() { const tilemap = getKibanaTileMap(); if (!tilemap.url) { @@ -88,19 +72,3 @@ registerSource({ ConstructorFunction: KibanaTilemapSource, type: SOURCE_TYPES.KIBANA_TILEMAP, }); - -export const kibanaBasemapLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.kbnTMSDescription', { - defaultMessage: 'Tile map service configured in kibana.yml', - }), - icon: 'logoKibana', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = () => { - const sourceDescriptor = KibanaTilemapSource.createDescriptor(); - const source = new KibanaTilemapSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx index dfdea1489d50c..c94fec3deac67 100644 --- a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx @@ -12,30 +12,20 @@ import { } from './mvt_single_layer_vector_source_editor'; import { MVTSingleLayerVectorSource, sourceTitle } from './mvt_single_layer_vector_source'; import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; -import { SOURCE_TYPES } from '../../../../common/constants'; +import { TiledVectorLayer } from '../../tiled_vector_layer'; export const mvtVectorSourceWizardConfig: LayerWizard = { description: i18n.translate('xpack.maps.source.mvtVectorSourceWizard', { defaultMessage: 'Vector source wizard', }), icon: 'grid', - renderWizard: ({ onPreviewSource, inspectorAdapters }: RenderWizardArguments) => { - const onSourceConfigChange = ({ - urlTemplate, - layerName, - minSourceZoom, - maxSourceZoom, - }: MVTSingleLayerVectorSourceConfig) => { - const sourceDescriptor = MVTSingleLayerVectorSource.createDescriptor({ - urlTemplate, - layerName, - minSourceZoom, - maxSourceZoom, - type: SOURCE_TYPES.MVT_SINGLE_LAYER, - }); - const source = new MVTSingleLayerVectorSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); + renderWizard: ({ previewLayer, mapColors }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: MVTSingleLayerVectorSourceConfig) => { + const sourceDescriptor = MVTSingleLayerVectorSource.createDescriptor(sourceConfig); + const layerDescriptor = TiledVectorLayer.createDescriptor({ sourceDescriptor }, mapColors); + previewLayer(layerDescriptor); }; + return ; }, title: sourceTitle, diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts index a73cfbdc0d043..58e6e39aaa1f9 100644 --- a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts @@ -7,7 +7,6 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { AbstractSource, ImmutableSourceProperty } from '../source'; -import { TiledVectorLayer } from '../../tiled_vector_layer'; import { GeoJsonWithMeta, ITiledSingleLayerVectorSource } from '../vector_source'; import { MAX_ZOOM, MIN_ZOOM, SOURCE_TYPES } from '../../../../common/constants'; import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; @@ -17,11 +16,10 @@ import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters import { MapExtent, TiledSingleLayerVectorSourceDescriptor, - VectorLayerDescriptor, VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; -import { VectorLayerArguments } from '../../vector_layer'; +import { MVTSingleLayerVectorSourceConfig } from './mvt_single_layer_vector_source_editor'; export const sourceTitle = i18n.translate( 'xpack.maps.source.MVTSingleLayerVectorSource.sourceTitle', @@ -37,7 +35,7 @@ export class MVTSingleLayerVectorSource extends AbstractSource layerName, minSourceZoom, maxSourceZoom, - }: TiledSingleLayerVectorSourceDescriptor) { + }: MVTSingleLayerVectorSourceConfig) { return { type: SOURCE_TYPES.MVT_SINGLE_LAYER, id: uuid(), @@ -66,22 +64,6 @@ export class MVTSingleLayerVectorSource extends AbstractSource return []; } - createDefaultLayer(options?: Partial): TiledVectorLayer { - const layerDescriptor: Partial = { - sourceDescriptor: this._descriptor, - ...options, - }; - const normalizedLayerDescriptor: VectorLayerDescriptor = TiledVectorLayer.createDescriptor( - layerDescriptor, - [] - ); - const vectorLayerArguments: VectorLayerArguments = { - layerDescriptor: normalizedLayerDescriptor, - source: this, - }; - return new TiledVectorLayer(vectorLayerArguments); - } - getGeoJsonWithMeta( layerName: 'string', searchFilters: unknown[], diff --git a/x-pack/plugins/maps/public/layers/sources/source.ts b/x-pack/plugins/maps/public/layers/sources/source.ts index 1cd84010159ab..af934d7464f61 100644 --- a/x-pack/plugins/maps/public/layers/sources/source.ts +++ b/x-pack/plugins/maps/public/layers/sources/source.ts @@ -13,8 +13,7 @@ import { Adapters } from 'src/plugins/inspector/public'; // @ts-ignore import { copyPersistentState } from '../../reducers/util'; -import { LayerDescriptor, SourceDescriptor } from '../../../common/descriptor_types'; -import { ILayer } from '../layer'; +import { SourceDescriptor } from '../../../common/descriptor_types'; import { IField } from '../fields/field'; import { MAX_ZOOM, MIN_ZOOM } from '../../../common/constants'; @@ -37,7 +36,6 @@ export type PreIndexedShape = { export type FieldFormatter = (value: string | number | null | undefined | boolean) => string; export interface ISource { - createDefaultLayer(options?: Partial): ILayer; destroy(): void; getDisplayName(): Promise; getInspectorAdapters(): Adapters | undefined; @@ -59,7 +57,6 @@ export interface ISource { getIndexPatternIds(): string[]; getQueryableIndexPatternIds(): string[]; getGeoGridPrecision(zoom: number): number; - shouldBeIndexed(): boolean; getPreIndexedShape(): Promise; createFieldFormatter(field: IField): Promise; getValueSuggestions(field: IField, query: string): Promise; @@ -99,10 +96,6 @@ export class AbstractSource implements ISource { return this._inspectorAdapters; } - createDefaultLayer(options?: Partial): ILayer { - throw new Error(`Source#createDefaultLayer not implemented`); - } - async getDisplayName(): Promise { return ''; } @@ -155,10 +148,6 @@ export class AbstractSource implements ISource { return false; } - shouldBeIndexed(): boolean { - return false; - } - isESSource(): boolean { return false; } diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js index 509584cbc415a..12e1780d9cad5 100644 --- a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js +++ b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { VectorLayer } from '../../vector_layer'; import { TooltipProperty } from '../../tooltips/tooltip_property'; -import { VectorStyle } from '../../styles/vector/vector_style'; import { AbstractSource } from './../source'; import * as topojson from 'topojson-client'; import _ from 'lodash'; @@ -74,30 +72,10 @@ export class AbstractVectorSource extends AbstractSource { return this.createField({ fieldName: name }); } - _createDefaultLayerDescriptor(options, mapColors) { - return VectorLayer.createDescriptor( - { - sourceDescriptor: this._descriptor, - ...options, - }, - mapColors - ); - } - _getTooltipPropertyNames() { return this._tooltipFields.map(field => field.getName()); } - createDefaultLayer(options, mapColors) { - const layerDescriptor = this._createDefaultLayerDescriptor(options, mapColors); - const style = new VectorStyle(layerDescriptor.style, this); - return new VectorLayer({ - layerDescriptor: layerDescriptor, - source: this, - style, - }); - } - isFilterByMapBounds() { return false; } diff --git a/x-pack/plugins/maps/public/layers/sources/wms_source/index.js b/x-pack/plugins/maps/public/layers/sources/wms_source/index.js index daae552a6f772..792e7e862826c 100644 --- a/x-pack/plugins/maps/public/layers/sources/wms_source/index.js +++ b/x-pack/plugins/maps/public/layers/sources/wms_source/index.js @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { WMSSource, wmsLayerWizardConfig } from './wms_source'; +export { wmsLayerWizardConfig } from './wms_layer_wizard'; +export { WMSSource } from './wms_source'; diff --git a/x-pack/plugins/maps/public/layers/sources/wms_source/wms_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_layer_wizard.tsx new file mode 100644 index 0000000000000..fbf5e25c78b17 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_layer_wizard.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { WMSCreateSourceEditor } from './wms_create_source_editor'; +// @ts-ignore +import { sourceTitle, WMSSource } from './wms_source'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { TileLayer } from '../../tile_layer'; + +export const wmsLayerWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.wmsDescription', { + defaultMessage: 'Maps from OGC Standard WMS', + }), + icon: 'grid', + renderWizard: ({ previewLayer }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: unknown) => { + if (!sourceConfig) { + previewLayer(null); + return; + } + + const layerDescriptor = TileLayer.createDescriptor({ + sourceDescriptor: WMSSource.createDescriptor(sourceConfig), + }); + previewLayer(layerDescriptor); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js index 33f764784124e..cb8f9c34e2b57 100644 --- a/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js +++ b/x-pack/plugins/maps/public/layers/sources/wms_source/wms_source.js @@ -4,18 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; - import { AbstractTMSSource } from '../tms_source'; -import { TileLayer } from '../../tile_layer'; -import { WMSCreateSourceEditor } from './wms_create_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; import { WmsClient } from './wms_client'; import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; -const sourceTitle = i18n.translate('xpack.maps.source.wmsTitle', { +export const sourceTitle = i18n.translate('xpack.maps.source.wmsTitle', { defaultMessage: 'Web Map Service', }); @@ -52,20 +48,6 @@ export class WMSSource extends AbstractTMSSource { ]; } - _createDefaultLayerDescriptor(options) { - return TileLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - } - - createDefaultLayer(options) { - return new TileLayer({ - layerDescriptor: this._createDefaultLayerDescriptor(options), - source: this, - }); - } - async getDisplayName() { return this._descriptor.serviceUrl; } @@ -94,24 +76,3 @@ registerSource({ ConstructorFunction: WMSSource, type: SOURCE_TYPES.WMS, }); - -export const wmsLayerWizardConfig = { - description: i18n.translate('xpack.maps.source.wmsDescription', { - defaultMessage: 'Maps from OGC Standard WMS', - }), - icon: 'grid', - renderWizard: ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = WMSSource.createDescriptor(sourceConfig); - const source = new WMSSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - }, - title: sourceTitle, -}; diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx index 8b1ed588c8dd1..e970c75fa7adf 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/layer_wizard.tsx @@ -9,17 +9,19 @@ import React from 'react'; import { XYZTMSEditor, XYZTMSSourceConfig } from './xyz_tms_editor'; import { XYZTMSSource, sourceTitle } from './xyz_tms_source'; import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { TileLayer } from '../../tile_layer'; export const tmsLayerWizardConfig: LayerWizard = { description: i18n.translate('xpack.maps.source.ems_xyzDescription', { defaultMessage: 'Tile map service configured in interface', }), icon: 'grid', - renderWizard: ({ onPreviewSource }: RenderWizardArguments) => { + renderWizard: ({ previewLayer }: RenderWizardArguments) => { const onSourceConfigChange = (sourceConfig: XYZTMSSourceConfig) => { - const sourceDescriptor = XYZTMSSource.createDescriptor(sourceConfig); - const source = new XYZTMSSource(sourceDescriptor); - onPreviewSource(source); + const layerDescriptor = TileLayer.createDescriptor({ + sourceDescriptor: XYZTMSSource.createDescriptor(sourceConfig), + }); + previewLayer(layerDescriptor); }; return ; }, diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts index 4031a18bff7cb..b1ba6fc6f6f8e 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.test.ts @@ -5,8 +5,6 @@ */ import { XYZTMSSource } from './xyz_tms_source'; -import { ILayer } from '../../layer'; -import { TileLayer } from '../../tile_layer'; import { SOURCE_TYPES } from '../../../../common/constants'; import { XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; @@ -16,12 +14,6 @@ const descriptor: XYZTMSSourceDescriptor = { id: 'foobar', }; describe('xyz Tilemap Source', () => { - it('should create a tile-layer', () => { - const source = new XYZTMSSource(descriptor); - const layer: ILayer = source.createDefaultLayer(); - expect(layer instanceof TileLayer).toEqual(true); - }); - it('should echo url template for url template', async () => { const source = new XYZTMSSource(descriptor); const template = await source.getUrlTemplate(); diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts index 77f8d88a8c0ab..b1003d25fb759 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts @@ -5,15 +5,13 @@ */ import { i18n } from '@kbn/i18n'; -import { TileLayer } from '../../tile_layer'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; import { SOURCE_TYPES } from '../../../../common/constants'; import { registerSource } from '../source_registry'; import { AbstractTMSSource } from '../tms_source'; -import { LayerDescriptor, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; +import { XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; import { Attribution, ImmutableSourceProperty } from '../source'; import { XYZTMSSourceConfig } from './xyz_tms_editor'; -import { ILayer } from '../../layer'; export const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', { defaultMessage: 'Tile Map Service', @@ -49,17 +47,6 @@ export class XYZTMSSource extends AbstractTMSSource { ]; } - createDefaultLayer(options?: LayerDescriptor): ILayer { - const layerDescriptor: LayerDescriptor = TileLayer.createDescriptor({ - sourceDescriptor: this._descriptor, - ...options, - }); - return new TileLayer({ - layerDescriptor, - source: this, - }); - } - async getDisplayName(): Promise { return this._descriptor.urlTemplate; } diff --git a/x-pack/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/plugins/maps/public/layers/tile_layer.test.ts index a7e8be9fc4b46..d536b18af4aad 100644 --- a/x-pack/plugins/maps/public/layers/tile_layer.test.ts +++ b/x-pack/plugins/maps/public/layers/tile_layer.test.ts @@ -23,9 +23,6 @@ class MockTileSource extends AbstractTMSSource implements ITMSSource { super(descriptor, {}); this._descriptor = descriptor; } - createDefaultLayer(): ILayer { - throw new Error('not implemented'); - } async getDisplayName(): Promise { return this._descriptor.urlTemplate; diff --git a/x-pack/plugins/maps/public/layers/util/can_skip_fetch.test.js b/x-pack/plugins/maps/public/layers/util/can_skip_fetch.test.js index 2a4843c78635f..bf1f9de6b2d2b 100644 --- a/x-pack/plugins/maps/public/layers/util/can_skip_fetch.test.js +++ b/x-pack/plugins/maps/public/layers/util/can_skip_fetch.test.js @@ -8,101 +8,74 @@ import { canSkipSourceUpdate, updateDueToExtent } from './can_skip_fetch'; import { DataRequest } from './data_request'; describe('updateDueToExtent', () => { - it('should be false when the source is not extent aware', async () => { - const sourceMock = { - isFilterByMapBounds: () => { - return false; - }, + it('should be false when buffers are the same', async () => { + const oldBuffer = { + maxLat: 12.5, + maxLon: 102.5, + minLat: 2.5, + minLon: 92.5, }; - expect(updateDueToExtent(sourceMock)).toBe(false); + const newBuffer = { + maxLat: 12.5, + maxLon: 102.5, + minLat: 2.5, + minLon: 92.5, + }; + expect(updateDueToExtent({ buffer: oldBuffer }, { buffer: newBuffer })).toBe(false); }); - describe('source is extent aware', () => { - const sourceMock = { - isFilterByMapBounds: () => { - return true; - }, + it('should be false when the new buffer is contained in the old buffer', async () => { + const oldBuffer = { + maxLat: 12.5, + maxLon: 102.5, + minLat: 2.5, + minLon: 92.5, }; + const newBuffer = { + maxLat: 10, + maxLon: 100, + minLat: 5, + minLon: 95, + }; + expect(updateDueToExtent({ buffer: oldBuffer }, { buffer: newBuffer })).toBe(false); + }); - it('should be false when buffers are the same', async () => { - const oldBuffer = { - maxLat: 12.5, - maxLon: 102.5, - minLat: 2.5, - minLon: 92.5, - }; - const newBuffer = { - maxLat: 12.5, - maxLon: 102.5, - minLat: 2.5, - minLon: 92.5, - }; - expect(updateDueToExtent(sourceMock, { buffer: oldBuffer }, { buffer: newBuffer })).toBe( - false - ); - }); - - it('should be false when the new buffer is contained in the old buffer', async () => { - const oldBuffer = { - maxLat: 12.5, - maxLon: 102.5, - minLat: 2.5, - minLon: 92.5, - }; - const newBuffer = { - maxLat: 10, - maxLon: 100, - minLat: 5, - minLon: 95, - }; - expect(updateDueToExtent(sourceMock, { buffer: oldBuffer }, { buffer: newBuffer })).toBe( - false - ); - }); - - it('should be true when the new buffer is contained in the old buffer and the past results were truncated', async () => { - const oldBuffer = { - maxLat: 12.5, - maxLon: 102.5, - minLat: 2.5, - minLon: 92.5, - }; - const newBuffer = { - maxLat: 10, - maxLon: 100, - minLat: 5, - minLon: 95, - }; - expect( - updateDueToExtent( - sourceMock, - { buffer: oldBuffer, areResultsTrimmed: true }, - { buffer: newBuffer } - ) - ).toBe(true); - }); + it('should be true when the new buffer is contained in the old buffer and the past results were truncated', async () => { + const oldBuffer = { + maxLat: 12.5, + maxLon: 102.5, + minLat: 2.5, + minLon: 92.5, + }; + const newBuffer = { + maxLat: 10, + maxLon: 100, + minLat: 5, + minLon: 95, + }; + expect( + updateDueToExtent({ buffer: oldBuffer, areResultsTrimmed: true }, { buffer: newBuffer }) + ).toBe(true); + }); - it('should be true when meta has no old buffer', async () => { - expect(updateDueToExtent(sourceMock)).toBe(true); - }); + it('should be true when meta has no old buffer', async () => { + expect(updateDueToExtent()).toBe(true); + }); - it('should be true when the new buffer is not contained in the old buffer', async () => { - const oldBuffer = { - maxLat: 12.5, - maxLon: 102.5, - minLat: 2.5, - minLon: 92.5, - }; - const newBuffer = { - maxLat: 7.5, - maxLon: 92.5, - minLat: -2.5, - minLon: 82.5, - }; - expect(updateDueToExtent(sourceMock, { buffer: oldBuffer }, { buffer: newBuffer })).toBe( - true - ); - }); + it('should be true when the new buffer is not contained in the old buffer', async () => { + const oldBuffer = { + maxLat: 12.5, + maxLon: 102.5, + minLat: 2.5, + minLon: 92.5, + }; + const newBuffer = { + maxLat: 7.5, + maxLon: 92.5, + minLat: -2.5, + minLon: 82.5, + }; + expect(updateDueToExtent({ buffer: oldBuffer }, { buffer: newBuffer })).toBe(true); }); }); diff --git a/x-pack/plugins/maps/public/layers/util/can_skip_fetch.ts b/x-pack/plugins/maps/public/layers/util/can_skip_fetch.ts index 758cc35f41fbb..8398bd7af39ad 100644 --- a/x-pack/plugins/maps/public/layers/util/can_skip_fetch.ts +++ b/x-pack/plugins/maps/public/layers/util/can_skip_fetch.ts @@ -15,16 +15,7 @@ import { DataRequest } from './data_request'; const SOURCE_UPDATE_REQUIRED = true; const NO_SOURCE_UPDATE_REQUIRED = false; -export function updateDueToExtent( - source: ISource, - prevMeta: DataMeta = {}, - nextMeta: DataMeta = {} -) { - const extentAware = source.isFilterByMapBounds(); - if (!extentAware) { - return NO_SOURCE_UPDATE_REQUIRED; - } - +export function updateDueToExtent(prevMeta: DataMeta = {}, nextMeta: DataMeta = {}) { const { buffer: previousBuffer } = prevMeta; const { buffer: newBuffer } = nextMeta; @@ -134,7 +125,10 @@ export async function canSkipSourceUpdate({ updateDueToPrecisionChange = !_.isEqual(prevMeta.geogridPrecision, nextMeta.geogridPrecision); } - const updateDueToExtentChange = updateDueToExtent(source, prevMeta, nextMeta); + let updateDueToExtentChange = false; + if (extentAware) { + updateDueToExtentChange = updateDueToExtent(prevMeta, nextMeta); + } const updateDueToSourceMetaChange = !_.isEqual(prevMeta.sourceMeta, nextMeta.sourceMeta); diff --git a/x-pack/plugins/maps/public/layers/vector_layer.js b/x-pack/plugins/maps/public/layers/vector_layer.js index 17b7f8152d76d..582e34bce2e98 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/plugins/maps/public/layers/vector_layer.js @@ -175,8 +175,7 @@ export class VectorLayer extends AbstractLayer { } async getBounds(dataFilters) { - const isStaticLayer = - !this.getSource().isBoundsAware() || !this.getSource().isFilterByMapBounds(); + const isStaticLayer = !this.getSource().isBoundsAware(); if (isStaticLayer) { return this._getBoundsBasedOnData(); } diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index 475e44af3669c..c65d872212ad6 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -15,7 +15,7 @@ import { LicenseManagementUIPluginSetup } from '../../../../../license_managemen interface StartPlugins { data: DataPublicPluginStart; - security: SecurityPluginSetup; + security?: SecurityPluginSetup; licenseManagement?: LicenseManagementUIPluginSetup; } export type StartServices = CoreStart & StartPlugins; diff --git a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx index 30fc74acbabf4..32b51c8b7d4ee 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/file_based/components/filebeat_config_flyout/filebeat_config_flyout.tsx @@ -55,9 +55,11 @@ export const FilebeatConfigFlyout: FC = ({ } = useMlKibana(); useEffect(() => { - security.authc.getCurrentUser().then(user => { - setUsername(user.username === undefined ? null : user.username); - }); + if (security !== undefined) { + security.authc.getCurrentUser().then(user => { + setUsername(user.username === undefined ? null : user.username); + }); + } }, []); useEffect(() => { diff --git a/x-pack/plugins/ml/public/application/management/index.ts b/x-pack/plugins/ml/public/application/management/index.ts index a6fe9e1d11953..6bc5c9b15074f 100644 --- a/x-pack/plugins/ml/public/application/management/index.ts +++ b/x-pack/plugins/ml/public/application/management/index.ts @@ -25,8 +25,11 @@ export function initManagementSection( ) { const licensing = pluginsSetup.licensing.license$.pipe(take(1)); licensing.subscribe(license => { - if (license.check(PLUGIN_ID, MINIMUM_FULL_LICENSE).state === 'valid') { - const management = pluginsSetup.management; + const management = pluginsSetup.management; + if ( + management !== undefined && + license.check(PLUGIN_ID, MINIMUM_FULL_LICENSE).state === 'valid' + ) { const mlSection = management.sections.register({ id: PLUGIN_ID, title: i18n.translate('xpack.ml.management.mlTitle', { diff --git a/x-pack/plugins/ml/public/application/util/dependency_cache.ts b/x-pack/plugins/ml/public/application/util/dependency_cache.ts index 934a0a5e9ae3a..f8dd2a37dd589 100644 --- a/x-pack/plugins/ml/public/application/util/dependency_cache.ts +++ b/x-pack/plugins/ml/public/application/util/dependency_cache.ts @@ -40,7 +40,7 @@ export interface DependencyCache { savedObjectsClient: SavedObjectsClientContract | null; application: ApplicationStart | null; http: HttpStart | null; - security: SecurityPluginSetup | null; + security: SecurityPluginSetup | undefined | null; i18n: I18nStart | null; urlGenerators: SharePluginStart['urlGenerators'] | null; mlConfig: MlConfigType | null; diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index b51be4d248683..e3b8441db432e 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -32,9 +32,9 @@ export interface MlStartDependencies { share: SharePluginStart; } export interface MlSetupDependencies { - security: SecurityPluginSetup; + security?: SecurityPluginSetup; licensing: LicensingPluginSetup; - management: ManagementSetup; + management?: ManagementSetup; usageCollection: UsageCollectionSetup; licenseManagement?: LicenseManagementUIPluginSetup; home: HomePublicPluginSetup; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rule_actions/saved_object_mappings.ts b/x-pack/plugins/siem/server/lib/detection_engine/rule_actions/saved_object_mappings.ts index d50c339c95266..e50f82bb482a7 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rule_actions/saved_object_mappings.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rule_actions/saved_object_mappings.ts @@ -31,9 +31,8 @@ export const ruleActionsSavedObjectMappings = { type: 'keyword', }, params: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - dynamic: true as any, - properties: {}, + type: 'object', + enabled: false, }, }, }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 785a58baa24a8..f3ddcd221ffb4 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6370,7 +6370,6 @@ "xpack.endpoint.host.list.os": "オペレーティングシステム", "xpack.endpoint.host.list.policy": "ポリシー", "xpack.endpoint.host.list.policyStatus": "ポリシーステータス", - "xpack.endpoint.host.list.sensorVersion": "サーバーバージョン", "xpack.endpoint.host.list.totalCount": "表示中: {totalItemCount, plural, one {# ホスト} other {# ホスト}}", "xpack.endpoint.notFound": "ページが見つかりません", "xpack.endpoint.pluginTitle": "エンドポイント", @@ -8819,10 +8818,8 @@ "xpack.logstash.workersTooltip": "パイプラインのフィルターとアウトプットステージを同時に実行するワーカーの数です。イベントが詰まってしまう場合や CPU が飽和状態ではない場合は、マシンの処理能力をより有効に活用するため、この数字を上げてみてください。\n\nデフォルト値:ホストの CPU コア数です", "xpack.maps.addLayerPanel.addLayer": "レイヤーを追加", "xpack.maps.addLayerPanel.changeDataSourceButtonLabel": "データソースを変更", - "xpack.maps.addLayerPanel.chooseDataSourceTitle": "データソースの選択", "xpack.maps.addLayerPanel.footer.cancelButtonLabel": "キャンセル", "xpack.maps.addLayerPanel.importFile": "ファイルのインポート", - "xpack.maps.addLayerPanel.selectSource": "ソースを選択", "xpack.maps.aggs.defaultCountLabel": "カウント", "xpack.maps.appDescription": "マップアプリケーション", "xpack.maps.appTitle": "マップ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ccee034773fef..de04f2aa298e5 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6372,7 +6372,6 @@ "xpack.endpoint.host.list.os": "操作系统", "xpack.endpoint.host.list.policy": "政策", "xpack.endpoint.host.list.policyStatus": "策略状态", - "xpack.endpoint.host.list.sensorVersion": "感应器版本", "xpack.endpoint.host.list.totalCount": "正在显示:{totalItemCount, plural, one {# 个主机} other {# 个主机}}", "xpack.endpoint.notFound": "未找到页面", "xpack.endpoint.pluginTitle": "终端", @@ -8822,10 +8821,8 @@ "xpack.logstash.workersTooltip": "并行执行管道的筛选和输出阶段的工作线程数目。如果您发现事件出现积压或 CPU 未饱和,请考虑增大此数值,以更好地利用机器处理能力。\n\n默认值:主机的 CPU 核心数", "xpack.maps.addLayerPanel.addLayer": "添加图层", "xpack.maps.addLayerPanel.changeDataSourceButtonLabel": "更改数据源", - "xpack.maps.addLayerPanel.chooseDataSourceTitle": "选择数据源", "xpack.maps.addLayerPanel.footer.cancelButtonLabel": "鍙栨秷", "xpack.maps.addLayerPanel.importFile": "导入文件", - "xpack.maps.addLayerPanel.selectSource": "选择源", "xpack.maps.aggs.defaultCountLabel": "计数", "xpack.maps.appDescription": "地图应用程序", "xpack.maps.appTitle": "Maps", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index 9da4f059f8967..230b896eeca7d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -7,24 +7,55 @@ import * as React from 'react'; import uuid from 'uuid'; import { shallow } from 'enzyme'; import { AlertDetails } from './alert_details'; -import { Alert, ActionType } from '../../../../types'; -import { EuiTitle, EuiBadge, EuiFlexItem, EuiSwitch, EuiBetaBadge } from '@elastic/eui'; +import { Alert, ActionType, AlertTypeRegistryContract } from '../../../../types'; +import { + EuiTitle, + EuiBadge, + EuiFlexItem, + EuiSwitch, + EuiBetaBadge, + EuiButtonEmpty, +} from '@elastic/eui'; import { times, random } from 'lodash'; import { i18n } from '@kbn/i18n'; import { ViewInApp } from './view_in_app'; import { PLUGIN } from '../../../constants/plugin'; +import { coreMock } from 'src/core/public/mocks'; +const mockes = coreMock.createSetup(); jest.mock('../../../app_context', () => ({ useAppDependencies: jest.fn(() => ({ http: jest.fn(), - legacy: { - capabilities: { - get: jest.fn(() => ({})), - }, + capabilities: { + get: jest.fn(() => ({})), }, + actionTypeRegistry: jest.fn(), + alertTypeRegistry: jest.fn(() => { + const mocked: jest.Mocked = { + has: jest.fn(), + register: jest.fn(), + get: jest.fn(), + list: jest.fn(), + }; + return mocked; + }), + toastNotifications: mockes.notifications.toasts, + docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' }, + uiSettings: mockes.uiSettings, + dataPlugin: jest.fn(), + charts: jest.fn(), })), })); +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + push: jest.fn(), + }), + useLocation: () => ({ + pathname: '/triggersActions/alerts/', + }), +})); + jest.mock('../../../lib/capabilities', () => ({ hasSaveAlertsCapability: jest.fn(() => true), })); @@ -232,6 +263,28 @@ describe('alert_details', () => { ).containsMatchingElement() ).toBeTruthy(); }); + + it('links to the Edit flyout', () => { + const alert = mockAlert(); + + const alertType = { + id: '.noop', + name: 'No Op', + actionGroups: [{ id: 'default', name: 'Default' }], + actionVariables: { context: [], state: [] }, + defaultActionGroupId: 'default', + }; + + expect( + shallow( + + ) + .find(EuiButtonEmpty) + .find('[data-test-subj="openEditAlertFlyoutButton"]') + .first() + .exists() + ).toBeTruthy(); + }); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 5bfcf9fd2d4e6..318dd28d92da1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useState, Fragment } from 'react'; import { indexBy } from 'lodash'; +import { useHistory } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, @@ -21,6 +22,7 @@ import { EuiCallOut, EuiSpacer, EuiBetaBadge, + EuiButtonEmpty, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -34,6 +36,9 @@ import { import { AlertInstancesRouteWithApi } from './alert_instances_route'; import { ViewInApp } from './view_in_app'; import { PLUGIN } from '../../../constants/plugin'; +import { AlertEdit } from '../../alert_form'; +import { AlertsContextProvider } from '../../../context/alerts_context'; +import { routeToAlertDetails } from '../../../constants'; type AlertDetailsProps = { alert: Alert; @@ -52,7 +57,18 @@ export const AlertDetails: React.FunctionComponent = ({ muteAlert, requestRefresh, }) => { - const { capabilities } = useAppDependencies(); + const history = useHistory(); + const { + http, + toastNotifications, + capabilities, + alertTypeRegistry, + actionTypeRegistry, + uiSettings, + docLinks, + charts, + dataPlugin, + } = useAppDependencies(); const canSave = hasSaveAlertsCapability(capabilities); @@ -61,6 +77,11 @@ export const AlertDetails: React.FunctionComponent = ({ const [isEnabled, setIsEnabled] = useState(alert.enabled); const [isMuted, setIsMuted] = useState(alert.muteAll); + const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); + + const setAlert = async () => { + history.push(routeToAlertDetails.replace(`:alertId`, alert.id)); + }; return ( @@ -90,6 +111,42 @@ export const AlertDetails: React.FunctionComponent = ({ + {canSave ? ( + + + {' '} + setEditFlyoutVisibility(true)} + > + + + + + + + + ) : null} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx index 498ecffe9b947..b9d08abae1684 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx @@ -26,13 +26,13 @@ export const AlertInstancesRoute: React.FunctionComponent = requestRefresh, loadAlertState, }) => { - const { http, toastNotifications } = useAppDependencies(); + const { toastNotifications } = useAppDependencies(); const [alertState, setAlertState] = useState(null); useEffect(() => { getAlertState(alert.id, loadAlertState, setAlertState, toastNotifications); - }, [alert, http, loadAlertState, toastNotifications]); + }, [alert, loadAlertState, toastNotifications]); return alertState ? ( diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts index fe0f630830a56..43d533ad3ae14 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/index.ts @@ -14,6 +14,7 @@ export default function(kibana: any) { require: ['xpack_main', 'actions', 'alerting', 'elasticsearch'], name: 'alerts', init(server: any) { + const clusterClient = server.newPlatform.start.core.elasticsearch.legacy.client; server.plugins.xpack_main.registerFeature({ id: 'alerting', name: 'Alerting', @@ -165,6 +166,22 @@ export default function(kibana: any) { } catch (e) { callClusterError = e; } + // Call scoped cluster + const callScopedCluster = services.getScopedCallCluster(clusterClient); + let callScopedClusterSuccess = false; + let callScopedClusterError; + try { + await callScopedCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callScopedClusterSuccess = true; + } catch (e) { + callScopedClusterError = e; + } // Saved objects client let savedObjectsClientSuccess = false; let savedObjectsClientError; @@ -185,6 +202,8 @@ export default function(kibana: any) { state: { callClusterSuccess, callClusterError, + callScopedClusterSuccess, + callScopedClusterError, savedObjectsClientSuccess, savedObjectsClientError, }, @@ -376,6 +395,22 @@ export default function(kibana: any) { } catch (e) { callClusterError = e; } + // Call scoped cluster + const callScopedCluster = services.getScopedCallCluster(clusterClient); + let callScopedClusterSuccess = false; + let callScopedClusterError; + try { + await callScopedCluster('index', { + index: params.callClusterAuthorizationIndex, + refresh: 'wait_for', + body: { + param1: 'test', + }, + }); + callScopedClusterSuccess = true; + } catch (e) { + callScopedClusterError = e; + } // Saved objects client let savedObjectsClientSuccess = false; let savedObjectsClientError; @@ -396,6 +431,8 @@ export default function(kibana: any) { state: { callClusterSuccess, callClusterError, + callScopedClusterSuccess, + callScopedClusterError, savedObjectsClientSuccess, savedObjectsClientError, }, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/execute.ts index a58e14dd563ef..af8af72d458fd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/execute.ts @@ -436,11 +436,16 @@ export default function({ getService }: FtrProviderContext) { indexedRecord = searchResult.hits.hits[0]; expect(indexedRecord._source.state).to.eql({ callClusterSuccess: false, + callScopedClusterSuccess: false, savedObjectsClientSuccess: false, callClusterError: { ...indexedRecord._source.state.callClusterError, statusCode: 403, }, + callScopedClusterError: { + ...indexedRecord._source.state.callScopedClusterError, + statusCode: 403, + }, savedObjectsClientError: { ...indexedRecord._source.state.savedObjectsClientError, output: { @@ -457,6 +462,7 @@ export default function({ getService }: FtrProviderContext) { indexedRecord = searchResult.hits.hits[0]; expect(indexedRecord._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...indexedRecord._source.state.savedObjectsClientError, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index d8e4f808f5cd2..59cf22b52920c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -469,11 +469,16 @@ instanceStateValue: true expect(searchResult.hits.total.value).to.eql(1); expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: false, + callScopedClusterSuccess: false, savedObjectsClientSuccess: false, callClusterError: { ...searchResult.hits.hits[0]._source.state.callClusterError, statusCode: 403, }, + callScopedClusterError: { + ...searchResult.hits.hits[0]._source.state.callScopedClusterError, + statusCode: 403, + }, savedObjectsClientError: { ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { @@ -497,6 +502,7 @@ instanceStateValue: true expect(searchResult.hits.total.value).to.eql(1); expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, @@ -577,11 +583,16 @@ instanceStateValue: true expect(searchResult.hits.total.value).to.eql(1); expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: false, + callScopedClusterSuccess: false, savedObjectsClientSuccess: false, callClusterError: { ...searchResult.hits.hits[0]._source.state.callClusterError, statusCode: 403, }, + callScopedClusterError: { + ...searchResult.hits.hits[0]._source.state.callScopedClusterError, + statusCode: 403, + }, savedObjectsClientError: { ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, output: { @@ -605,6 +616,7 @@ instanceStateValue: true expect(searchResult.hits.total.value).to.eql(1); expect(searchResult.hits.hits[0]._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...searchResult.hits.hits[0]._source.state.savedObjectsClientError, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts index 3faa54ee0b219..715573ef1237e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/execute.ts @@ -186,6 +186,7 @@ export default function({ getService }: FtrProviderContext) { const indexedRecord = searchResult.hits.hits[0]; expect(indexedRecord._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...indexedRecord._source.state.savedObjectsClientError, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts index 0d1596a95bfbb..95ccfb897cf54 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/alerts_base.ts @@ -277,6 +277,7 @@ instanceStateValue: true )[0]; expect(alertTestRecord._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...alertTestRecord._source.state.savedObjectsClientError, @@ -332,6 +333,7 @@ instanceStateValue: true )[0]; expect(actionTestRecord._source.state).to.eql({ callClusterSuccess: true, + callScopedClusterSuccess: true, savedObjectsClientSuccess: false, savedObjectsClientError: { ...actionTestRecord._source.state.savedObjectsClientError, diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts index e238937ee845f..a9133bb380179 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts @@ -195,7 +195,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '10.0 MB', total_by_field_count: '37', total_over_field_count: '92', total_partition_field_count: '8', @@ -262,7 +261,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '100.0 MB', total_by_field_count: '994', total_over_field_count: '0', total_partition_field_count: '2', @@ -549,7 +547,6 @@ export default function({ getService }: FtrProviderContext) { job_id: testData.jobId, result_type: testData.expected.modelSizeStats.result_type, model_bytes_exceeded: testData.expected.modelSizeStats.model_bytes_exceeded, - model_bytes_memory_limit: testData.expected.modelSizeStats.model_bytes_memory_limit, total_by_field_count: testData.expected.modelSizeStats.total_by_field_count, total_over_field_count: testData.expected.modelSizeStats.total_over_field_count, total_partition_field_count: @@ -813,7 +810,6 @@ export default function({ getService }: FtrProviderContext) { job_id: testData.jobIdClone, result_type: testData.expected.modelSizeStats.result_type, model_bytes_exceeded: testData.expected.modelSizeStats.model_bytes_exceeded, - model_bytes_memory_limit: testData.expected.modelSizeStats.model_bytes_memory_limit, total_by_field_count: testData.expected.modelSizeStats.total_by_field_count, total_over_field_count: testData.expected.modelSizeStats.total_over_field_count, total_partition_field_count: diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/categorization_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/categorization_job.ts index 5a39b06b4c15a..b8ac646c35875 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/categorization_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/categorization_job.ts @@ -64,7 +64,6 @@ export default function({ getService }: FtrProviderContext) { job_id: expectedJobId, result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '15.0 MB', total_by_field_count: '30', total_over_field_count: '0', total_partition_field_count: '2', diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/date_nanos_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/date_nanos_job.ts index 96b69c10f4c2f..d3934d674124e 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/date_nanos_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/date_nanos_job.ts @@ -153,7 +153,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '10.0 MB', total_by_field_count: '3', total_over_field_count: '0', total_partition_field_count: '2', @@ -422,7 +421,6 @@ export default function({ getService }: FtrProviderContext) { job_id: testData.jobId, result_type: testData.expected.modelSizeStats.result_type, model_bytes_exceeded: testData.expected.modelSizeStats.model_bytes_exceeded, - model_bytes_memory_limit: testData.expected.modelSizeStats.model_bytes_memory_limit, total_by_field_count: testData.expected.modelSizeStats.total_by_field_count, total_over_field_count: testData.expected.modelSizeStats.total_over_field_count, total_partition_field_count: diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts index 45b03b3d179b7..f6a9c96492f39 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts @@ -61,7 +61,6 @@ export default function({ getService }: FtrProviderContext) { job_id: expectedJobId, result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '59', total_over_field_count: '0', total_partition_field_count: '58', diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts index a9c94a650898e..547c489411b5f 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts @@ -75,7 +75,6 @@ export default function({ getService }: FtrProviderContext) { job_id: expectedJobId, result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '8.0 MB', total_by_field_count: '25', total_over_field_count: '92', total_partition_field_count: '3', diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts index 862904862cb13..b1fee1633641a 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts @@ -54,7 +54,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '3', total_over_field_count: '0', total_partition_field_count: '2', @@ -105,7 +104,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '7', total_over_field_count: '0', total_partition_field_count: '6', @@ -156,7 +154,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '7', total_over_field_count: '0', total_partition_field_count: '6', @@ -208,7 +205,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '3', total_over_field_count: '0', total_partition_field_count: '2', @@ -259,7 +255,6 @@ export default function({ getService }: FtrProviderContext) { modelSizeStats: { result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '20.0 MB', total_by_field_count: '3', total_over_field_count: '0', total_partition_field_count: '2', @@ -464,7 +459,6 @@ export default function({ getService }: FtrProviderContext) { job_id: testData.jobId, result_type: testData.expected.modelSizeStats.result_type, model_bytes_exceeded: testData.expected.modelSizeStats.model_bytes_exceeded, - model_bytes_memory_limit: testData.expected.modelSizeStats.model_bytes_memory_limit, total_by_field_count: testData.expected.modelSizeStats.total_by_field_count, total_over_field_count: testData.expected.modelSizeStats.total_over_field_count, total_partition_field_count: diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts index 46fbc40139485..0f8655e3c6bbc 100644 --- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts +++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts @@ -60,7 +60,6 @@ export default function({ getService }: FtrProviderContext) { job_id: expectedJobId, result_type: 'model_size_stats', model_bytes_exceeded: '0.0 B', - model_bytes_memory_limit: '15.0 MB', total_by_field_count: '3', total_over_field_count: '0', total_partition_field_count: '2', diff --git a/x-pack/test/functional/apps/machine_learning/pages.ts b/x-pack/test/functional/apps/machine_learning/pages.ts index 3c3698792ff7d..35536b4eeda12 100644 --- a/x-pack/test/functional/apps/machine_learning/pages.ts +++ b/x-pack/test/functional/apps/machine_learning/pages.ts @@ -10,7 +10,7 @@ export default function({ getService }: FtrProviderContext) { const ml = getService('ml'); describe('page navigation', function() { - this.tags(['includeFirefox', 'mlqa']); + this.tags(['skipFirefox', 'mlqa']); before(async () => { await ml.api.cleanMlIndices(); await ml.securityUI.loginAsMlPowerUser(); diff --git a/x-pack/test/functional/services/machine_learning/job_table.ts b/x-pack/test/functional/services/machine_learning/job_table.ts index 0e638963f2367..e2451328ea941 100644 --- a/x-pack/test/functional/services/machine_learning/job_table.ts +++ b/x-pack/test/functional/services/machine_learning/job_table.ts @@ -187,44 +187,24 @@ export function MachineLearningJobTableProvider({ getService }: FtrProviderConte expectedCounts: object, expectedModelSizeStats: object ) { - const countDetails = await this.parseJobCounts(jobId); - const counts = countDetails.counts; - - // fields that have changing values are only validated - // to be present and then removed so they don't make - // the object validation fail - expect(counts).to.have.property('last_data_time'); - delete counts.last_data_time; - - expect(counts).to.eql(expectedCounts); - - const modelSizeStats = countDetails.modelSizeStats; - - // fields that have changing values are only validated - // to be present and then removed so they don't make - // the object validation fail - expect(modelSizeStats).to.have.property('log_time'); - delete modelSizeStats.log_time; - expect(modelSizeStats).to.have.property('model_bytes'); - delete modelSizeStats.model_bytes; - - // remove categorization fields from validation until - // the ES version is updated - delete modelSizeStats.categorization_status; - delete modelSizeStats.categorized_doc_count; - delete modelSizeStats.dead_category_count; - delete modelSizeStats.frequent_category_count; - delete modelSizeStats.rare_category_count; - delete modelSizeStats.total_category_count; - - // MML during clone has changed in #61589 - // TODO: adjust test code to reflect the new behavior - expect(modelSizeStats).to.have.property('model_bytes_memory_limit'); - delete modelSizeStats.model_bytes_memory_limit; - // @ts-ignore - delete expectedModelSizeStats.model_bytes_memory_limit; - - expect(modelSizeStats).to.eql(expectedModelSizeStats); + const { counts, modelSizeStats } = await this.parseJobCounts(jobId); + + // Only check for expected keys / values, ignore additional properties + // This way the tests stay stable when new properties are added on the ES side + for (const [key, value] of Object.entries(expectedCounts)) { + expect(counts) + .to.have.property(key) + .eql(value, `Expected counts property '${key}' to exist with value '${value}'`); + } + + for (const [key, value] of Object.entries(expectedModelSizeStats)) { + expect(modelSizeStats) + .to.have.property(key) + .eql( + value, + `Expected model size stats property '${key}' to exist with value '${value}')` + ); + } } public async clickActionsMenu(jobId: string) { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index 2c29954528bd5..1b75f4a27766a 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -17,6 +17,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const log = getService('log'); const alerting = getService('alerting'); const retry = getService('retry'); + const find = getService('find'); describe('Alert Details', function() { describe('Header', function() { @@ -148,6 +149,56 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); + describe('Edit alert button', function() { + const testRunUuid = uuid.v4(); + + it('should open edit alert flyout', async () => { + await pageObjects.common.navigateToApp('triggersActions'); + const params = { + aggType: 'count', + termSize: 5, + thresholdComparator: '>', + timeWindowSize: 5, + timeWindowUnit: 'm', + groupBy: 'all', + threshold: [1000, 5000], + index: ['.kibana_1'], + timeField: 'alert', + }; + const alert = await alerting.alerts.createAlertWithActions( + testRunUuid, + '.index-threshold', + params + ); + // refresh to see alert + await browser.refresh(); + + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Verify content + await testSubjects.existOrFail('alertsList'); + + // click on first alert + await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(alert.name); + + const editButton = await testSubjects.find('openEditAlertFlyoutButton'); + await editButton.click(); + + const updatedAlertName = `Changed Alert Name ${uuid.v4()}`; + await testSubjects.setValue('alertNameInput', updatedAlertName, { + clearWithKeyboard: true, + }); + + await find.clickByCssSelector('[data-test-subj="saveEditedAlertButton"]:not(disabled)'); + + const toastTitle = await pageObjects.common.closeToast(); + expect(toastTitle).to.eql(`Updated '${updatedAlertName}'`); + + const headingText = await pageObjects.alertDetailsUI.getHeadingText(); + expect(headingText).to.be(updatedAlertName); + }); + }); + describe('View In App', function() { const testRunUuid = uuid.v4(); diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts index 5b506c20e029c..2a0d28f246765 100644 --- a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts @@ -22,6 +22,44 @@ export class Alerts { }); } + public async createAlertWithActions( + name: string, + alertTypeId: string, + params?: Record, + actions?: Array<{ + id: string; + group: string; + params: Record; + }>, + tags?: string[], + consumer?: string, + schedule?: Record, + throttle?: string + ) { + this.log.debug(`creating alert ${name}`); + + const { data: alert, status, statusText } = await this.axios.post(`/api/alert`, { + enabled: true, + name, + tags, + alertTypeId, + consumer: consumer ?? 'bar', + schedule: schedule ?? { interval: '1m' }, + throttle: throttle ?? '1m', + actions: actions ?? [], + params: params ?? {}, + }); + if (status !== 200) { + throw new Error( + `Expected status code of 200, received ${status} ${statusText}: ${util.inspect(alert)}` + ); + } + + this.log.debug(`created alert ${alert.id}`); + + return alert; + } + public async createNoOp(name: string) { this.log.debug(`creating alert ${name}`); diff --git a/yarn.lock b/yarn.lock index 0a1432882c327..9677f7e00682a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1192,6 +1192,32 @@ date-fns "^1.27.2" figures "^1.7.0" +"@cypress/request@2.88.5": + version "2.88.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.5.tgz#8d7ecd17b53a849cfd5ab06d5abe7d84976375d7" + integrity sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + "@cypress/webpack-preprocessor@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.0.tgz#8c4debc0b1abf045b62524d1996dd9aeaf7e86a8" @@ -3699,15 +3725,20 @@ resolved "https://registry.yarnpkg.com/@types/base64-js/-/base64-js-1.2.5.tgz#582b2476169a6cba460a214d476c744441d873d5" integrity sha1-WCskdhaabLpGCiFNR2x0REHYc9U= -"@types/bluebird@*": - version "3.5.28" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.28.tgz#04c1a520ff076649236bc8ca21198542ce2bdb09" - integrity sha512-0Vk/kqkukxPKSzP9c8WJgisgGDx5oZDbsLLWIP5t70yThO/YleE+GEm2S1GlRALTaack3O7U5OS5qEm7q2kciA== +"@types/blob-util@1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@types/blob-util/-/blob-util-1.3.3.tgz#adba644ae34f88e1dd9a5864c66ad651caaf628a" + integrity sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w== -"@types/bluebird@^3.1.1": - version "3.5.20" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.20.tgz#f6363172add6f4eabb8cada53ca9af2781e8d6a1" - integrity sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA== +"@types/bluebird@*", "@types/bluebird@^3.1.1": + version "3.5.30" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5" + integrity sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw== + +"@types/bluebird@3.5.29": + version "3.5.29" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6" + integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw== "@types/boom@*", "@types/boom@^7.2.0": version "7.2.0" @@ -3739,6 +3770,19 @@ resolved "https://registry.yarnpkg.com/@types/catbox/-/catbox-10.0.1.tgz#266679017749041fe9873fee1131dd2aaa04a07e" integrity sha512-ECuJ+f5gGHiLeiE4RlE/xdqv/0JVDToegPV1aTb10tQStYa0Ycq2OJfQukDv3IFaw3B+CMV46jHc5bXe6QXEQg== +"@types/chai-jquery@1.1.40": + version "1.1.40" + resolved "https://registry.yarnpkg.com/@types/chai-jquery/-/chai-jquery-1.1.40.tgz#445bedcbbb2ae4e3027f46fa2c1733c43481ffa1" + integrity sha512-mCNEZ3GKP7T7kftKeIs7QmfZZQM7hslGSpYzKbOlR2a2HCFf9ph4nlMRA9UnuOETeOQYJVhJQK7MwGqNZVyUtQ== + dependencies: + "@types/chai" "*" + "@types/jquery" "*" + +"@types/chai@*", "@types/chai@4.2.7", "@types/chai@^4.2.11": + version "4.2.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" + integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== + "@types/chance@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.0.1.tgz#c10703020369602c40dd9428cc6e1437027116df" @@ -4176,7 +4220,7 @@ resolved "https://registry.yarnpkg.com/@types/joi/-/joi-13.6.1.tgz#325486a397504f8e22c8c551dc8b0e1d41d5d5ae" integrity sha512-JxZ0NP8NuB0BJOXi1KvAA6rySLTPmhOy4n2gzSFq/IFM3LNFm0h+2Vn/bPPgEYlWqzS2NPeLgKqfm75baX+Hog== -"@types/jquery@*", "@types/jquery@^3.3.31": +"@types/jquery@*", "@types/jquery@3.3.31", "@types/jquery@^3.3.31": version "3.3.31" resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b" integrity sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg== @@ -4282,9 +4326,14 @@ "@types/lodash" "*" "@types/lodash@*", "@types/lodash@^4.14.110", "@types/lodash@^4.14.116": - version "4.14.137" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.137.tgz#8a4804937dc6462274ffcc088df8f14fc1b368e2" - integrity sha512-g4rNK5SRKloO+sUGbuO7aPtwbwzMgjK+bm9BBhLD7jGUiGR7zhwYEhSln/ihgYQBeIJ5j7xjyaYzrWTcu3UotQ== + version "4.14.150" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.150.tgz#649fe44684c3f1fcb6164d943c5a61977e8cf0bd" + integrity sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w== + +"@types/lodash@4.14.149": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== "@types/lodash@^3.10.1": version "3.10.2" @@ -4342,7 +4391,7 @@ dependencies: "@types/mime-db" "*" -"@types/minimatch@*", "@types/minimatch@^3.0.3": +"@types/minimatch@*", "@types/minimatch@3.0.3", "@types/minimatch@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== @@ -4359,6 +4408,11 @@ dependencies: "@types/node" "*" +"@types/mocha@5.2.7": + version "5.2.7" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" + integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== + "@types/mocha@^7.0.2": version "7.0.2" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" @@ -4751,11 +4805,36 @@ dependencies: "@types/node" "*" +"@types/sinon-chai@3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.3.tgz#afe392303dda95cc8069685d1e537ff434fa506e" + integrity sha512-TOUFS6vqS0PVL1I8NGVSNcFaNJtFoyZPXZ5zur+qlhDfOmQECZZM4H4kKgca6O8L+QceX/ymODZASfUfn+y4yQ== + dependencies: + "@types/chai" "*" + "@types/sinon" "*" + +"@types/sinon@*": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.0.tgz#5b70a360f55645dd64f205defd2a31b749a59799" + integrity sha512-v2TkYHkts4VXshMkcmot/H+ERZ2SevKa10saGaJPGCJ8vh3lKrC4u663zYEeRZxep+VbG6YRDtQ6gVqw9dYzPA== + dependencies: + "@types/sinonjs__fake-timers" "*" + +"@types/sinon@7.5.1": + version "7.5.1" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.5.1.tgz#d27b81af0d1cfe1f9b24eebe7a24f74ae40f5b7c" + integrity sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ== + "@types/sinon@^7.0.13": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-7.0.13.tgz#ca039c23a9e27ebea53e0901ef928ea2a1a6d313" integrity sha512-d7c/C/+H/knZ3L8/cxhicHUiTDxdgap0b/aNJfsmLwFu/iOP17mdgbQsbHA3SJmrzsjD0l3UEE5SN4xxuz5ung== +"@types/sinonjs__fake-timers@*": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e" + integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA== + "@types/sizzle@*", "@types/sizzle@2.3.2": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" @@ -6759,15 +6838,7 @@ axios@^0.18.0: follow-redirects "1.5.10" is-buffer "^2.0.2" -axios@^0.19.0: - version "0.19.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" - integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== - dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" - -axios@^0.19.2: +axios@^0.19.0, axios@^0.19.2: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== @@ -10370,13 +10441,24 @@ cypress-multi-reporters@^1.2.3: debug "^4.1.1" lodash "^4.17.11" -cypress@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.2.0.tgz#45673fb648b1a77b9a78d73e58b89ed05212d243" - integrity sha512-8LdreL91S/QiTCLYLNbIjLL8Ht4fJmu/4HGLxUI20Tc7JSfqEfCmXELrRfuPT0kjosJwJJZacdSji9XSRkPKUw== +cypress@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-4.4.1.tgz#f5aa1aa5f328f1299bff328103f7cbad89e80f29" + integrity sha512-LcskZ/PXRG9XTlEeeenKqz/KddT1x+7O7dqXsdKWPII01LxLNmNHIvHnlUqApchVbinJ5vir6J255CkELSeL0A== dependencies: "@cypress/listr-verbose-renderer" "0.4.1" + "@cypress/request" "2.88.5" "@cypress/xvfb" "1.2.4" + "@types/blob-util" "1.3.3" + "@types/bluebird" "3.5.29" + "@types/chai" "4.2.7" + "@types/chai-jquery" "1.1.40" + "@types/jquery" "3.3.31" + "@types/lodash" "4.14.149" + "@types/minimatch" "3.0.3" + "@types/mocha" "5.2.7" + "@types/sinon" "7.5.1" + "@types/sinon-chai" "3.2.3" "@types/sizzle" "2.3.2" arch "2.1.1" bluebird "3.7.2" @@ -10390,7 +10472,7 @@ cypress@^4.2.0: eventemitter2 "4.1.2" execa "1.0.0" executable "4.1.1" - extract-zip "1.6.7" + extract-zip "1.7.0" fs-extra "8.1.0" getos "3.1.4" is-ci "2.0.0" @@ -10399,12 +10481,11 @@ cypress@^4.2.0: listr "0.14.3" lodash "4.17.15" log-symbols "3.0.0" - minimist "1.2.2" + minimist "1.2.5" moment "2.24.0" ospath "1.2.2" pretty-bytes "5.3.0" ramda "0.26.1" - request cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16 request-progress "3.0.0" supports-color "7.1.0" tmp "0.1.0" @@ -13187,16 +13268,6 @@ extract-stack@^1.0.0: resolved "https://registry.yarnpkg.com/extract-stack/-/extract-stack-1.0.0.tgz#b97acaf9441eea2332529624b732fc5a1c8165fa" integrity sha1-uXrK+UQe6iMyUpYktzL8WhyBZfo= -extract-zip@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= - dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" - extract-zip@1.7.0, extract-zip@^1.6.6, extract-zip@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" @@ -20579,12 +20650,7 @@ minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minimist@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.2.tgz#b00a00230a1108c48c169e69a291aafda3aacd63" - integrity sha512-rIqbOrKb8GJmx/5bc2M0QchhUouMXSpd1RTclXsB41JdL+VtnojfaJR+h7F9k18/4kHUsBFgk80Uk+q569vjPA== - -minimist@^1.2.3, minimist@^1.2.5: +minimist@1.2.5, minimist@^1.2.3, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -25793,31 +25859,6 @@ request@^2.87.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16: - version "2.88.1" - resolved "https://codeload.github.com/cypress-io/request/tar.gz/b5af0d1fa47eec97ba980cde90a13e69a2afcd16" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - require-ancestors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/require-ancestors/-/require-ancestors-1.0.0.tgz#807831f8f8081fb12863da81ddb15c8f2a73a004" @@ -32456,13 +32497,6 @@ yauzl@2.10.0, yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= - dependencies: - fd-slicer "~1.0.1" - yauzl@^2.4.2: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f"