From 5c64db9695f82e1642239b9fd20be2fd16a29323 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Wed, 16 Dec 2020 08:23:39 -0800 Subject: [PATCH 01/38] [ML] Add transforms to doc links service (#86036) --- .../public/kibana-plugin-core-public.doclinksstart.links.md | 1 + .../core/public/kibana-plugin-core-public.doclinksstart.md | 2 +- src/core/public/doc_links/doc_links_service.ts | 4 ++++ src/core/public/public.api.md | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index 522c01124de8..d73ed716e6b1 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -102,6 +102,7 @@ readonly links: { }; readonly management: Record; readonly ml: Record; + readonly transforms: Record; readonly visualize: Record; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index 2bb885cba434..7aa170eef9b5 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly date_histogram: string;
readonly date_range: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly eql: string;
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly visualize: Record<string, string>;
} | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | {
readonly dashboard: {
readonly guide: string;
readonly drilldowns: string;
readonly drilldownsTriggerPicker: string;
readonly urlDrilldownTemplateSyntax: string;
readonly urlDrilldownVariables: string;
};
readonly filebeat: {
readonly base: string;
readonly installation: string;
readonly configuration: string;
readonly elasticsearchOutput: string;
readonly startup: string;
readonly exportedFields: string;
};
readonly auditbeat: {
readonly base: string;
};
readonly metricbeat: {
readonly base: string;
};
readonly heartbeat: {
readonly base: string;
};
readonly logstash: {
readonly base: string;
};
readonly functionbeat: {
readonly base: string;
};
readonly winlogbeat: {
readonly base: string;
};
readonly aggs: {
readonly date_histogram: string;
readonly date_range: string;
readonly filter: string;
readonly filters: string;
readonly geohash_grid: string;
readonly histogram: string;
readonly ip_range: string;
readonly range: string;
readonly significant_terms: string;
readonly terms: string;
readonly avg: string;
readonly avg_bucket: string;
readonly max_bucket: string;
readonly min_bucket: string;
readonly sum_bucket: string;
readonly cardinality: string;
readonly count: string;
readonly cumulative_sum: string;
readonly derivative: string;
readonly geo_bounds: string;
readonly geo_centroid: string;
readonly max: string;
readonly median: string;
readonly min: string;
readonly moving_avg: string;
readonly percentile_ranks: string;
readonly serial_diff: string;
readonly std_dev: string;
readonly sum: string;
readonly top_hits: string;
};
readonly scriptedFields: {
readonly scriptFields: string;
readonly scriptAggs: string;
readonly painless: string;
readonly painlessApi: string;
readonly painlessSyntax: string;
readonly luceneExpressions: string;
};
readonly indexPatterns: {
readonly loadingData: string;
readonly introduction: string;
};
readonly addData: string;
readonly kibana: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly eql: string;
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
readonly kueryQuerySyntax: string;
};
readonly date: {
readonly dateMath: string;
};
readonly management: Record<string, string>;
readonly ml: Record<string, string>;
readonly transforms: Record<string, string>;
readonly visualize: Record<string, string>;
} | | diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 07c07728d908..b8843b5c8559 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -148,6 +148,9 @@ export class DocLinksService { outlierDetectionRoc: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-roc`, regressionEvaluation: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-regression-evaluation`, }, + transforms: { + guide: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/transforms.html`, + }, visualize: { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/visualize.html`, timelionDeprecation: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/dashboard.html#timelion-deprecation`, @@ -258,6 +261,7 @@ export interface DocLinksStart { }; readonly management: Record; readonly ml: Record; + readonly transforms: Record; readonly visualize: Record; }; } diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 64833c21df6b..defe43377172 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -574,6 +574,7 @@ export interface DocLinksStart { }; readonly management: Record; readonly ml: Record; + readonly transforms: Record; readonly visualize: Record; }; } From 0be9230ff327802191d185e8d59e2ad677bb4985 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Wed, 16 Dec 2020 19:52:51 +0300 Subject: [PATCH 02/38] add tests for response headers (#86091) --- src/core/server/http/http_server.test.ts | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index e04131e5f0e5..71040598d34b 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -20,6 +20,7 @@ import { Server } from 'http'; import { readFileSync } from 'fs'; import supertest from 'supertest'; +import { omit } from 'lodash'; import { ByteSizeValue, schema } from '@kbn/config-schema'; import { HttpConfig } from './http_config'; @@ -887,6 +888,53 @@ describe('conditional compression', () => { expect(response.header).not.toHaveProperty('content-encoding'); }); }); + + describe('response headers', () => { + it('allows to configure "keep-alive" header', async () => { + const { registerRouter, server: innerServer } = await server.setup({ + ...config, + keepaliveTimeout: 100_000, + }); + + const router = new Router('', logger, enhanceWithContext); + router.get({ path: '/', validate: false }, (context, req, res) => + res.ok({ body: req.route }) + ); + registerRouter(router); + + await server.start(); + const response = await supertest(innerServer.listener) + .get('/') + .set('Connection', 'keep-alive') + .expect(200); + + expect(response.header.connection).toBe('keep-alive'); + expect(response.header['keep-alive']).toBe('timeout=100'); + }); + + it('default headers', async () => { + const { registerRouter, server: innerServer } = await server.setup(config); + + const router = new Router('', logger, enhanceWithContext); + router.get({ path: '/', validate: false }, (context, req, res) => + res.ok({ body: req.route }) + ); + registerRouter(router); + + await server.start(); + const response = await supertest(innerServer.listener).get('/').expect(200); + + const restHeaders = omit(response.header, ['date', 'content-length']); + expect(restHeaders).toMatchInlineSnapshot(` + Object { + "accept-ranges": "bytes", + "cache-control": "private, no-cache, no-store, must-revalidate", + "connection": "close", + "content-type": "application/json; charset=utf-8", + } + `); + }); + }); }); test('exposes route details of incoming request to a route handler (POST + payload options)', async () => { From 1e3a483b06846d276cd26535bda287bbd4457c55 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 16 Dec 2020 17:58:46 +0000 Subject: [PATCH 03/38] chore(NA): rebalance x-pack cigroups (#85797) --- .ci/es-snapshots/Jenkinsfile_verify_es | 2 + .ci/jobs.yml | 2 + test/functional/apps/visualize/index.ts | 2 +- test/scripts/jenkins_xpack_build_kibana.sh | 4 +- vars/kibanaCoverage.groovy | 2 + vars/tasks.groovy | 2 +- .../test/api_integration_basic/apis/index.ts | 2 +- .../exception_operators_data_types/index.ts | 36 +++++++---- .../security_and_spaces/tests/index.ts | 59 ++++++++++--------- .../tests/index.ts | 2 +- .../apps/api_keys/feature_controls/index.ts | 2 +- .../feature_controls/index.ts | 2 +- .../test/functional/apps/dev_tools/index.ts | 2 +- .../functional/apps/grok_debugger/index.js | 2 +- .../functional/apps/index_management/index.ts | 2 +- x-pack/test/functional_cors/tests/index.ts | 2 +- x-pack/test/licensing_plugin/public/index.ts | 2 +- .../test_suites/event_log/index.ts | 2 +- .../test_suites/task_manager/index.ts | 2 +- .../test_suites/task_manager/index.ts | 2 +- .../test_suites/global_search/index.ts | 2 +- 21 files changed, 80 insertions(+), 55 deletions(-) diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index 3c38d6279a03..11a39faa9aed 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -56,6 +56,8 @@ kibanaPipeline(timeoutMinutes: 150) { 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), 'xpack-ciGroup11': kibanaPipeline.xpackCiGroupProcess(11), + 'xpack-ciGroup12': kibanaPipeline.xpackCiGroupProcess(12), + 'xpack-ciGroup13': kibanaPipeline.xpackCiGroupProcess(13), ]), ]) } diff --git a/.ci/jobs.yml b/.ci/jobs.yml index d4ec8a3d5a69..d6ffb7d8f90a 100644 --- a/.ci/jobs.yml +++ b/.ci/jobs.yml @@ -32,6 +32,8 @@ JOB: - x-pack-ciGroup9 - x-pack-ciGroup10 - x-pack-ciGroup11 + - x-pack-ciGroup12 + - x-pack-ciGroup13 - x-pack-accessibility - x-pack-visualRegression diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index de73b2deabbd..1e4349ea5e8a 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -66,7 +66,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup11'); + this.tags('ciGroup4'); loadTestFile(require.resolve('./_line_chart')); loadTestFile(require.resolve('./_pie_chart')); diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index 8bb6effbec89..a9e603f63bd4 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -23,7 +23,9 @@ node scripts/functional_tests --assert-none-excluded \ --include-tag ciGroup8 \ --include-tag ciGroup9 \ --include-tag ciGroup10 \ - --include-tag ciGroup11 + --include-tag ciGroup11 \ + --include-tag ciGroup12 \ + --include-tag ciGroup13 # Do not build kibana for code coverage run if [[ -z "$CODE_COVERAGE" ]] ; then diff --git a/vars/kibanaCoverage.groovy b/vars/kibanaCoverage.groovy index 422a6c188979..77b00b0ec59a 100644 --- a/vars/kibanaCoverage.groovy +++ b/vars/kibanaCoverage.groovy @@ -251,6 +251,8 @@ def xpackProks() { 'xpack-ciGroup9' : kibanaPipeline.xpackCiGroupProcess(9), 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), 'xpack-ciGroup11': kibanaPipeline.xpackCiGroupProcess(11), + 'xpack-ciGroup12': kibanaPipeline.xpackCiGroupProcess(12), + 'xpack-ciGroup13': kibanaPipeline.xpackCiGroupProcess(13), ] } diff --git a/vars/tasks.groovy b/vars/tasks.groovy index a01e63e21814..73d7bb4088b3 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -95,7 +95,7 @@ def functionalXpack(Map params = [:]) { kibanaPipeline.buildXpack(10) if (config.ciGroups) { - def ciGroups = 1..11 + def ciGroups = 1..13 tasks(ciGroups.collect { kibanaPipeline.xpackCiGroupProcess(it) }) } diff --git a/x-pack/test/api_integration_basic/apis/index.ts b/x-pack/test/api_integration_basic/apis/index.ts index 66b3a45c12df..4c797b21c6fe 100644 --- a/x-pack/test/api_integration_basic/apis/index.ts +++ b/x-pack/test/api_integration_basic/apis/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', function () { - this.tags('ciGroup2'); + this.tags('ciGroup11'); loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./transform')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index 6b32eb19c83d..78450ccd70c2 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -9,18 +9,30 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { describe('Detection exceptions data types and operators', function () { - this.tags('ciGroup11'); + describe('', function () { + this.tags('ciGroup11'); - loadTestFile(require.resolve('./date')); - loadTestFile(require.resolve('./double')); - loadTestFile(require.resolve('./float')); - loadTestFile(require.resolve('./integer')); - loadTestFile(require.resolve('./ip')); - loadTestFile(require.resolve('./ip_array')); - loadTestFile(require.resolve('./keyword')); - loadTestFile(require.resolve('./keyword_array')); - loadTestFile(require.resolve('./long')); - loadTestFile(require.resolve('./text')); - loadTestFile(require.resolve('./text_array')); + loadTestFile(require.resolve('./date')); + loadTestFile(require.resolve('./double')); + loadTestFile(require.resolve('./float')); + loadTestFile(require.resolve('./integer')); + }); + + describe('', function () { + this.tags('ciGroup12'); + + loadTestFile(require.resolve('./ip')); + loadTestFile(require.resolve('./ip_array')); + loadTestFile(require.resolve('./keyword')); + loadTestFile(require.resolve('./keyword_array')); + loadTestFile(require.resolve('./long')); + }); + + describe('', function () { + this.tags('ciGroup13'); + + loadTestFile(require.resolve('./text')); + loadTestFile(require.resolve('./text_array')); + }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts index 6eb74af91060..719ae136dc56 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts @@ -9,33 +9,38 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { describe('detection engine api security and spaces enabled', function () { - this.tags('ciGroup11'); + describe('', function () { + this.tags('ciGroup11'); - loadTestFile(require.resolve('./add_actions')); - loadTestFile(require.resolve('./add_prepackaged_rules')); - loadTestFile(require.resolve('./create_rules')); - loadTestFile(require.resolve('./create_rules_bulk')); - loadTestFile(require.resolve('./create_threat_matching')); - loadTestFile(require.resolve('./create_exceptions')); - loadTestFile(require.resolve('./delete_rules')); - loadTestFile(require.resolve('./delete_rules_bulk')); - loadTestFile(require.resolve('./exception_operators_data_types/index')); - loadTestFile(require.resolve('./export_rules')); - loadTestFile(require.resolve('./find_rules')); - loadTestFile(require.resolve('./find_statuses')); - loadTestFile(require.resolve('./generating_signals')); - loadTestFile(require.resolve('./get_prepackaged_rules_status')); - loadTestFile(require.resolve('./import_rules')); - loadTestFile(require.resolve('./read_rules')); - loadTestFile(require.resolve('./update_rules')); - loadTestFile(require.resolve('./update_rules_bulk')); - loadTestFile(require.resolve('./patch_rules_bulk')); - loadTestFile(require.resolve('./patch_rules')); - loadTestFile(require.resolve('./query_signals')); - loadTestFile(require.resolve('./open_close_signals')); - loadTestFile(require.resolve('./get_signals_migration_status')); - loadTestFile(require.resolve('./create_signals_migrations')); - loadTestFile(require.resolve('./finalize_signals_migrations')); - loadTestFile(require.resolve('./delete_signals_migrations')); + loadTestFile(require.resolve('./add_actions')); + loadTestFile(require.resolve('./add_prepackaged_rules')); + loadTestFile(require.resolve('./create_rules')); + loadTestFile(require.resolve('./create_rules_bulk')); + loadTestFile(require.resolve('./create_threat_matching')); + loadTestFile(require.resolve('./create_exceptions')); + loadTestFile(require.resolve('./delete_rules')); + loadTestFile(require.resolve('./delete_rules_bulk')); + loadTestFile(require.resolve('./export_rules')); + loadTestFile(require.resolve('./find_rules')); + loadTestFile(require.resolve('./find_statuses')); + loadTestFile(require.resolve('./generating_signals')); + loadTestFile(require.resolve('./get_prepackaged_rules_status')); + loadTestFile(require.resolve('./import_rules')); + loadTestFile(require.resolve('./read_rules')); + loadTestFile(require.resolve('./update_rules')); + loadTestFile(require.resolve('./update_rules_bulk')); + loadTestFile(require.resolve('./patch_rules_bulk')); + loadTestFile(require.resolve('./patch_rules')); + loadTestFile(require.resolve('./query_signals')); + loadTestFile(require.resolve('./open_close_signals')); + loadTestFile(require.resolve('./get_signals_migration_status')); + loadTestFile(require.resolve('./create_signals_migrations')); + loadTestFile(require.resolve('./finalize_signals_migrations')); + loadTestFile(require.resolve('./delete_signals_migrations')); + }); + + describe('', function () { + loadTestFile(require.resolve('./exception_operators_data_types/index')); + }); }); }; diff --git a/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts b/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts index 4948bee7e6f5..83c4e5a48b89 100644 --- a/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts +++ b/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('encryptedSavedObjects', function encryptedSavedObjectsSuite() { - this.tags('ciGroup2'); + this.tags('ciGroup13'); loadTestFile(require.resolve('./encrypted_saved_objects_api')); }); } diff --git a/x-pack/test/functional/apps/api_keys/feature_controls/index.ts b/x-pack/test/functional/apps/api_keys/feature_controls/index.ts index 169b5c7fb0a7..4cd95e5966bb 100644 --- a/x-pack/test/functional/apps/api_keys/feature_controls/index.ts +++ b/x-pack/test/functional/apps/api_keys/feature_controls/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('feature controls', function () { - this.tags(['ciGroup2']); + this.tags(['ciGroup8']); loadTestFile(require.resolve('./api_keys_security')); }); diff --git a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts index e7be2cb48ce3..89690829a0d3 100644 --- a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts +++ b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('feature controls', function () { - this.tags(['ciGroup2']); + this.tags(['ciGroup8']); loadTestFile(require.resolve('./ccr_security')); }); diff --git a/x-pack/test/functional/apps/dev_tools/index.ts b/x-pack/test/functional/apps/dev_tools/index.ts index 767829d4494b..121d9effc2b6 100644 --- a/x-pack/test/functional/apps/dev_tools/index.ts +++ b/x-pack/test/functional/apps/dev_tools/index.ts @@ -7,7 +7,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('console', function () { - this.tags('ciGroup10'); + this.tags('ciGroup13'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./searchprofiler_editor')); diff --git a/x-pack/test/functional/apps/grok_debugger/index.js b/x-pack/test/functional/apps/grok_debugger/index.js index 75c05f35abd2..948509f650e9 100644 --- a/x-pack/test/functional/apps/grok_debugger/index.js +++ b/x-pack/test/functional/apps/grok_debugger/index.js @@ -6,7 +6,7 @@ export default function ({ loadTestFile }) { describe('logstash', function () { - this.tags('ciGroup2'); + this.tags('ciGroup13'); loadTestFile(require.resolve('./grok_debugger')); }); diff --git a/x-pack/test/functional/apps/index_management/index.ts b/x-pack/test/functional/apps/index_management/index.ts index 97b23cbf82c3..4b585b4d698d 100644 --- a/x-pack/test/functional/apps/index_management/index.ts +++ b/x-pack/test/functional/apps/index_management/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext) => { describe('Index Management app', function () { - this.tags('ciGroup3'); + this.tags('ciGroup13'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./home_page')); }); diff --git a/x-pack/test/functional_cors/tests/index.ts b/x-pack/test/functional_cors/tests/index.ts index 7e16e1339b1e..673cb464c860 100644 --- a/x-pack/test/functional_cors/tests/index.ts +++ b/x-pack/test/functional_cors/tests/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Kibana cors', function () { - this.tags('ciGroup2'); + this.tags('ciGroup12'); loadTestFile(require.resolve('./cors')); }); } diff --git a/x-pack/test/licensing_plugin/public/index.ts b/x-pack/test/licensing_plugin/public/index.ts index 268a74c56bd7..e771098ecd36 100644 --- a/x-pack/test/licensing_plugin/public/index.ts +++ b/x-pack/test/licensing_plugin/public/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../services'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile }: FtrProviderContext) { describe('Licensing plugin public client', function () { - this.tags('ciGroup2'); + this.tags('ciGroup5'); loadTestFile(require.resolve('./feature_usage')); // MUST BE LAST! CHANGES LICENSE TYPE! loadTestFile(require.resolve('./updates')); diff --git a/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts b/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts index c73820536120..4965e1aa7d2d 100644 --- a/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('event_log', function taskManagerSuite() { - this.tags('ciGroup2'); + this.tags('ciGroup6'); loadTestFile(require.resolve('./public_api_integration')); loadTestFile(require.resolve('./service_api_integration')); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts index c1e7aad8ac36..69fbb6be3ad5 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('task_manager', function taskManagerSuite() { - this.tags('ciGroup2'); + this.tags('ciGroup12'); loadTestFile(require.resolve('./health_route')); loadTestFile(require.resolve('./task_management')); loadTestFile(require.resolve('./task_management_removed_types')); diff --git a/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts b/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts index 648890a2b543..302ddf071bc3 100644 --- a/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts +++ b/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts @@ -14,7 +14,7 @@ export default function ({ loadTestFile }: { loadTestFile: (file: string) => voi * worth keeping around for future use, rather than being rewritten time and time again. */ describe.skip('task_manager_perf', function taskManagerSuite() { - this.tags('ciGroup2'); + this.tags('ciGroup12'); loadTestFile(require.resolve('./task_manager_perf_integration')); }); } diff --git a/x-pack/test/plugin_functional/test_suites/global_search/index.ts b/x-pack/test/plugin_functional/test_suites/global_search/index.ts index f3557ee8cc8d..f05aebd26cc8 100644 --- a/x-pack/test/plugin_functional/test_suites/global_search/index.ts +++ b/x-pack/test/plugin_functional/test_suites/global_search/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('GlobalSearch API', function () { - this.tags('ciGroup10'); + this.tags('ciGroup7'); loadTestFile(require.resolve('./global_search_providers')); loadTestFile(require.resolve('./global_search_bar')); }); From 0921a7a1e1463023c2a2ed457256e70bbda99d41 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 16 Dec 2020 10:10:39 -0800 Subject: [PATCH 04/38] [backportrc] Adds 7.11 branch and bumps 7.x (#86131) Signed-off-by: Tyler Smalley --- .backportrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.backportrc.json b/.backportrc.json index a97c82ca0efa..e44d3ce11429 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -3,6 +3,7 @@ "targetBranchChoices": [ { "name": "master", "checked": true }, { "name": "7.x", "checked": true }, + "7.11", "7.10", "7.9", "7.8", @@ -28,7 +29,7 @@ "targetPRLabels": ["backport"], "branchLabelMapping": { "^v8.0.0$": "master", - "^v7.11.0$": "7.x", + "^v7.12.0$": "7.x", "^v(\\d+).(\\d+).\\d+$": "$1.$2" } } From 4b2c9de638f3c051a0dd0b30f78a5ce5c61a5944 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 16 Dec 2020 11:21:04 -0700 Subject: [PATCH 05/38] [Maps] convert MBMap component to TS (#85192) * [Maps] convert MBMap component to TS * clean up imports messed up by eslint fix Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../maps/public/actions/map_actions.ts | 13 +- .../map_container/map_container.tsx | 1 - .../mb_map/get_initial_view.ts | 2 +- .../mb_map/{index.js => index.ts} | 21 ++- .../mb_map/{mb_map.js => mb_map.tsx} | 155 +++++++++++++----- 5 files changed, 135 insertions(+), 57 deletions(-) rename x-pack/plugins/maps/public/connected_components/mb_map/{index.js => index.ts} (74%) rename x-pack/plugins/maps/public/connected_components/mb_map/{mb_map.js => mb_map.tsx} (74%) diff --git a/x-pack/plugins/maps/public/actions/map_actions.ts b/x-pack/plugins/maps/public/actions/map_actions.ts index f26b00cec9fa..6dd8db4799d4 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.ts +++ b/x-pack/plugins/maps/public/actions/map_actions.ts @@ -51,6 +51,7 @@ import { addLayer, addLayerWithoutDataSync } from './layer_actions'; import { MapSettings } from '../reducers/map'; import { DrawState, + MapCenter, MapCenterAndZoom, MapExtent, MapRefreshConfig, @@ -59,6 +60,12 @@ import { INITIAL_LOCATION } from '../../common/constants'; import { scaleBounds } from '../../common/elasticsearch_util'; import { cleanTooltipStateForLayer } from './tooltip_actions'; +export interface MapExtentState { + zoom: number; + extent: MapExtent; + center: MapCenter; +} + export function setMapInitError(errorMessage: string) { return { type: SET_MAP_INIT_ERROR, @@ -125,13 +132,13 @@ export function mapDestroyed() { }; } -export function mapExtentChanged(newMapConstants: { zoom: number; extent: MapExtent }) { +export function mapExtentChanged(mapExtentState: MapExtentState) { return async ( dispatch: ThunkDispatch, getState: () => MapStoreState ) => { const dataFilters = getDataFilters(getState()); - const { extent, zoom: newZoom } = newMapConstants; + const { extent, zoom: newZoom } = mapExtentState; const { buffer, zoom: currentZoom } = dataFilters; if (extent) { @@ -162,7 +169,7 @@ export function mapExtentChanged(newMapConstants: { zoom: number; extent: MapExt type: MAP_EXTENT_CHANGED, mapState: { ...dataFilters, - ...newMapConstants, + ...mapExtentState, }, }); diff --git a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index 9a5110a0c24d..d7881d5f84bd 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -12,7 +12,6 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; -// @ts-expect-error import { MBMap } from '../mb_map'; // @ts-expect-error import { WidgetOverlay } from '../widget_overlay'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/get_initial_view.ts b/x-pack/plugins/maps/public/connected_components/mb_map/get_initial_view.ts index 853819eb289a..8fb4bfdfc1f4 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/get_initial_view.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/get_initial_view.ts @@ -9,7 +9,7 @@ import { Goto, MapCenterAndZoom } from '../../../common/descriptor_types'; import { MapSettings } from '../../reducers/map'; export async function getInitialView( - goto: Goto | null, + goto: Goto | null | undefined, settings: MapSettings ): Promise { if (settings.initialLocation === INITIAL_LOCATION.FIXED_LOCATION) { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/index.js b/x-pack/plugins/maps/public/connected_components/mb_map/index.ts similarity index 74% rename from x-pack/plugins/maps/public/connected_components/mb_map/index.js rename to x-pack/plugins/maps/public/connected_components/mb_map/index.ts index cccd5e571d3e..d43f357ccbcb 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/index.js +++ b/x-pack/plugins/maps/public/connected_components/mb_map/index.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AnyAction } from 'redux'; +import { ThunkDispatch } from 'redux-thunk'; import { connect } from 'react-redux'; import { MBMap } from './mb_map'; import { @@ -14,6 +16,7 @@ import { clearMouseCoordinates, clearGoto, setMapInitError, + MapExtentState, } from '../../actions'; import { getLayerList, @@ -26,10 +29,10 @@ import { getSpatialFiltersLayer, getMapSettings, } from '../../selectors/map_selectors'; - import { getInspectorAdapters } from '../../reducers/non_serializable_instances'; +import { MapStoreState } from '../../reducers/store'; -function mapStateToProps(state = {}) { +function mapStateToProps(state: MapStoreState) { return { isMapReady: getMapReady(state), settings: getMapSettings(state), @@ -44,20 +47,20 @@ function mapStateToProps(state = {}) { }; } -function mapDispatchToProps(dispatch) { +function mapDispatchToProps(dispatch: ThunkDispatch) { return { - extentChanged: (e) => { - dispatch(mapExtentChanged(e)); + extentChanged: (mapExtentState: MapExtentState) => { + dispatch(mapExtentChanged(mapExtentState)); }, - onMapReady: (e) => { + onMapReady: (mapExtentState: MapExtentState) => { dispatch(clearGoto()); - dispatch(mapExtentChanged(e)); + dispatch(mapExtentChanged(mapExtentState)); dispatch(mapReady()); }, onMapDestroyed: () => { dispatch(mapDestroyed()); }, - setMouseCoordinates: ({ lat, lon }) => { + setMouseCoordinates: ({ lat, lon }: { lat: number; lon: number }) => { dispatch(setMouseCoordinates({ lat, lon })); }, clearMouseCoordinates: () => { @@ -66,7 +69,7 @@ function mapDispatchToProps(dispatch) { clearGoto: () => { dispatch(clearGoto()); }, - setMapInitError(errorMessage) { + setMapInitError(errorMessage: string) { dispatch(setMapInitError(errorMessage)); }, }; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.js b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx similarity index 74% rename from x-pack/plugins/maps/public/connected_components/mb_map/mb_map.js rename to x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index 0ea40f6e3182..401d45eefdd1 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.js +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -5,39 +5,93 @@ */ import _ from 'lodash'; -import React from 'react'; -import { ResizeChecker } from '../../../../../../src/plugins/kibana_utils/public'; -import { removeOrphanedSourcesAndLayers, addSpritesheetToMap } from './utils'; -import { syncLayerOrder } from './sort_layers'; -import { getGlyphUrl, isRetina } from '../../meta'; -import { - DECIMAL_DEGREES_PRECISION, - KBN_TOO_MANY_FEATURES_IMAGE_ID, - ZOOM_PRECISION, -} from '../../../common/constants'; +import React, { Component } from 'react'; +import { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; +// @ts-expect-error import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; -import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; -import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; +// @ts-expect-error import { spritesheet } from '@elastic/maki'; import sprites1 from '@elastic/maki/dist/sprite@1.png'; import sprites2 from '@elastic/maki/dist/sprite@2.png'; +import { Adapters } from 'src/plugins/inspector/public'; +import { Filter } from 'src/plugins/data/public'; +import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; +// @ts-expect-error import { DrawControl } from './draw_control'; +// @ts-expect-error import { TooltipControl } from './tooltip_control'; import { clampToLatBounds, clampToLonBounds } from '../../../common/elasticsearch_util'; import { getInitialView } from './get_initial_view'; import { getPreserveDrawingBuffer } from '../../kibana_services'; +import { ILayer } from '../../classes/layers/layer'; +import { MapSettings } from '../../reducers/map'; +import { Goto } from '../../../common/descriptor_types'; +import { + DECIMAL_DEGREES_PRECISION, + KBN_TOO_MANY_FEATURES_IMAGE_ID, + RawValue, + ZOOM_PRECISION, +} from '../../../common/constants'; +import { getGlyphUrl, isRetina } from '../../meta'; +import { syncLayerOrder } from './sort_layers'; +// @ts-expect-error +import { removeOrphanedSourcesAndLayers, addSpritesheetToMap } from './utils'; +import { ResizeChecker } from '../../../../../../src/plugins/kibana_utils/public'; +import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; +import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; +import { MapExtentState } from '../../actions'; +// @ts-expect-error +import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; +// @ts-expect-error +import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; mapboxgl.workerUrl = mbWorkerUrl; mapboxgl.setRTLTextPlugin(mbRtlPlugin); -export class MBMap extends React.Component { - state = { +interface Props { + isMapReady: boolean; + settings: MapSettings; + layerList: ILayer[]; + spatialFiltersLayer: ILayer; + goto?: Goto | null; + inspectorAdapters: Adapters; + scrollZoom: boolean; + disableInteractive: boolean; + disableTooltipControl: boolean; + hideViewControl: boolean; + extentChanged: (mapExtentState: MapExtentState) => void; + onMapReady: (mapExtentState: MapExtentState) => void; + onMapDestroyed: () => void; + setMouseCoordinates: ({ lat, lon }: { lat: number; lon: number }) => void; + clearMouseCoordinates: () => void; + clearGoto: () => void; + setMapInitError: (errorMessage: string) => void; + addFilters: ((filters: Filter[]) => Promise) | null; + getFilterActions?: () => Promise; + getActionContext?: () => ActionExecutionContext; + onSingleValueTrigger?: (actionId: string, key: string, value: RawValue) => void; + geoFields: GeoFieldWithIndex[]; + renderTooltipContent?: RenderToolTipContent; +} + +interface State { + prevLayerList: ILayer[] | undefined; + hasSyncedLayerList: boolean; + mbMap: MapboxMap | undefined; +} + +export class MBMap extends Component { + private _checker?: ResizeChecker; + private _isMounted: boolean = false; + private _containerRef: HTMLDivElement | null = null; + + state: State = { prevLayerList: undefined, hasSyncedLayerList: false, mbMap: undefined, }; - static getDerivedStateFromProps(nextProps, prevState) { + static getDerivedStateFromProps(nextProps: Props, prevState: State) { const nextLayerList = nextProps.layerList; if (nextLayerList !== prevState.prevLayerList) { return { @@ -69,13 +123,13 @@ export class MBMap extends React.Component { } if (this.state.mbMap) { this.state.mbMap.remove(); - this.state.mbMap = null; + this.state.mbMap = undefined; } this.props.onMapDestroyed(); } _debouncedSync = _.debounce(() => { - if (this._isMounted && this.props.isMapReady) { + if (this._isMounted && this.props.isMapReady && this.state.mbMap) { if (!this.state.hasSyncedLayerList) { this.setState( { @@ -93,9 +147,9 @@ export class MBMap extends React.Component { }, 256); _getMapState() { - const zoom = this.state.mbMap.getZoom(); - const mbCenter = this.state.mbMap.getCenter(); - const mbBounds = this.state.mbMap.getBounds(); + const zoom = this.state.mbMap!.getZoom(); + const mbCenter = this.state.mbMap!.getCenter(); + const mbBounds = this.state.mbMap!.getBounds(); return { zoom: _.round(zoom, ZOOM_PRECISION), center: { @@ -111,7 +165,7 @@ export class MBMap extends React.Component { }; } - async _createMbMapInstance() { + async _createMbMapInstance(): Promise { const initialView = await getInitialView(this.props.goto, this.props.settings); return new Promise((resolve) => { const mbStyle = { @@ -121,9 +175,9 @@ export class MBMap extends React.Component { glyphs: getGlyphUrl(), }; - const options = { + const options: MapboxOptions = { attributionControl: false, - container: this.refs.mapContainer, + container: this._containerRef!, style: mbStyle, scrollZoom: this.props.scrollZoom, preserveDrawingBuffer: getPreserveDrawingBuffer(), @@ -155,9 +209,10 @@ export class MBMap extends React.Component { }; tooManyFeaturesImage.src = tooManyFeaturesImageSrc; - let emptyImage; - mbMap.on('styleimagemissing', (e) => { + let emptyImage: HTMLImageElement; + mbMap.on('styleimagemissing', (e: unknown) => { if (emptyImage) { + // @ts-expect-error mbMap.addImage(e.id, emptyImage); } }); @@ -173,7 +228,7 @@ export class MBMap extends React.Component { } async _initializeMap() { - let mbMap; + let mbMap: MapboxMap; try { mbMap = await this._createMbMapInstance(); } catch (error) { @@ -186,19 +241,19 @@ export class MBMap extends React.Component { } this.setState({ mbMap }, () => { - this._loadMakiSprites(); + this._loadMakiSprites(mbMap); this._initResizerChecker(); - this._registerMapEventListeners(); + this._registerMapEventListeners(mbMap); this.props.onMapReady(this._getMapState()); }); } - _registerMapEventListeners() { + _registerMapEventListeners(mbMap: MapboxMap) { // moveend callback is debounced to avoid updating map extent state while map extent is still changing // moveend is fired while the map extent is still changing in the following scenarios // 1) During opening/closing of layer details panel, the EUI animation results in 8 moveend events // 2) Setting map zoom and center from goto is done in 2 API calls, resulting in 2 moveend events - this.state.mbMap.on( + mbMap.on( 'moveend', _.debounce(() => { this.props.extentChanged(this._getMapState()); @@ -206,14 +261,14 @@ export class MBMap extends React.Component { ); // Attach event only if view control is visible, which shows lat/lon if (!this.props.hideViewControl) { - const throttledSetMouseCoordinates = _.throttle((e) => { + const throttledSetMouseCoordinates = _.throttle((e: MapMouseEvent) => { this.props.setMouseCoordinates({ lat: e.lngLat.lat, lon: e.lngLat.lng, }); }, 100); - this.state.mbMap.on('mousemove', throttledSetMouseCoordinates); - this.state.mbMap.on('mouseout', () => { + mbMap.on('mousemove', throttledSetMouseCoordinates); + mbMap.on('mouseout', () => { throttledSetMouseCoordinates.cancel(); // cancel any delayed setMouseCoordinates invocations this.props.clearMouseCoordinates(); }); @@ -221,29 +276,31 @@ export class MBMap extends React.Component { } _initResizerChecker() { - this._checker = new ResizeChecker(this.refs.mapContainer); + this._checker = new ResizeChecker(this._containerRef!); this._checker.on('resize', () => { - this.state.mbMap.resize(); + if (this.state.mbMap) { + this.state.mbMap.resize(); + } }); } - _loadMakiSprites() { + _loadMakiSprites(mbMap: MapboxMap) { const sprites = isRetina() ? sprites2 : sprites1; const json = isRetina() ? spritesheet[2] : spritesheet[1]; - addSpritesheetToMap(json, sprites, this.state.mbMap); + addSpritesheetToMap(json, sprites, mbMap); } _syncMbMapWithMapState = () => { const { isMapReady, goto, clearGoto } = this.props; - if (!isMapReady || !goto) { + if (!isMapReady || !goto || !this.state.mbMap) { return; } clearGoto(); if (goto.bounds) { - //clamping ot -89/89 latitudes since Mapboxgl does not seem to handle bounds that contain the poles (logs errors to the console when using -90/90) + // clamping ot -89/89 latitudes since Mapboxgl does not seem to handle bounds that contain the poles (logs errors to the console when using -90/90) const lnLatBounds = new mapboxgl.LngLatBounds( new mapboxgl.LngLat( clampToLonBounds(goto.bounds.minLon), @@ -254,8 +311,8 @@ export class MBMap extends React.Component { clampToLatBounds(goto.bounds.maxLat) ) ); - //maxZoom ensure we're not zooming in too far on single points or small shapes - //the padding is to avoid too tight of a fit around edges + // maxZoom ensure we're not zooming in too far on single points or small shapes + // the padding is to avoid too tight of a fit around edges this.state.mbMap.fitBounds(lnLatBounds, { maxZoom: 17, padding: 16 }); } else if (goto.center) { this.state.mbMap.setZoom(goto.center.zoom); @@ -267,6 +324,10 @@ export class MBMap extends React.Component { }; _syncMbMapWithLayerList = () => { + if (!this.state.mbMap) { + return; + } + removeOrphanedSourcesAndLayers( this.state.mbMap, this.props.layerList, @@ -277,7 +338,7 @@ export class MBMap extends React.Component { }; _syncMbMapWithInspector = () => { - if (!this.props.inspectorAdapters.map) { + if (!this.props.inspectorAdapters.map || !this.state.mbMap) { return; } @@ -292,6 +353,10 @@ export class MBMap extends React.Component { }; _syncSettings() { + if (!this.state.mbMap) { + return; + } + let zoomRangeChanged = false; if (this.props.settings.minZoom !== this.state.mbMap.getMinZoom()) { this.state.mbMap.setMinZoom(this.props.settings.minZoom); @@ -312,6 +377,10 @@ export class MBMap extends React.Component { } } + _setContainerRef = (element: HTMLDivElement) => { + this._containerRef = element; + }; + render() { let drawControl; let tooltipControl; @@ -333,7 +402,7 @@ export class MBMap extends React.Component {
{drawControl} From 272b2d06289bb9fcad82462976aafca4b6b671fb Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 16 Dec 2020 11:21:51 -0700 Subject: [PATCH 06/38] [KQL] Fix handling of backslashes when autocompleting values (#85457) * [KQL] Fix handling of backslashes when autocompleting values * Revert change to test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../kql_query_suggestion/lib/escape_kuery.test.ts | 7 +++++++ .../providers/kql_query_suggestion/lib/escape_kuery.ts | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.test.ts b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.test.ts index a4a1d977a207..906319865c21 100644 --- a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.test.ts +++ b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.test.ts @@ -14,6 +14,13 @@ describe('Kuery escape', () => { expect(escapeQuotes(value)).toBe(expected); }); + test('should escape backslashes and quotes', () => { + const value = 'Backslashes \\" in the middle and ends with quotes \\"'; + const expected = 'Backslashes \\\\\\" in the middle and ends with quotes \\\\\\"'; + + expect(escapeQuotes(value)).toBe(expected); + }); + test('should escape special characters', () => { const value = `This \\ has (a lot of) characters, don't you *think*? "Yes."`; const expected = `This \\\\ has \\(a lot of\\) \\ characters, don't you \\*think\\*? \\"Yes.\\"`; diff --git a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.ts b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.ts index 2ddb3966bb56..6ccf8f577fbe 100644 --- a/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.ts +++ b/x-pack/plugins/data_enhanced/public/autocomplete/providers/kql_query_suggestion/lib/escape_kuery.ts @@ -6,8 +6,12 @@ import { flow } from 'lodash'; +/** + * Escapes backslashes and double-quotes. (Useful when putting a string in quotes to use as a value + * in a KQL expression. See the QuotedCharacter rule in kuery.peg.) + */ export function escapeQuotes(str: string) { - return str.replace(/"/g, '\\"'); + return str.replace(/[\\"]/g, '\\$&'); } export const escapeKuery = flow(escapeSpecialCharacters, escapeAndOr, escapeNot, escapeWhitespace); From 4e6189436e7c0a2f523b80588e9643421162c03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Wed, 16 Dec 2020 13:35:53 -0500 Subject: [PATCH 07/38] Fix codeowners file for alerting stack alerts (#86148) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0993876f98a6..94afc5dd22ba 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -258,7 +258,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services /docs/user/alerting/ @elastic/kibana-alerting-services /docs/management/alerting/ @elastic/kibana-alerting-services -#CC# /x-pack/plugins/stack_alerts @elastic/kibana-alerting-services +#CC# /x-pack/plugins/stack_alerts/ @elastic/kibana-alerting-services # Enterprise Search # Shared From 42ee51b67d2da36795499b360487cc071e153c48 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 16 Dec 2020 13:41:35 -0500 Subject: [PATCH 08/38] Update index.tsx to note use can go to docs for DEB/RPM Agent deploy instructions (#86128) --- .../fleet/components/enrollment_instructions/manual/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/enrollment_instructions/manual/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/enrollment_instructions/manual/index.tsx index d0145601b8a0..4580f20003ba 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/enrollment_instructions/manual/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/enrollment_instructions/manual/index.tsx @@ -72,7 +72,7 @@ export const ManualInstructions: React.FunctionComponent = ({ Date: Wed, 16 Dec 2020 13:44:37 -0500 Subject: [PATCH 09/38] [Security Solution] Add Pinned Event tabs on Timeline (#85905) * wip * finish drag & drop from pinned events + fix top n * Fix types * update cypress * Fix unit tests * fix cypress test * fix filter out/in * remove unused components * fix pagination cypress test * cypress timelines selectors * review and skip cypress test * more to skip * fix type * skip case * Fix types * Fix tests * skip resolver * only query pinned events Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Christos Nasikas Co-authored-by: Angela Chuang --- .../cypress/integration/alerts.spec.ts | 15 +- .../alerts_detection_exceptions.spec.ts | 2 +- ...ts_detection_rules_indicator_match.spec.ts | 2 +- .../alerts_detection_rules_prebuilt.spec.ts | 4 +- .../cypress/integration/cases.spec.ts | 2 +- .../integration/fields_browser.spec.ts | 4 +- .../cypress/integration/pagination.spec.ts | 37 ++- .../cypress/integration/sourcerer.spec.ts | 2 +- .../integration/timeline_creation.spec.ts | 4 +- .../timeline_toggle_column.spec.ts | 2 +- .../cypress/screens/alerts.ts | 8 +- .../cypress/screens/timeline.ts | 4 +- .../cypress/tasks/pagination.ts | 4 +- .../cypress/tasks/timeline.ts | 3 +- .../draggable_wrapper_hover_content.test.tsx | 11 +- .../draggable_wrapper_hover_content.tsx | 12 +- .../events_viewer/events_viewer.tsx | 22 +- .../public/common/store/app/selectors.ts | 2 +- .../flyout/bottom_bar/index.test.tsx | 69 ++++- .../components/flyout/bottom_bar/index.tsx | 41 ++- .../components/flyout/header/index.tsx | 8 +- .../timelines/components/flyout/index.tsx | 7 +- .../timelines/components/flyout/selectors.ts | 2 + .../open_timeline/note_previews/index.tsx | 76 +++-- .../body/data_driven_columns/index.tsx | 9 +- .../body/events/event_column_view.tsx | 5 +- .../components/timeline/body/events/index.tsx | 7 +- .../timeline/body/events/stateful_event.tsx | 5 +- .../components/timeline/body/index.test.tsx | 2 + .../components/timeline/body/index.tsx | 5 + .../components/timeline/header/index.tsx | 4 +- .../components/timeline/index.test.tsx | 10 +- .../timeline/notes_tab_content/index.tsx | 11 +- .../__snapshots__/index.test.tsx.snap | 149 +++++++++ .../pinned_tab_content/index.test.tsx | 133 ++++++++ .../timeline/pinned_tab_content/index.tsx | 283 ++++++++++++++++++ .../__snapshots__/index.test.tsx.snap | 2 + .../timeline/query_tab_content/index.test.tsx | 3 + .../timeline/query_tab_content/index.tsx | 43 +-- .../search_or_filter/search_or_filter.tsx | 3 + .../timeline/tabs_content/index.tsx | 85 ++++-- .../timeline/tabs_content/selectors.ts | 7 + .../timeline/epic_local_storage.test.tsx | 3 + .../events/all/query.events_all.dsl.ts | 22 +- .../apps/endpoint/resolver.ts | 2 +- 45 files changed, 954 insertions(+), 182 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts index c2fb7a851eef..a40c79acd8fd 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts.spec.ts @@ -43,7 +43,7 @@ describe('Alerts', () => { removeSignalsIndex(); }); - it('Closes and opens alerts', () => { + it.skip('Closes and opens alerts', () => { waitForAlertsPanelToBeLoaded(); waitForAlertsToBeLoaded(); @@ -117,14 +117,13 @@ describe('Alerts', () => { `Showing ${expectedNumberOfOpenedAlerts.toString()} alerts` ); - cy.get('[data-test-subj="server-side-event-count"]').should( - 'have.text', - expectedNumberOfOpenedAlerts.toString() - ); + cy.get( + '[data-test-subj="events-viewer-panel"] [data-test-subj="server-side-event-count"]' + ).should('have.text', expectedNumberOfOpenedAlerts.toString()); }); }); - it('Closes one alert when more than one opened alerts are selected', () => { + it.skip('Closes one alert when more than one opened alerts are selected', () => { waitForAlertsToBeLoaded(); cy.get(ALERTS_COUNT) @@ -173,7 +172,7 @@ describe('Alerts', () => { removeSignalsIndex(); }); - it('Open one alert when more than one closed alerts are selected', () => { + it.skip('Open one alert when more than one closed alerts are selected', () => { waitForAlerts(); goToClosedAlerts(); waitForAlertsToBeLoaded(); @@ -225,7 +224,7 @@ describe('Alerts', () => { removeSignalsIndex(); }); - it('Mark one alert in progress when more than one open alerts are selected', () => { + it.skip('Mark one alert in progress when more than one open alerts are selected', () => { waitForAlerts(); waitForAlertsToBeLoaded(); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_exceptions.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_exceptions.spec.ts index f98a51a3e418..9137d6383a15 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_exceptions.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_exceptions.spec.ts @@ -34,7 +34,7 @@ import { refreshPage } from '../tasks/security_header'; import { DETECTIONS_URL } from '../urls/navigation'; -describe('Exceptions', () => { +describe.skip('Exceptions', () => { const NUMBER_OF_AUDITBEAT_EXCEPTIONS_ALERTS = '1'; beforeEach(() => { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_indicator_match.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_indicator_match.spec.ts index d447c3c8862c..cbc4f2157786 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_indicator_match.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_indicator_match.spec.ts @@ -101,7 +101,7 @@ describe('Detection rules, Indicator Match', () => { removeSignalsIndex(); }); - it('Creates and activates a new Indicator Match rule', () => { + it.skip('Creates and activates a new Indicator Match rule', () => { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_prebuilt.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_prebuilt.spec.ts index b76e4b108a16..e1451d78192b 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_prebuilt.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_prebuilt.spec.ts @@ -46,7 +46,7 @@ describe('Alerts rules, prebuilt rules', () => { esArchiverUnloadEmptyKibana(); }); - it('Loads prebuilt rules', () => { + it.skip('Loads prebuilt rules', () => { const expectedNumberOfRules = totalNumberOfPrebuiltRules; const expectedElasticRulesBtnText = `Elastic rules (${expectedNumberOfRules})`; @@ -78,7 +78,7 @@ describe('Alerts rules, prebuilt rules', () => { }); }); -describe('Deleting prebuilt rules', () => { +describe.skip('Deleting prebuilt rules', () => { beforeEach(() => { const expectedNumberOfRules = totalNumberOfPrebuiltRules; const expectedElasticRulesBtnText = `Elastic rules (${expectedNumberOfRules})`; diff --git a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts index 909bf690d467..b755de8efe75 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts @@ -51,7 +51,7 @@ import { closeTimeline } from '../tasks/timeline'; import { CASES_URL } from '../urls/navigation'; -describe('Cases', () => { +describe.skip('Cases', () => { const mycase = { ...case1 }; before(() => { diff --git a/x-pack/plugins/security_solution/cypress/integration/fields_browser.spec.ts b/x-pack/plugins/security_solution/cypress/integration/fields_browser.spec.ts index e09d62d2a87d..cb8949402b98 100644 --- a/x-pack/plugins/security_solution/cypress/integration/fields_browser.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/fields_browser.spec.ts @@ -45,7 +45,7 @@ const defaultHeaders = [ ]; describe('Fields Browser', () => { - context('Fields Browser rendering', () => { + context.skip('Fields Browser rendering', () => { before(() => { loginAndWaitForPage(HOSTS_URL); openTimelineUsingToggle(); @@ -108,7 +108,7 @@ describe('Fields Browser', () => { }); }); - context('Editing the timeline', () => { + context.skip('Editing the timeline', () => { before(() => { loginAndWaitForPage(HOSTS_URL); openTimelineUsingToggle(); diff --git a/x-pack/plugins/security_solution/cypress/integration/pagination.spec.ts b/x-pack/plugins/security_solution/cypress/integration/pagination.spec.ts index fdccf164c746..d75573598251 100644 --- a/x-pack/plugins/security_solution/cypress/integration/pagination.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/pagination.spec.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PROCESS_NAME_FIELD } from '../screens/hosts/uncommon_processes'; +import { PROCESS_NAME_FIELD, UNCOMMON_PROCESSES_TABLE } from '../screens/hosts/uncommon_processes'; import { FIRST_PAGE_SELECTOR, THIRD_PAGE_SELECTOR } from '../screens/pagination'; import { waitForAuthenticationsToBeLoaded } from '../tasks/hosts/authentications'; @@ -27,28 +27,39 @@ describe('Pagination', () => { }); it('pagination updates results and page number', () => { - cy.get(FIRST_PAGE_SELECTOR).should('have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('have.class', 'euiPaginationButton-isActive'); - cy.get(PROCESS_NAME_FIELD) + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(PROCESS_NAME_FIELD) .first() .invoke('text') .then((processNameFirstPage) => { goToThirdPage(); waitForUncommonProcessesToBeLoaded(); cy.wait(1500); - cy.get(PROCESS_NAME_FIELD) + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(PROCESS_NAME_FIELD) .first() .invoke('text') .should((processNameSecondPage) => { expect(processNameFirstPage).not.to.eq(processNameSecondPage); }); }); - cy.get(FIRST_PAGE_SELECTOR).should('not.have.class', 'euiPaginationButton-isActive'); - cy.get(THIRD_PAGE_SELECTOR).should('have.class', 'euiPaginationButton-isActive'); + cy.wait(3000); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('not.have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(THIRD_PAGE_SELECTOR) + .should('have.class', 'euiPaginationButton-isActive'); }); it('pagination keeps track of page results when tabs change', () => { - cy.get(FIRST_PAGE_SELECTOR).should('have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('have.class', 'euiPaginationButton-isActive'); goToThirdPage(); waitForUncommonProcessesToBeLoaded(); @@ -72,12 +83,18 @@ describe('Pagination', () => { }); it('pagination resets results and page number to first page when refresh is clicked', () => { - cy.get(FIRST_PAGE_SELECTOR).should('have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('have.class', 'euiPaginationButton-isActive'); goToThirdPage(); waitForUncommonProcessesToBeLoaded(); - cy.get(FIRST_PAGE_SELECTOR).should('not.have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('not.have.class', 'euiPaginationButton-isActive'); refreshPage(); waitForUncommonProcessesToBeLoaded(); - cy.get(FIRST_PAGE_SELECTOR).should('have.class', 'euiPaginationButton-isActive'); + cy.get(UNCOMMON_PROCESSES_TABLE) + .find(FIRST_PAGE_SELECTOR) + .should('have.class', 'euiPaginationButton-isActive'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts b/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts index 4126bcfdbf0b..ead3fa617510 100644 --- a/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts @@ -89,7 +89,7 @@ describe('Sourcerer', () => { openSourcerer('timeline'); isCustomRadio(); }); - it('Selected index patterns are properly queried', () => { + it.skip('Selected index patterns are properly queried', () => { openTimelineUsingToggle(); populateTimeline(); openSourcerer('timeline'); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts index 65dce5717783..1fb751f344fd 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts @@ -11,7 +11,7 @@ import { NOTES_TAB_BUTTON, // NOTES_COUNT, NOTES_TEXT_AREA, - NOTE_BY_NOTE_ID, + NOTE_CONTENT, PIN_EVENT, TIMELINE_DESCRIPTION, TIMELINE_FILTER, @@ -104,7 +104,7 @@ describe.skip('Timelines', () => { getTimelineById(timelineId).then((singleTimeline) => { const noteId = singleTimeline!.body.data.getOneTimeline.notes[0].noteId; - cy.get(`${NOTE_BY_NOTE_ID(noteId)} p`).should('have.text', timeline.notes); + cy.get(NOTE_CONTENT(noteId)).should('have.text', timeline.notes); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_toggle_column.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_toggle_column.spec.ts index 8c416fd872a2..80693f3dd807 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_toggle_column.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_toggle_column.spec.ts @@ -75,7 +75,7 @@ describe('toggle column in timeline', () => { cy.get(ID_HEADER_FIELD).should('exist'); }); - it('adds the _id field to the timeline via drag and drop', () => { + it.skip('adds the _id field to the timeline via drag and drop', () => { expandFirstTimelineEventDetails(); dragAndDropIdToggleFieldToTimeline(); diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts.ts b/x-pack/plugins/security_solution/cypress/screens/alerts.ts index bc3be900284b..8c51a9b32c43 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts.ts @@ -6,9 +6,10 @@ export const ADD_EXCEPTION_BTN = '[data-test-subj="addExceptionButton"]'; -export const ALERTS = '[data-test-subj="event"]'; +export const ALERTS = '[data-test-subj="events-viewer-panel"] [data-test-subj="event"]'; -export const ALERTS_COUNT = '[data-test-subj="server-side-event-count"]'; +export const ALERTS_COUNT = + '[data-test-subj="events-viewer-panel"] [data-test-subj="server-side-event-count"]'; export const ALERT_CHECKBOX = '[data-test-subj="select-event-container"] .euiCheckbox__input'; @@ -45,7 +46,8 @@ export const MARK_ALERT_IN_PROGRESS_BTN = '[data-test-subj="in-progress-alert-st export const MARK_SELECTED_ALERTS_IN_PROGRESS_BTN = '[data-test-subj="markSelectedAlertsInProgressButton"]'; -export const NUMBER_OF_ALERTS = '[data-test-subj="local-events-count"]'; +export const NUMBER_OF_ALERTS = + '[data-test-subj="events-viewer-panel"] [data-test-subj="local-events-count"]'; export const OPEN_ALERT_BTN = '[data-test-subj="open-alert-status"]'; diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts index 4972cba93758..6f31a470dd61 100644 --- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts @@ -53,7 +53,9 @@ export const LOCKED_ICON = '[data-test-subj="timeline-date-picker-lock-button"]' export const NOTES = '[data-test-subj="note-card-body"]'; -export const NOTE_BY_NOTE_ID = (noteId: string) => `[data-test-subj="note-preview-${noteId}"]`; +const NOTE_BY_NOTE_ID = (noteId: string) => `[data-test-subj="note-preview-${noteId}"]`; + +export const NOTE_CONTENT = (noteId: string) => `${NOTE_BY_NOTE_ID(noteId)} p`; export const NOTES_TEXT_AREA = '[data-test-subj="add-a-note"] textarea'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/pagination.ts b/x-pack/plugins/security_solution/cypress/tasks/pagination.ts index 6b65d5181a7d..cdc0cf68e5b3 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/pagination.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/pagination.ts @@ -7,9 +7,9 @@ import { FIRST_PAGE_SELECTOR, THIRD_PAGE_SELECTOR } from '../screens/pagination'; export const goToFirstPage = () => { - cy.get(FIRST_PAGE_SELECTOR).click({ force: true }); + cy.get(FIRST_PAGE_SELECTOR).last().click({ force: true }); }; export const goToThirdPage = () => { - cy.get(THIRD_PAGE_SELECTOR).click({ force: true }); + cy.get(THIRD_PAGE_SELECTOR).last().click({ force: true }); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index b9703bad7705..fee1bc4ae689 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -118,6 +118,7 @@ export const closeTimeline = () => { export const createNewTimeline = () => { cy.get(TIMELINE_SETTINGS_ICON).filter(':visible').click({ force: true }); + cy.wait(1000); cy.get(CREATE_NEW_TIMELINE).should('be.visible'); cy.get(CREATE_NEW_TIMELINE).click(); }; @@ -140,7 +141,7 @@ export const markAsFavorite = () => { }; export const openTimelineFieldsBrowser = () => { - cy.get(TIMELINE_FIELDS_BUTTON).click({ force: true }); + cy.get(TIMELINE_FIELDS_BUTTON).first().click({ force: true }); }; export const openTimelineInspectButton = () => { diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.test.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.test.tsx index fd1c9e515bad..1cf03225cec0 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.test.tsx @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount, ReactWrapper } from 'enzyme'; import React from 'react'; +import { waitFor } from '@testing-library/react'; +import { mount, ReactWrapper } from 'enzyme'; import { coreMock } from '../../../../../../../src/core/public/mocks'; import { mockBrowserFields } from '../../containers/source/mock'; @@ -399,7 +400,9 @@ describe('DraggableWrapperHoverContent', () => { wrapper.find('[data-test-subj="add-to-timeline"]').first().simulate('click'); wrapper.update(); - expect(startDragToTimeline).toHaveBeenCalled(); + waitFor(() => { + expect(startDragToTimeline).toHaveBeenCalled(); + }); }); }); @@ -473,7 +476,9 @@ describe('DraggableWrapperHoverContent', () => { ); const button = wrapper.find(`[data-test-subj="show-top-field"]`).first(); button.simulate('mouseenter'); - expect(goGetTimelineId).toHaveBeenCalledWith(true); + waitFor(() => { + expect(goGetTimelineId).toHaveBeenCalledWith(true); + }); }); test(`invokes the toggleTopN function when the 'Show top field' button is clicked`, async () => { diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.tsx index 4210f85fe677..2d3fdb9cb942 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.tsx +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.tsx @@ -134,7 +134,6 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ ? SourcererScopeName.detections : SourcererScopeName.default; const { browserFields, indexPattern, selectedPatterns } = useSourcererScope(activeScope); - const handleStartDragToTimeline = useCallback(() => { startDragToTimeline(); if (closePopOver != null) { @@ -175,8 +174,11 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ } }, [closePopOver, field, value, filterManager, onFilterAdded]); - const handleGoGetTimelineId = useCallback(() => { - if (goGetTimelineId != null && timelineId == null) { + const isInit = useRef(true); + + useEffect(() => { + if (isInit.current && goGetTimelineId != null && timelineId == null) { + isInit.current = false; goGetTimelineId(true); } }, [goGetTimelineId, timelineId]); @@ -275,7 +277,6 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ data-test-subj="filter-for-value" iconType="magnifyWithPlus" onClick={filterForValue} - onMouseEnter={handleGoGetTimelineId} /> )} @@ -300,7 +301,6 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ data-test-subj="filter-out-value" iconType="magnifyWithMinus" onClick={filterOutValue} - onMouseEnter={handleGoGetTimelineId} /> )} @@ -324,7 +324,6 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ color="text" data-test-subj="add-to-timeline" iconType="timeline" - onClick={handleStartDragToTimeline} /> )} @@ -355,7 +354,6 @@ const DraggableWrapperHoverContentComponent: React.FC = ({ data-test-subj="show-top-field" iconType="visBarVertical" onClick={toggleTopN} - onMouseEnter={handleGoGetTimelineId} /> )} diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx index 56b0525ec624..515758965d6d 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx @@ -43,6 +43,7 @@ import { ExitFullScreen } from '../exit_full_screen'; import { useGlobalFullScreen } from '../../containers/use_full_screen'; import { TimelineExpandedEvent, TimelineId } from '../../../../common/types/timeline'; import { GraphOverlay } from '../../../timelines/components/graph_overlay'; +import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from '../../../timelines/components/timeline/styles'; export const EVENTS_VIEWER_HEADER_HEIGHT = 90; // px const UTILITY_BAR_HEIGHT = 19; // px @@ -74,7 +75,9 @@ const TitleFlexGroup = styled(EuiFlexGroup)` margin-top: 8px; `; -const EventsContainerLoading = styled.div` +const EventsContainerLoading = styled.div.attrs(({ className = '' }) => ({ + className: `${SELECTOR_TIMELINE_GLOBAL_CONTAINER} ${className}`, +}))` width: 100%; overflow: hidden; flex: 1; @@ -213,6 +216,12 @@ const EventsViewerComponent: React.FC = ({ queryFields, ]); + const prevSortField = useRef< + Array<{ + field: string; + direction: Direction; + }> + >([]); const sortField = useMemo( () => sort.map(({ columnId, sortDirection }) => ({ @@ -243,7 +252,11 @@ const EventsViewerComponent: React.FC = ({ prevCombinedQueries.current = combinedQueries; dispatch(timelineActions.toggleExpandedEvent({ timelineId: id })); } - }, [combinedQueries, dispatch, id]); + if (!deepEqual(prevSortField.current, sortField)) { + prevSortField.current = sortField; + dispatch(timelineActions.toggleExpandedEvent({ timelineId: id })); + } + }, [combinedQueries, dispatch, id, sortField]); const totalCountMinusDeleted = useMemo( () => (totalCount > 0 ? totalCount - deletedEventIds.length : 0), @@ -297,7 +310,10 @@ const EventsViewerComponent: React.FC = ({ {utilityBar && !resolverIsShowing(graphEventId) && ( {utilityBar?.(refetch, totalCountMinusDeleted)} )} - + state.app.notesById; +export const selectNotesById = (state: State): NotesById => state.app.notesById; const getErrors = (state: State): ErrorModel => state.app.errors; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.test.tsx index 81fb42dd8d20..c9bd1ee13cd9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.test.tsx @@ -8,13 +8,18 @@ import { mount } from 'enzyme'; import React from 'react'; import { TestProviders } from '../../../../common/mock/test_providers'; +import { TimelineTabs } from '../../../store/timeline/model'; import { FlyoutBottomBar } from '.'; describe('FlyoutBottomBar', () => { test('it renders the expected bottom bar', () => { const wrapper = mount( - + ); @@ -24,7 +29,67 @@ describe('FlyoutBottomBar', () => { test('it renders the data providers drop target area', () => { const wrapper = mount( - + + + ); + + expect(wrapper.find('[data-test-subj="dataProviders"]').exists()).toBe(true); + }); + + test('it renders the flyout header panel', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="timeline-flyout-header-panel"]').exists()).toBe(true); + }); + + test('it hides the data providers drop target area', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="dataProviders"]').exists()).toBe(false); + }); + + test('it hides the flyout header panel', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="timeline-flyout-header-panel"]').exists()).toBe(false); + }); + + test('it renders the data providers drop target area when showDataproviders=false and tab is not query', () => { + const wrapper = mount( + + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx index 1c0f2ba55de4..e6de34f1bf7a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/bottom_bar/index.tsx @@ -14,25 +14,32 @@ import { DataProvider } from '../../timeline/data_providers/data_provider'; import { flattenIntoAndGroups } from '../../timeline/data_providers/helpers'; import { DataProviders } from '../../timeline/data_providers'; import { FlyoutHeaderPanel } from '../header'; +import { TimelineTabs } from '../../../store/timeline/model'; export const FLYOUT_BUTTON_CLASS_NAME = 'timeline-flyout-button'; export const getBadgeCount = (dataProviders: DataProvider[]): number => flattenIntoAndGroups(dataProviders).reduce((total, group) => total + group.length, 0); -const SHOW_HIDE_TRANSLATE_X = 50; // px +const SHOW_HIDE_GLOBAL_TRANSLATE_Y = 50; // px +const SHOW_HIDE_TIMELINE_TRANSLATE_Y = 0; // px -const Container = styled.div` +const Container = styled.div.attrs<{ $isGlobal: boolean }>(({ $isGlobal = true }) => ({ + style: { + transform: $isGlobal + ? `translateY(calc(100% - ${SHOW_HIDE_GLOBAL_TRANSLATE_Y}px))` + : `translateY(calc(100% - ${SHOW_HIDE_TIMELINE_TRANSLATE_Y}px))`, + }, +}))<{ $isGlobal: boolean }>` position: fixed; left: 0; bottom: 0; - transform: translateY(calc(100% - ${SHOW_HIDE_TRANSLATE_X}px)); user-select: none; width: 100%; - z-index: ${({ theme }) => theme.eui.euiZLevel6}; + z-index: ${({ theme }) => theme.eui.euiZLevel8 + 1}; .${IS_DRAGGING_CLASS_NAME} & { - transform: none; + transform: none !important; } .${FLYOUT_BUTTON_CLASS_NAME} { @@ -61,16 +68,24 @@ const DataProvidersPanel = styled(EuiPanel)` `; interface FlyoutBottomBarProps { + activeTab: TimelineTabs; + showDataproviders: boolean; timelineId: string; } -export const FlyoutBottomBar = React.memo(({ timelineId }) => ( - - - - - - -)); +export const FlyoutBottomBar = React.memo( + ({ activeTab, showDataproviders, timelineId }) => { + return ( + + {showDataproviders && } + {(showDataproviders || (!showDataproviders && activeTab !== TimelineTabs.query)) && ( + + + + )} + + ); + } +); FlyoutBottomBar.displayName = 'FlyoutBottomBar'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index 063e968a6c51..e22a6616ecfc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -86,7 +86,13 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline ); return ( - + diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx index ccd514f880d9..622efefc6230 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx @@ -33,7 +33,7 @@ interface OwnProps { const FlyoutComponent: React.FC = ({ timelineId, onAppLeave }) => { const dispatch = useDispatch(); const getTimelineShowStatus = useMemo(() => getTimelineShowStatusByIdSelector(), []); - const { show, status: timelineStatus, updated } = useDeepEqualSelector((state) => + const { activeTab, show, status: timelineStatus, updated } = useDeepEqualSelector((state) => getTimelineShowStatus(state, timelineId) ); @@ -78,7 +78,6 @@ const FlyoutComponent: React.FC = ({ timelineId, onAppLeave }) => { } }); }, [dispatch, onAppLeave, show, timelineStatus, updated]); - return ( <> @@ -86,9 +85,7 @@ const FlyoutComponent: React.FC = ({ timelineId, onAppLeave }) => { - - - + ); }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts index ca811afd164f..0ec4fecedfa7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts @@ -8,9 +8,11 @@ import { createSelector } from 'reselect'; import { TimelineStatus } from '../../../../common/types/timeline'; import { timelineSelectors } from '../../store/timeline'; +import { TimelineTabs } from '../../store/timeline/model'; export const getTimelineShowStatusByIdSelector = () => createSelector(timelineSelectors.selectTimeline, (timeline) => ({ + activeTab: timeline?.activeTab ?? TimelineTabs.query, status: timeline?.status ?? TimelineStatus.draft, show: timeline?.show ?? false, updated: timeline?.updated ?? undefined, diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx index 7efa16d8168e..2a1d0d2ad11c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx @@ -63,43 +63,55 @@ const ToggleEventDetailsButton = React.memo(ToggleEventDetailsButtonComponent); */ interface NotePreviewsProps { + eventIdToNoteIds?: Record; notes?: TimelineResultNote[] | null; timelineId?: string; } -export const NotePreviews = React.memo(({ notes, timelineId }) => { - const notesList = useMemo( - () => - uniqBy('savedObjectId', notes).map((note) => ({ - 'data-test-subj': `note-preview-${note.savedObjectId}`, - username: defaultToEmptyTag(note.updatedBy), - event: 'added a comment', - timestamp: note.updated ? ( - - ) : ( - getEmptyValue() - ), - children: {note.note ?? ''}, - actions: - note.eventId && timelineId ? ( - - ) : null, - timelineIcon: ( - - ), - })), - [notes, timelineId] - ); +export const NotePreviews = React.memo( + ({ eventIdToNoteIds, notes, timelineId }) => { + const notesList = useMemo( + () => + uniqBy('savedObjectId', notes).map((note) => { + const eventId = + eventIdToNoteIds != null + ? Object.entries(eventIdToNoteIds).reduce( + (acc, [id, noteIds]) => (noteIds.includes(note.noteId ?? '') ? id : acc), + null + ) + : note.eventId ?? null; + return { + 'data-test-subj': `note-preview-${note.savedObjectId}`, + username: defaultToEmptyTag(note.updatedBy), + event: 'added a comment', + timestamp: note.updated ? ( + + ) : ( + getEmptyValue() + ), + children: {note.note ?? ''}, + actions: + eventId && timelineId ? ( + + ) : null, + timelineIcon: ( + + ), + }; + }), + [eventIdToNoteIds, notes, timelineId] + ); - if (notes == null || notes.length === 0) { - return null; - } + if (notes == null || notes.length === 0) { + return null; + } - return ; -}); + return ; + } +); NotePreviews.displayName = 'NotePreviews'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx index 6bbc39f49575..6dad9851e5ad 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx @@ -11,7 +11,7 @@ import { getOr } from 'lodash/fp'; import { DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME } from '../../../../../common/components/drag_and_drop/helpers'; import { Ecs } from '../../../../../../common/ecs'; import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; +import { ColumnHeaderOptions, TimelineTabs } from '../../../../../timelines/store/timeline/model'; import { ARIA_COLUMN_INDEX_OFFSET } from '../../helpers'; import { EventsTd, EVENTS_TD_CLASS_NAME, EventsTdContent, EventsTdGroupData } from '../../styles'; import { ColumnRenderer } from '../renderers/column_renderer'; @@ -21,6 +21,7 @@ import * as i18n from './translations'; interface Props { _id: string; + activeTab?: TimelineTabs; ariaRowindex: number; columnHeaders: ColumnHeaderOptions[]; columnRenderers: ColumnRenderer[]; @@ -73,12 +74,12 @@ export const onKeyDown = (keyboardEvent: React.KeyboardEvent) => { }; export const DataDrivenColumns = React.memo( - ({ _id, ariaRowindex, columnHeaders, columnRenderers, data, ecsData, timelineId }) => ( + ({ _id, activeTab, ariaRowindex, columnHeaders, columnRenderers, data, ecsData, timelineId }) => ( {columnHeaders.map((header, i) => ( ( eventId: _id, field: header, linkValues: getOr([], header.linkField ?? '', ecsData), - timelineId, + timelineId: activeTab != null ? `${timelineId}-${activeTab}` : timelineId, truncate: true, values: getMappedNonEcsValue({ data, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx index f7898e347ba6..6aee6f9d4fdf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import { useShallowEqualSelector } from '../../../../../common/hooks/use_selector'; import { Ecs } from '../../../../../../common/ecs'; import { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; +import { ColumnHeaderOptions, TimelineTabs } from '../../../../../timelines/store/timeline/model'; import { OnPinEvent, OnRowSelected, OnUnPinEvent } from '../../events'; import { EventsTrData } from '../../styles'; import { Actions } from '../actions'; @@ -35,6 +35,7 @@ import * as i18n from '../translations'; interface Props { id: string; actionsColumnWidth: number; + activeTab?: TimelineTabs; ariaRowindex: number; columnHeaders: ColumnHeaderOptions[]; columnRenderers: ColumnRenderer[]; @@ -64,6 +65,7 @@ export const EventColumnView = React.memo( ({ id, actionsColumnWidth, + activeTab, ariaRowindex, columnHeaders, columnRenderers, @@ -223,6 +225,7 @@ export const EventColumnView = React.memo( = ({ actionsColumnWidth, + activeTab, browserFields, columnHeaders, columnRenderers, @@ -67,6 +69,7 @@ const EventsComponent: React.FC = ({ {data.map((event, i) => ( = ({ eventIdToNoteIds={eventIdToNoteIds} isEventPinned={eventIsPinned({ eventId: event._id, pinnedEventIds })} isEventViewer={isEventViewer} - key={`${event._id}_${event._index}`} + key={`${id}_${activeTab}_${event._id}_${event._index}`} lastFocusedAriaColindex={lastFocusedAriaColindex} loadingEventIds={loadingEventIds} onRowSelected={onRowSelected} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx index 2cdaf74f5ecf..9802e4532b05 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx @@ -14,7 +14,7 @@ import { TimelineItem, TimelineNonEcsData, } from '../../../../../../common/search_strategy/timeline'; -import { ColumnHeaderOptions } from '../../../../../timelines/store/timeline/model'; +import { ColumnHeaderOptions, TimelineTabs } from '../../../../../timelines/store/timeline/model'; import { OnPinEvent, OnRowSelected } from '../../events'; import { STATEFUL_EVENT_CSS_CLASS_NAME } from '../../helpers'; import { EventsTrGroup, EventsTrSupplement, EventsTrSupplementContainer } from '../../styles'; @@ -34,6 +34,7 @@ import { timelineDefaults } from '../../../../store/timeline/defaults'; interface Props { actionsColumnWidth: number; + activeTab?: TimelineTabs; containerRef: React.MutableRefObject; browserFields: BrowserFields; columnHeaders: ColumnHeaderOptions[]; @@ -65,6 +66,7 @@ EventsTrSupplementContainerWrapper.displayName = 'EventsTrSupplementContainerWra const StatefulEventComponent: React.FC = ({ actionsColumnWidth, + activeTab, browserFields, containerRef, columnHeaders, @@ -193,6 +195,7 @@ const StatefulEventComponent: React.FC = ({ { setSelected: (jest.fn() as unknown) as StatefulBodyProps['setSelected'], sort: mockSort, showCheckboxes: false, + activeTab: TimelineTabs.query, totalPages: 1, }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx index 30588f3e2ea2..f6190b39214e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx @@ -60,6 +60,7 @@ export type StatefulBodyProps = OwnProps & PropsFromRedux; export const BodyComponent = React.memo( ({ + activeTab, activePage, browserFields, columnHeaders, @@ -199,6 +200,7 @@ export const BodyComponent = React.memo( ( ); }, (prevProps, nextProps) => + prevProps.activeTab === nextProps.activeTab && deepEqual(prevProps.browserFields, nextProps.browserFields) && deepEqual(prevProps.columnHeaders, nextProps.columnHeaders) && deepEqual(prevProps.data, nextProps.data) && @@ -250,6 +253,7 @@ const makeMapStateToProps = () => { const mapStateToProps = (state: State, { browserFields, id }: OwnProps) => { const timeline: TimelineModel = getTimeline(state, id) ?? timelineDefaults; const { + activeTab, columns, eventIdToNoteIds, excludedRowRendererIds, @@ -261,6 +265,7 @@ const makeMapStateToProps = () => { } = timeline; return { + activeTab: id === TimelineId.active ? activeTab : undefined, columnHeaders: memoizedColumnHeaders(columns, browserFields), eventIdToNoteIds, excludedRowRendererIds, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx index 248267fb2e05..5359491f15b0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/header/index.tsx @@ -19,6 +19,7 @@ import { interface Props { filterManager: FilterManager; + show: boolean; showCallOutUnauthorizedMsg: boolean; status: TimelineStatusLiteralWithNull; timelineId: string; @@ -26,6 +27,7 @@ interface Props { const TimelineHeaderComponent: React.FC = ({ filterManager, + show, showCallOutUnauthorizedMsg, status, timelineId, @@ -49,7 +51,7 @@ const TimelineHeaderComponent: React.FC = ({ size="s" /> )} - + {show && } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx index 7abccd83db5f..1e1b827f3879 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx @@ -12,12 +12,7 @@ import { DragDropContextWrapper } from '../../../common/components/drag_and_drop import '../../../common/mock/match_media'; import { mockBrowserFields, mockDocValueFields } from '../../../common/containers/source/mock'; -import { - mockIndexNames, - mockIndexPattern, - mockTimelineData, - TestProviders, -} from '../../../common/mock'; +import { mockIndexNames, mockIndexPattern, TestProviders } from '../../../common/mock'; import { StatefulTimeline, Props as StatefulTimelineOwnProps } from './index'; import { useTimelineEvents } from '../../containers/index'; @@ -66,9 +61,10 @@ describe('StatefulTimeline', () => { (useTimelineEvents as jest.Mock).mockReturnValue([ false, { - events: mockTimelineData, + events: [], pageInfo: { activePage: 0, + totalPages: 10, querySize: 0, }, }, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx index 20c528c70189..bfb990cbd736 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx @@ -122,9 +122,14 @@ interface NotesTabContentProps { const NotesTabContentComponent: React.FC = ({ timelineId }) => { const dispatch = useDispatch(); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const { createdBy, expandedEvent, status: timelineStatus } = useDeepEqualSelector((state) => + const { + createdBy, + expandedEvent, + eventIdToNoteIds, + status: timelineStatus, + } = useDeepEqualSelector((state) => pick( - ['createdBy', 'expandedEvent', 'status'], + ['createdBy', 'expandedEvent', 'eventIdToNoteIds', 'status'], getTimeline(state, timelineId) ?? timelineDefaults ) ); @@ -192,7 +197,7 @@ const NotesTabContentComponent: React.FC = ({ timelineId }

{NOTES}

- + {!isImmutable && ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap new file mode 100644 index 000000000000..ca75dd669caf --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/__snapshots__/index.test.tsx.snap @@ -0,0 +1,149 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PinnedTabContent rendering renders correctly against snapshot 1`] = ` + +`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx new file mode 100644 index 000000000000..bea72d37b9a7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.test.tsx @@ -0,0 +1,133 @@ +/* + * 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 { shallow } from 'enzyme'; +import React from 'react'; +import useResizeObserver from 'use-resize-observer/polyfilled'; + +import { Direction } from '../../../../graphql/types'; +import { defaultHeaders, mockTimelineData } from '../../../../common/mock'; +import '../../../../common/mock/match_media'; +import { TestProviders } from '../../../../common/mock/test_providers'; + +import { Sort } from '../body/sort'; +import { useMountAppended } from '../../../../common/utils/use_mount_appended'; +import { TimelineId } from '../../../../../common/types/timeline'; +import { useTimelineEvents } from '../../../containers/index'; +import { useTimelineEventsDetails } from '../../../containers/details/index'; +import { useSourcererScope } from '../../../../common/containers/sourcerer'; +import { mockSourcererScope } from '../../../../common/containers/sourcerer/mocks'; +import { PinnedTabContentComponent, Props as PinnedTabContentComponentProps } from '.'; + +jest.mock('../../../containers/index', () => ({ + useTimelineEvents: jest.fn(), +})); +jest.mock('../../../containers/details/index', () => ({ + useTimelineEventsDetails: jest.fn(), +})); +jest.mock('../body/events/index', () => ({ + // eslint-disable-next-line react/display-name + Events: () => <>, +})); + +jest.mock('../../../../common/containers/sourcerer'); + +const mockUseResizeObserver: jest.Mock = useResizeObserver as jest.Mock; +jest.mock('use-resize-observer/polyfilled'); +mockUseResizeObserver.mockImplementation(() => ({})); + +jest.mock('../../../../common/lib/kibana', () => { + const originalModule = jest.requireActual('../../../../common/lib/kibana'); + return { + ...originalModule, + useKibana: jest.fn().mockReturnValue({ + services: { + application: { + navigateToApp: jest.fn(), + getUrlForApp: jest.fn(), + }, + uiSettings: { + get: jest.fn(), + }, + savedObjects: { + client: {}, + }, + }, + }), + useGetUserSavedObjectPermissions: jest.fn(), + }; +}); + +describe('PinnedTabContent', () => { + let props = {} as PinnedTabContentComponentProps; + const sort: Sort[] = [ + { + columnId: '@timestamp', + sortDirection: Direction.desc, + }, + ]; + + const mount = useMountAppended(); + + beforeEach(() => { + (useTimelineEvents as jest.Mock).mockReturnValue([ + false, + { + events: mockTimelineData, + pageInfo: { + activePage: 0, + totalPages: 10, + }, + }, + ]); + (useTimelineEventsDetails as jest.Mock).mockReturnValue([false, {}]); + + (useSourcererScope as jest.Mock).mockReturnValue(mockSourcererScope); + + props = { + columns: defaultHeaders, + timelineId: TimelineId.test, + itemsPerPage: 5, + itemsPerPageOptions: [5, 10, 20], + sort, + pinnedEventIds: {}, + showEventDetails: false, + onEventClosed: jest.fn(), + }; + }); + + describe('rendering', () => { + test('renders correctly against snapshot', () => { + const wrapper = shallow( + + + + ); + + expect(wrapper.find('PinnedTabContentComponent')).toMatchSnapshot(); + }); + + test('it renders the timeline table', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="events-table"]').exists()).toEqual(true); + }); + + it('it shows the timeline footer', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find('[data-test-subj="timeline-footer"]').exists()).toEqual(true); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx new file mode 100644 index 000000000000..45c190c42605 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx @@ -0,0 +1,283 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiFlyoutBody, EuiFlyoutFooter } from '@elastic/eui'; +import { isEmpty } from 'lodash/fp'; +import React, { useMemo, useCallback } from 'react'; +import styled from 'styled-components'; +import { Dispatch } from 'redux'; +import { connect, ConnectedProps } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; + +import { timelineActions, timelineSelectors } from '../../../store/timeline'; +import { Direction } from '../../../../../common/search_strategy'; +import { useTimelineEvents } from '../../../containers/index'; +import { defaultHeaders } from '../body/column_headers/default_headers'; +import { StatefulBody } from '../body'; +import { Footer, footerHeight } from '../footer'; +import { requiredFieldsForActions } from '../../../../detections/components/alerts_table/default_config'; +import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; +import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; +import { timelineDefaults } from '../../../store/timeline/defaults'; +import { useSourcererScope } from '../../../../common/containers/sourcerer'; +import { TimelineModel } from '../../../store/timeline/model'; +import { EventDetails } from '../event_details'; +import { ToggleExpandedEvent } from '../../../store/timeline/actions'; +import { State } from '../../../../common/store'; +import { calculateTotalPages } from '../helpers'; + +const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` + overflow-y: hidden; + flex: 1; + + .euiFlyoutBody__overflow { + overflow: hidden; + mask-image: none; + } + + .euiFlyoutBody__overflowContent { + padding: 0; + height: 100%; + display: flex; + } +`; + +const StyledEuiFlyoutFooter = styled(EuiFlyoutFooter)` + background: none; + padding: 0; +`; + +const FullWidthFlexGroup = styled(EuiFlexGroup)` + margin: 0; + width: 100%; + overflow: hidden; +`; + +const ScrollableFlexItem = styled(EuiFlexItem)` + overflow: hidden; +`; + +const VerticalRule = styled.div` + width: 2px; + height: 100%; + background: ${({ theme }) => theme.eui.euiColorLightShade}; +`; + +VerticalRule.displayName = 'VerticalRule'; + +interface OwnProps { + timelineId: string; +} + +interface PinnedFilter { + bool: { + should: Array<{ match_phrase: { _id: string } }>; + minimum_should_match: number; + }; +} + +export type Props = OwnProps & PropsFromRedux; + +export const PinnedTabContentComponent: React.FC = ({ + columns, + timelineId, + itemsPerPage, + itemsPerPageOptions, + pinnedEventIds, + onEventClosed, + showEventDetails, + sort, +}) => { + const { browserFields, docValueFields, loading: loadingSourcerer } = useSourcererScope( + SourcererScopeName.timeline + ); + + const filterQuery = useMemo(() => { + if (isEmpty(pinnedEventIds)) { + return ''; + } + const filterObj = Object.entries(pinnedEventIds).reduce( + (acc, [pinnedId, isPinned]) => { + if (isPinned) { + return { + ...acc, + bool: { + ...acc.bool, + should: [ + ...acc.bool.should, + { + match_phrase: { + _id: pinnedId, + }, + }, + ], + }, + }; + } + return acc; + }, + { + bool: { + should: [], + minimum_should_match: 1, + }, + } + ); + try { + return JSON.stringify(filterObj); + } catch { + return ''; + } + }, [pinnedEventIds]); + + const timelineQueryFields = useMemo(() => { + const columnsHeader = isEmpty(columns) ? defaultHeaders : columns; + const columnFields = columnsHeader.map((c) => c.id); + + return [...columnFields, ...requiredFieldsForActions]; + }, [columns]); + + const timelineQuerySortField = useMemo( + () => + sort.map(({ columnId, sortDirection }) => ({ + field: columnId, + direction: sortDirection as Direction, + })), + [sort] + ); + + const [ + isQueryLoading, + { events, totalCount, pageInfo, loadPage, updatedAt, refetch }, + ] = useTimelineEvents({ + docValueFields, + endDate: '', + id: `pinned-${timelineId}`, + indexNames: [''], + fields: timelineQueryFields, + limit: itemsPerPage, + filterQuery, + skip: filterQuery === '', + startDate: '', + sort: timelineQuerySortField, + timerangeKind: undefined, + }); + + const handleOnEventClosed = useCallback(() => { + onEventClosed({ timelineId }); + }, [timelineId, onEventClosed]); + + return ( + <> + + + + + + + +
+ + + + {showEventDetails && ( + <> + + + + + + )} + + + ); +}; + +const makeMapStateToProps = () => { + const getTimeline = timelineSelectors.getTimelineByIdSelector(); + const mapStateToProps = (state: State, { timelineId }: OwnProps) => { + const timeline: TimelineModel = getTimeline(state, timelineId) ?? timelineDefaults; + const { + columns, + expandedEvent, + itemsPerPage, + itemsPerPageOptions, + pinnedEventIds, + sort, + } = timeline; + + return { + columns, + timelineId, + itemsPerPage, + itemsPerPageOptions, + pinnedEventIds, + showEventDetails: !!expandedEvent.eventId, + sort, + }; + }; + return mapStateToProps; +}; + +const mapDispatchToProps = (dispatch: Dispatch, { timelineId }: OwnProps) => ({ + onEventClosed: (args: ToggleExpandedEvent) => { + dispatch(timelineActions.toggleExpandedEvent(args)); + }, +}); + +const connector = connect(makeMapStateToProps, mapDispatchToProps); + +type PropsFromRedux = ConnectedProps; + +const PinnedTabContent = connector( + React.memo( + PinnedTabContentComponent, + (prevProps, nextProps) => + prevProps.itemsPerPage === nextProps.itemsPerPage && + prevProps.onEventClosed === nextProps.onEventClosed && + prevProps.showEventDetails === nextProps.showEventDetails && + prevProps.timelineId === nextProps.timelineId && + deepEqual(prevProps.columns, nextProps.columns) && + deepEqual(prevProps.itemsPerPageOptions, nextProps.itemsPerPageOptions) && + deepEqual(prevProps.pinnedEventIds, nextProps.pinnedEventIds) && + deepEqual(prevProps.sort, nextProps.sort) + ) +); + +// eslint-disable-next-line import/no-default-export +export { PinnedTabContent as default }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap index 20f5b61457e9..e09a66dde6d9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/__snapshots__/index.test.tsx.snap @@ -2,6 +2,7 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = ` ({ useTimelineEvents: jest.fn(), @@ -111,6 +112,8 @@ describe('Timeline', () => { status: TimelineStatus.active, timerangeKind: 'absolute', updateEventTypeAndIndexesName: jest.fn(), + activeTab: TimelineTabs.query, + show: true, }; }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx index fe8a8ad374c3..f6d6654d7fec 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx @@ -5,7 +5,6 @@ */ import { - EuiTabbedContent, EuiFlexGroup, EuiFlexItem, EuiFlyoutHeader, @@ -45,7 +44,7 @@ import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { timelineDefaults } from '../../../../timelines/store/timeline/defaults'; import { useSourcererScope } from '../../../../common/containers/sourcerer'; import { useTimelineEventsCountPortal } from '../../../../common/hooks/use_timeline_events_count'; -import { TimelineModel } from '../../../../timelines/store/timeline/model'; +import { TimelineModel, TimelineTabs } from '../../../../timelines/store/timeline/model'; import { EventDetails } from '../event_details'; import { TimelineDatePickerLock } from '../date_picker_lock'; import { HideShowContainer } from '../styles'; @@ -116,22 +115,6 @@ const VerticalRule = styled.div` VerticalRule.displayName = 'VerticalRule'; -const StyledEuiTabbedContent = styled(EuiTabbedContent)` - display: flex; - flex-direction: column; - flex: 1; - overflow: hidden; - - > [role='tabpanel'] { - display: flex; - flex-direction: column; - flex: 1; - overflow: hidden; - } -`; - -StyledEuiTabbedContent.displayName = 'StyledEuiTabbedContent'; - const EventsCountBadge = styled(EuiBadge)` margin-left: ${({ theme }) => theme.eui.paddingSizes.s}; `; @@ -150,6 +133,7 @@ const EMPTY_EVENTS: TimelineItem[] = []; export type Props = OwnProps & PropsFromRedux; export const QueryTabContentComponent: React.FC = ({ + activeTab, columns, dataProviders, end, @@ -163,6 +147,7 @@ export const QueryTabContentComponent: React.FC = ({ kqlMode, kqlQueryExpression, onEventClosed, + show, showCallOutUnauthorizedMsg, showEventDetails, start, @@ -226,7 +211,12 @@ export const QueryTabContentComponent: React.FC = ({ return [...columnFields, ...requiredFieldsForActions]; }, [columns]); - + const prevTimelineQuerySortField = useRef< + Array<{ + field: string; + direction: Direction; + }> + >([]); const timelineQuerySortField = useMemo( () => sort.map(({ columnId, sortDirection }) => ({ @@ -281,7 +271,11 @@ export const QueryTabContentComponent: React.FC = ({ prevCombinedQueries.current = combinedQueries; handleOnEventClosed(); } - }, [combinedQueries, handleOnEventClosed]); + if (!deepEqual(prevTimelineQuerySortField.current, timelineQuerySortField)) { + prevTimelineQuerySortField.current = timelineQuerySortField; + handleOnEventClosed(); + } + }, [combinedQueries, handleOnEventClosed, timelineQuerySortField]); return ( <> @@ -318,9 +312,10 @@ export const QueryTabContentComponent: React.FC = ({ @@ -392,6 +387,7 @@ const makeMapStateToProps = () => { const timeline: TimelineModel = getTimeline(state, timelineId) ?? timelineDefaults; const input: inputsModel.InputsRange = getInputsTimeline(state); const { + activeTab, columns, dataProviders, eventType, @@ -400,6 +396,7 @@ const makeMapStateToProps = () => { itemsPerPage, itemsPerPageOptions, kqlMode, + show, sort, status, timelineType, @@ -413,6 +410,7 @@ const makeMapStateToProps = () => { ? ' ' : kqlQueryTimeline; return { + activeTab, columns, dataProviders, eventType: eventType ?? 'raw', @@ -427,6 +425,7 @@ const makeMapStateToProps = () => { kqlQueryExpression, showCallOutUnauthorizedMsg: getShowCallOutUnauthorizedMsg(state), showEventDetails: !!expandedEvent.eventId, + show, sort, start: input.timerange.from, status, @@ -460,6 +459,7 @@ const QueryTabContent = connector( React.memo( QueryTabContentComponent, (prevProps, nextProps) => + prevProps.activeTab === nextProps.activeTab && isTimerangeSame(prevProps, nextProps) && prevProps.eventType === nextProps.eventType && prevProps.isLive === nextProps.isLive && @@ -467,6 +467,7 @@ const QueryTabContent = connector( prevProps.kqlMode === nextProps.kqlMode && prevProps.kqlQueryExpression === nextProps.kqlQueryExpression && prevProps.onEventClosed === nextProps.onEventClosed && + prevProps.show === nextProps.show && prevProps.showCallOutUnauthorizedMsg === nextProps.showCallOutUnauthorizedMsg && prevProps.showEventDetails === nextProps.showEventDetails && prevProps.status === nextProps.status && diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx index fb326cf58a51..1b5e6932dff0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx @@ -67,6 +67,9 @@ const SearchOrFilterContainer = styled.div` margin-right: 0px; } } + .globalFilterGroup__wrapper.globalFilterGroup__wrapper-isVisible { + height: auto !important; + } } `; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx index 7ffe661e7851..7f0809cf9b9d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiLoadingContent, EuiTabs, EuiTab } from '@elastic/eui'; +import { EuiBadge, EuiLoadingContent, EuiTabs, EuiTab } from '@elastic/eui'; import React, { lazy, memo, Suspense, useCallback, useEffect, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; @@ -13,7 +13,12 @@ import { useShallowEqualSelector } from '../../../../common/hooks/use_selector'; import { TimelineEventsCountBadge } from '../../../../common/hooks/use_timeline_events_count'; import { timelineActions } from '../../../store/timeline'; import { TimelineTabs } from '../../../store/timeline/model'; -import { getActiveTabSelector, getShowTimelineSelector } from './selectors'; +import { + getActiveTabSelector, + getNotesSelector, + getPinnedEventSelector, + getShowTimelineSelector, +} from './selectors'; import * as i18n from './translations'; const HideShowContainer = styled.div.attrs<{ $isVisible: boolean }>(({ $isVisible = false }) => ({ @@ -28,6 +33,7 @@ const HideShowContainer = styled.div.attrs<{ $isVisible: boolean }>(({ $isVisibl const QueryTabContent = lazy(() => import('../query_tab_content')); const GraphTabContent = lazy(() => import('../graph_tab_content')); const NotesTabContent = lazy(() => import('../notes_tab_content')); +const PinnedTabContent = lazy(() => import('../pinned_tab_content')); interface BasicTimelineTab { timelineId: string; @@ -57,7 +63,7 @@ NotesTab.displayName = 'NotesTab'; const PinnedTab: React.FC = memo(({ timelineId }) => ( }> - + )); PinnedTab.displayName = 'PinnedTab'; @@ -72,8 +78,6 @@ const ActiveTimelineTab = memo(({ activeTimelineTab, tim return ; case TimelineTabs.notes: return ; - case TimelineTabs.pinned: - return ; default: return null; } @@ -81,6 +85,11 @@ const ActiveTimelineTab = memo(({ activeTimelineTab, tim [timelineId] ); + const isGraphOrNotesTabs = useMemo( + () => [TimelineTabs.graph, TimelineTabs.notes].includes(activeTimelineTab), + [activeTimelineTab] + ); + /* Future developer -> why are we doing that * It is really expansive to re-render the QueryTab because the drag/drop * Therefore, we are only hiding its dom when switching to another tab @@ -91,8 +100,11 @@ const ActiveTimelineTab = memo(({ activeTimelineTab, tim - - {activeTimelineTab !== TimelineTabs.query && getTab(activeTimelineTab)} + + + + + {isGraphOrNotesTabs && getTab(activeTimelineTab)} ); @@ -100,6 +112,10 @@ const ActiveTimelineTab = memo(({ activeTimelineTab, tim ActiveTimelineTab.displayName = 'ActiveTimelineTab'; +const CountBadge = styled(EuiBadge)` + margin-left: ${({ theme }) => theme.eui.paddingSizes.s}; +`; + const StyledEuiTab = styled(EuiTab)` > span { display: flex; @@ -120,8 +136,14 @@ const TabsContentComponent: React.FC = ({ timelineId, graphEve const dispatch = useDispatch(); const getActiveTab = useMemo(() => getActiveTabSelector(), []); const getShowTimeline = useMemo(() => getShowTimelineSelector(), []); + const getNumberOfPinnedEvents = useMemo(() => getPinnedEventSelector(), []); + const getNumberOfNotes = useMemo(() => getNotesSelector(), []); const activeTab = useShallowEqualSelector((state) => getActiveTab(state, timelineId)); const showTimeline = useShallowEqualSelector((state) => getShowTimeline(state, timelineId)); + const numberOfPinnedEvents = useShallowEqualSelector((state) => + getNumberOfPinnedEvents(state, timelineId) + ); + const numberOfNotes = useShallowEqualSelector((state) => getNumberOfNotes(state)); const setQueryAsActiveTab = useCallback(() => { dispatch(timelineActions.toggleExpandedEvent({ timelineId })); @@ -130,13 +152,12 @@ const TabsContentComponent: React.FC = ({ timelineId, graphEve ); }, [dispatch, timelineId]); - const setGraphAsActiveTab = useCallback( - () => - dispatch( - timelineActions.setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph }) - ), - [dispatch, timelineId] - ); + const setGraphAsActiveTab = useCallback(() => { + dispatch(timelineActions.toggleExpandedEvent({ timelineId })); + dispatch( + timelineActions.setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph }) + ); + }, [dispatch, timelineId]); const setNotesAsActiveTab = useCallback(() => { dispatch(timelineActions.toggleExpandedEvent({ timelineId })); @@ -145,13 +166,12 @@ const TabsContentComponent: React.FC = ({ timelineId, graphEve ); }, [dispatch, timelineId]); - const setPinnedAsActiveTab = useCallback( - () => - dispatch( - timelineActions.setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.pinned }) - ), - [dispatch, timelineId] - ); + const setPinnedAsActiveTab = useCallback(() => { + dispatch(timelineActions.toggleExpandedEvent({ timelineId })); + dispatch( + timelineActions.setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.pinned }) + ); + }, [dispatch, timelineId]); useEffect(() => { if (!graphEventId && activeTab === TimelineTabs.graph) { @@ -181,24 +201,33 @@ const TabsContentComponent: React.FC = ({ timelineId, graphEve > {i18n.GRAPH_TAB} - - {i18n.NOTES_TAB} - - {i18n.NOTES_TAB} + {showTimeline && numberOfNotes > 0 && ( +
+ {numberOfNotes} +
+ )} + + - {i18n.PINNED_TAB} -
+ {i18n.PINNED_TAB} + {showTimeline && numberOfPinnedEvents > 0 && ( +
+ {numberOfPinnedEvents} +
+ )} + diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts index a4bf3f05a3d2..332785161b09 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts @@ -5,6 +5,7 @@ */ import { createSelector } from 'reselect'; +import { selectNotesById } from '../../../../common/store/app/selectors'; import { TimelineTabs } from '../../../store/timeline/model'; import { selectTimeline } from '../../../store/timeline/selectors'; @@ -13,3 +14,9 @@ export const getActiveTabSelector = () => export const getShowTimelineSelector = () => createSelector(selectTimeline, (timeline) => timeline?.show ?? false); + +export const getPinnedEventSelector = () => + createSelector(selectTimeline, (timeline) => Object.keys(timeline?.pinnedEventIds ?? {}).length); + +export const getNotesSelector = () => + createSelector(selectNotesById, (notesById) => Object.keys(notesById ?? {}).length); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx index 95a916a6858e..3014ae8d19d3 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx @@ -41,6 +41,7 @@ import { Direction } from '../../../graphql/types'; import { addTimelineInStorage } from '../../containers/local_storage'; import { isPageTimeline } from './epic_local_storage'; import { TimelineId, TimelineStatus } from '../../../../common/types/timeline'; +import { TimelineTabs } from './model'; jest.mock('../../containers/local_storage'); @@ -96,6 +97,8 @@ describe('epicLocalStorage', () => { timelineId: 'foo', timerangeKind: 'absolute', updateEventTypeAndIndexesName: jest.fn(), + activeTab: TimelineTabs.query, + show: true, }; }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts index 034a2b3c6ea9..3ff542ebde5f 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/query.events_all.dsl.ts @@ -27,17 +27,19 @@ export const buildTimelineEventsAllQuery = ({ const getTimerangeFilter = (timerangeOption: TimerangeInput | undefined): TimerangeFilter[] => { if (timerangeOption) { const { to, from } = timerangeOption; - return [ - { - range: { - '@timestamp': { - gte: from, - lte: to, - format: 'strict_date_optional_time', + return !isEmpty(to) && !isEmpty(from) + ? [ + { + range: { + '@timestamp': { + gte: from, + lte: to, + format: 'strict_date_optional_time', + }, + }, }, - }, - }, - ]; + ] + : []; } return []; }; diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts index debde49e3587..7a30d7acf5f8 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts @@ -22,7 +22,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.timePicker.setAbsoluteRange(fromTime, toTime); await browser.setWindowSize(1800, 1200); }); - describe('Endpoint Resolver Tree', function () { + describe.skip('Endpoint Resolver Tree', function () { before(async () => { await esArchiver.load('empty_kibana'); await esArchiver.load('endpoint/resolver_tree/functions', { useCreate: true }); From a0898715b38f8eed6995e16cd0288ae6a2d11c91 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Wed, 16 Dec 2020 13:44:59 -0500 Subject: [PATCH 10/38] [ML] Data Frame Analytics map: add initial functional tests (#86032) * initial functional tests for job map * move tests to own statement --- .../pages/job_map/components/cytoscape.tsx | 2 +- .../pages/job_map/components/legend.tsx | 6 +++- .../pages/job_map/job_map.tsx | 4 +-- .../pages/job_map/job_map_title.tsx | 2 +- .../classification_creation.ts | 8 ++++++ .../outlier_detection_creation.ts | 8 ++++++ .../regression_creation.ts | 8 ++++++ .../services/ml/data_frame_analytics_map.ts | 28 +++++++++++++++++++ .../services/ml/data_frame_analytics_table.ts | 10 +++++++ x-pack/test/functional/services/ml/index.ts | 3 ++ 10 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 x-pack/test/functional/services/ml/data_frame_analytics_map.ts diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx index 838e1ec2f768..92d9ed5694d0 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx @@ -132,7 +132,7 @@ export function Cytoscape({ return ( -
+
{children}
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx index 31c2b12e003d..af1314a91b1c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/legend.tsx @@ -35,7 +35,11 @@ export const JobMapLegend: FC<{ theme: EuiThemeType }> = ({ theme }) => { const [showJobTypes, setShowJobTypes] = useState(false); return ( - + diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx index 0c314d099015..a7a1a407f70a 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx @@ -131,7 +131,7 @@ export const JobMap: FC = ({ analyticsId, modelId }) => { const refreshCallback = () => fetchAndSetElementsWrapper({ analyticsId, modelId }); return ( - <> +
@@ -197,6 +197,6 @@ export const JobMap: FC = ({ analyticsId, modelId }) => { />
- +
); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map_title.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map_title.tsx index 217a40a4fe1f..008a63331788 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map_title.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map_title.tsx @@ -13,7 +13,7 @@ export const JobMapTitle: FC<{ analyticsId?: string; modelId?: string }> = ({ modelId, }) => ( - + {analyticsId ? ( { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); }); } }); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts index b5b0f4c94f26..53daa0cae252 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts @@ -222,6 +222,14 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsResults.assertResultsTableExists(); await ml.dataFrameAnalyticsResults.assertResultsTableNotEmpty(); }); + + it('displays the analytics job in the map view', async () => { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); }); } }); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts index dad3d990cfca..fef22fcebc3e 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts @@ -208,6 +208,14 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsResults.assertResultsTableTrainingFiltersExist(); await ml.dataFrameAnalyticsResults.assertResultsTableNotEmpty(); }); + + it('displays the analytics job in the map view', async () => { + await ml.testExecution.logTestStep('should open the map view for created job'); + await ml.navigation.navigateToDataFrameAnalytics(); + await ml.dataFrameAnalyticsTable.openMapView(testData.jobId); + await ml.dataFrameAnalyticsMap.assertMapElementsExists(); + await ml.dataFrameAnalyticsMap.assertJobMapTitle(testData.jobId); + }); }); } }); diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_map.ts b/x-pack/test/functional/services/ml/data_frame_analytics_map.ts new file mode 100644 index 000000000000..1ad5afd68477 --- /dev/null +++ b/x-pack/test/functional/services/ml/data_frame_analytics_map.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function MachineLearningDataFrameAnalyticsMapProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + + return { + async assertMapElementsExists() { + await testSubjects.existOrFail('mlPageDataFrameAnalyticsMapTitle'); + await testSubjects.existOrFail('mlPageDataFrameAnalyticsMapLegend'); + await testSubjects.existOrFail('mlPageDataFrameAnalyticsMapCytoscape'); + }, + async assertJobMapTitle(id: string) { + const expected = `Map for analytics ID ${id}`; + const actualTitle = await testSubjects.getVisibleText('mlPageDataFrameAnalyticsMapTitle'); + expect(actualTitle).to.eql( + expected, + `Title for map should be '${expected}' (got '${actualTitle}')` + ); + }, + }; +} diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts index cd2f26f3a660..151476a0b5fb 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_table.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_table.ts @@ -94,6 +94,10 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F await testSubjects.existOrFail(this.rowSelector(analyticsId, 'mlAnalyticsJobViewButton')); } + public async assertJobRowMapButtonExists(analyticsId: string) { + await testSubjects.existOrFail(this.rowSelector(analyticsId, 'mlAnalyticsJobMapButton')); + } + public async assertJobRowViewButtonEnabled(analyticsId: string, expectedValue: boolean) { const isEnabled = await testSubjects.isEnabled( this.rowSelector(analyticsId, 'mlAnalyticsJobViewButton') @@ -112,6 +116,12 @@ export function MachineLearningDataFrameAnalyticsTableProvider({ getService }: F await testSubjects.existOrFail('mlPageDataFrameAnalyticsExploration', { timeout: 20 * 1000 }); } + public async openMapView(analyticsId: string) { + await this.assertJobRowMapButtonExists(analyticsId); + await testSubjects.click(this.rowSelector(analyticsId, 'mlAnalyticsJobMapButton')); + await testSubjects.existOrFail('mlPageDataFrameAnalyticsMap', { timeout: 20 * 1000 }); + } + public async assertAnalyticsSearchInputValue(expectedSearchValue: string) { const searchBarInput = await this.getAnalyticsSearchInput(); const actualSearchValue = await searchBarInput.getAttribute('value'); diff --git a/x-pack/test/functional/services/ml/index.ts b/x-pack/test/functional/services/ml/index.ts index 72903b2c409d..559a12f0f557 100644 --- a/x-pack/test/functional/services/ml/index.ts +++ b/x-pack/test/functional/services/ml/index.ts @@ -17,6 +17,7 @@ import { MachineLearningDataFrameAnalyticsProvider } from './data_frame_analytic import { MachineLearningDataFrameAnalyticsCreationProvider } from './data_frame_analytics_creation'; import { MachineLearningDataFrameAnalyticsEditProvider } from './data_frame_analytics_edit'; import { MachineLearningDataFrameAnalyticsResultsProvider } from './data_frame_analytics_results'; +import { MachineLearningDataFrameAnalyticsMapProvider } from './data_frame_analytics_map'; import { MachineLearningDataFrameAnalyticsTableProvider } from './data_frame_analytics_table'; import { MachineLearningDataVisualizerProvider } from './data_visualizer'; import { MachineLearningDataVisualizerFileBasedProvider } from './data_visualizer_file_based'; @@ -60,6 +61,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { ); const dataFrameAnalyticsEdit = MachineLearningDataFrameAnalyticsEditProvider(context, commonUI); const dataFrameAnalyticsResults = MachineLearningDataFrameAnalyticsResultsProvider(context); + const dataFrameAnalyticsMap = MachineLearningDataFrameAnalyticsMapProvider(context); const dataFrameAnalyticsTable = MachineLearningDataFrameAnalyticsTableProvider(context); const dataVisualizer = MachineLearningDataVisualizerProvider(context); const dataVisualizerFileBased = MachineLearningDataVisualizerFileBasedProvider(context, commonUI); @@ -102,6 +104,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { dataFrameAnalyticsCreation, dataFrameAnalyticsEdit, dataFrameAnalyticsResults, + dataFrameAnalyticsMap, dataFrameAnalyticsTable, dataVisualizer, dataVisualizerFileBased, From 7933f0458c56a24835e8ce098a369d28f9c982c8 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 16 Dec 2020 14:04:21 -0500 Subject: [PATCH 11/38] =?UTF-8?q?Fixes=20Failing=20test:=20Chrome=20X-Pack?= =?UTF-8?q?=20UI=20Functional=20Tests.x-pack/test/functional=5Fwith=5Fes?= =?UTF-8?q?=5Fssl/apps/triggers=5Factions=5Fui/alert=5Fcreate=5Fflyout?= =?UTF-8?q?=C2=B7ts=20-=20Actions=20and=20Triggers=20app=20create=20alert?= =?UTF-8?q?=20should=20show=20save=20confirmation=20before=20creating=20al?= =?UTF-8?q?ert=20with=20no=20actions=20(#85623)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unskipping test * Using simpler alert type during test * Fixing test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/triggers_actions_ui/alert_create_flyout.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index 2598fc890211..91eabb6c6472 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -61,8 +61,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('test.always-firing-SelectOption'); } - // FLAKY: https://github.com/elastic/kibana/issues/85105 - describe.skip('create alert', function () { + describe('create alert', function () { before(async () => { await pageObjects.common.navigateToApp('triggersActions'); await testSubjects.click('alertsTab'); @@ -179,7 +178,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should show save confirmation before creating alert with no actions', async () => { const alertName = generateUniqueKey(); - await defineAlert(alertName); + await defineAlwaysFiringAlert(alertName); await testSubjects.click('saveAlertButton'); await testSubjects.existOrFail('confirmAlertSaveModal'); @@ -200,7 +199,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { name: alertName, tagsText: '', - alertType: 'Index threshold', + alertType: 'Always Firing', interval: '1m', }, ]); From 2fcce0bcbcd1ad49be3f2ff2376d3fbf1d075436 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 16 Dec 2020 20:20:55 +0100 Subject: [PATCH 12/38] [coverage] re-enable jest (#85946) * [coverage] re-enable jest * fix coverage script for x-pack * use presets in entry configs * set max workers * run tests from x-pack folde * remove duplicate 'reporters' prop * remove reporters for x-pack config Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- jest.config.oss.js | 2 +- .../shell_scripts/extract_archives.sh | 2 +- ...te_team_assignments_and_ingest_coverage.sh | 2 +- .../merge_jest_and_functional.sh | 2 +- test/scripts/jenkins_unit.sh | 20 +++++++++---------- test/scripts/jenkins_xpack.sh | 7 ++++--- vars/kibanaCoverage.groovy | 17 ++++++++-------- x-pack/jest.config.js | 5 +---- 8 files changed, 27 insertions(+), 30 deletions(-) diff --git a/jest.config.oss.js b/jest.config.oss.js index e9235069687e..874fd1e929a7 100644 --- a/jest.config.oss.js +++ b/jest.config.oss.js @@ -18,6 +18,7 @@ */ module.exports = { + preset: '@kbn/test', rootDir: '.', projects: [ '/packages/*/jest.config.js', @@ -26,5 +27,4 @@ module.exports = { '/src/plugins/*/jest.config.js', '/test/*/jest.config.js', ], - reporters: ['default', '/packages/kbn-test/target/jest/junit_reporter'], }; diff --git a/src/dev/code_coverage/shell_scripts/extract_archives.sh b/src/dev/code_coverage/shell_scripts/extract_archives.sh index 32b4ccd6abcc..376467f9f2e5 100644 --- a/src/dev/code_coverage/shell_scripts/extract_archives.sh +++ b/src/dev/code_coverage/shell_scripts/extract_archives.sh @@ -6,7 +6,7 @@ EXTRACT_DIR=/tmp/extracted_coverage mkdir -p $EXTRACT_DIR echo "### Extracting downloaded artifacts" -for x in kibana-intake kibana-oss-tests kibana-xpack-tests; do #x-pack-intake skipping due to failures +for x in kibana-intake x-pack-intake kibana-oss-tests kibana-xpack-tests; do tar -xzf $DOWNLOAD_DIR/coverage/${x}/kibana-coverage.tar.gz -C $EXTRACT_DIR || echo "### Error 'tarring': ${x}" done diff --git a/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh b/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh index 5d983828394b..62b81929ae79 100644 --- a/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh +++ b/src/dev/code_coverage/shell_scripts/generate_team_assignments_and_ingest_coverage.sh @@ -32,7 +32,7 @@ TEAM_ASSIGN_PATH=$5 # Build team assignments dat file node scripts/generate_team_assignments.js --verbose --src .github/CODEOWNERS --dest $TEAM_ASSIGN_PATH -for x in functional; do #jest skip due to failures +for x in jest functional; do echo "### Ingesting coverage for ${x}" COVERAGE_SUMMARY_FILE=target/kibana-coverage/${x}-combined/coverage-summary.json diff --git a/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh b/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh index a8952f987b41..707c6de3f88a 100644 --- a/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh +++ b/src/dev/code_coverage/shell_scripts/merge_jest_and_functional.sh @@ -4,6 +4,6 @@ COVERAGE_TEMP_DIR=/tmp/extracted_coverage/target/kibana-coverage/ export COVERAGE_TEMP_DIR echo "### Merge coverage reports" -for x in functional; do # jest skip due to failures +for x in jest functional; do yarn nyc report --nycrc-path src/dev/code_coverage/nyc_config/nyc.${x}.config.js done diff --git a/test/scripts/jenkins_unit.sh b/test/scripts/jenkins_unit.sh index 34b194ba5d4a..956468d23a59 100755 --- a/test/scripts/jenkins_unit.sh +++ b/test/scripts/jenkins_unit.sh @@ -34,16 +34,16 @@ if [[ -z "$CODE_COVERAGE" ]] ; then ./test/scripts/checks/test_projects.sh ./test/scripts/checks/test_hardening.sh else - # echo " -> Running jest tests with coverage" - # node scripts/jest --ci --verbose --coverage --config jest.config.oss.js - # rename_coverage_file "oss" - # echo "" - # echo "" - # echo " -> Running jest integration tests with coverage" - # node --max-old-space-size=8192 scripts/jest_integration --ci --verbose --coverage || true; - # rename_coverage_file "oss-integration" - # echo "" - # echo "" + echo " -> Running jest tests with coverage" + node scripts/jest --ci --verbose --coverage --config jest.config.oss.js + rename_coverage_file "oss" + echo "" + echo "" + echo " -> Running jest integration tests with coverage" + node --max-old-space-size=8192 scripts/jest_integration --ci --verbose --coverage || true; + rename_coverage_file "oss-integration" + echo "" + echo "" echo " -> Running mocha tests with coverage" ./test/scripts/checks/mocha_coverage.sh echo "" diff --git a/test/scripts/jenkins_xpack.sh b/test/scripts/jenkins_xpack.sh index 6199aa0e5cdf..c4604109fe71 100755 --- a/test/scripts/jenkins_xpack.sh +++ b/test/scripts/jenkins_xpack.sh @@ -7,12 +7,13 @@ if [[ -z "$CODE_COVERAGE" ]] ; then ./test/scripts/test/xpack_jest_unit.sh else - echo " -> Running jest tests with coverage" - + echo " -> Build runtime for canvas" # build runtime for canvas echo "NODE_ENV=$NODE_ENV" node ./x-pack/plugins/canvas/scripts/shareable_runtime - node --max-old-space-size=6144 scripts/jest x-pack --ci --verbose --coverage + echo " -> Running jest tests with coverage" + cd x-pack + node --max-old-space-size=6144 scripts/jest --ci --verbose --maxWorkers=5 --coverage --config jest.config.js # rename file in order to be unique one test -f ../target/kibana-coverage/jest/coverage-final.json \ && mv ../target/kibana-coverage/jest/coverage-final.json \ diff --git a/vars/kibanaCoverage.groovy b/vars/kibanaCoverage.groovy index 77b00b0ec59a..b566bbcc6aee 100644 --- a/vars/kibanaCoverage.groovy +++ b/vars/kibanaCoverage.groovy @@ -59,7 +59,7 @@ def uploadBaseWebsiteFiles(prefix) { def uploadCoverageHtmls(prefix) { [ 'target/kibana-coverage/functional-combined', - // 'target/kibana-coverage/jest-combined', skipped due to failures + 'target/kibana-coverage/jest-combined', 'target/kibana-coverage/mocha-combined', ].each { uploadWithVault(prefix, it) } } @@ -200,14 +200,13 @@ def ingest(jobName, buildNumber, buildUrl, timestamp, previousSha, teamAssignmen def runTests() { parallel([ 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), - // skipping due to failures - // 'x-pack-intake-agent': { - // withEnv([ - // 'NODE_ENV=test' // Needed for jest tests only - // ]) { - // workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')() - // } - // }, + 'x-pack-intake-agent': { + withEnv([ + 'NODE_ENV=test' // Needed for jest tests only + ]) { + workers.intake('x-pack-intake', './test/scripts/jenkins_xpack.sh')() + } + }, 'kibana-oss-agent' : workers.functional( 'kibana-oss-tests', { kibanaPipeline.buildOss() }, diff --git a/x-pack/jest.config.js b/x-pack/jest.config.js index 8b3f717b40e6..8158987213cd 100644 --- a/x-pack/jest.config.js +++ b/x-pack/jest.config.js @@ -5,10 +5,7 @@ */ module.exports = { + preset: '@kbn/test', rootDir: '..', projects: ['/x-pack/plugins/*/jest.config.js'], - reporters: [ - 'default', - ['/packages/kbn-test/target/jest/junit_reporter', { reportName: 'X-Pack Jest Tests' }], - ], }; From 0ad88af8947e2a293538ea083019649165d19c4a Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Wed, 16 Dec 2020 14:25:16 -0600 Subject: [PATCH 13/38] [Workplace Search] Add unit tests for Add Source components (#86020) * Add mocks * Make mergeServerAndStaticData available to tests This method is needed to combine the 3 types of data to use in the logic files. Exporting this so that the mock data can be combined for testing in components. It was discovered that the serverData had the wrong typings. This was only discovered when actully mocking the real server data, so it was changed here. * Add tests for AddSourceHeader * Add tests for AddSourceList * Add tests for AvailableSourcesList * Add tests for ConfigCompleted * Add tests for ConfigDocsLinks * Add tests for ConfigurationIntro * Add tests for ConfigureCustom * Add tests for ConfigureOauth * Fix typo * Add coverage for missing functions The converage tool was complaining and this change assures formSubmitSuccess and handleFormSubmitError are covered * Fix mocks Needed an accountOnly source in this test so changed and update other tests where used * Add tests for ConfiguredSourcesList * Add tests for ReAuthenticate Also changes the syntax of the redirect to use the replace method for easier testing * Add sourceConfigData mock * Add tests for SaveConfig * Add tests for SaveCustom * Add tests for SourceFeatures * Add tests for ConnectInstance As with the ReAuthenticate component, changes the syntax of the redirect to use the replace method for easier testing. --- .../__mocks__/content_sources.mock.ts | 192 ++++++++++++++++++ .../add_source/add_source_header.test.tsx | 29 +++ .../add_source/add_source_list.test.tsx | 159 +++++++++++++++ .../available_sources_list.test.tsx | 46 +++++ .../add_source/config_completed.test.tsx | 46 +++++ .../add_source/config_completed.tsx | 20 +- .../add_source/config_docs_links.test.tsx | 46 +++++ .../add_source/configuration_intro.test.tsx | 29 +++ .../add_source/configure_custom.test.tsx | 58 ++++++ .../add_source/configure_oauth.test.tsx | 92 +++++++++ .../components/add_source/configure_oauth.tsx | 4 +- .../configured_sources_list.test.tsx | 35 ++++ .../add_source/configured_sources_list.tsx | 14 +- .../add_source/connect_instance.test.tsx | 177 ++++++++++++++++ .../add_source/connect_instance.tsx | 4 +- .../add_source/re_authenticate.test.tsx | 62 ++++++ .../components/add_source/re_authenticate.tsx | 2 +- .../add_source/save_config.test.tsx | 152 ++++++++++++++ .../add_source/save_custom.test.tsx | 36 ++++ .../add_source/source_features.test.tsx | 61 ++++++ .../views/content_sources/sources_logic.ts | 4 +- 21 files changed, 1253 insertions(+), 15 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts index c305ae9d5f7a..a3042f2df7ac 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/__mocks__/content_sources.mock.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { mergeServerAndStaticData } from '../views/content_sources/sources_logic'; +import { staticSourceData } from '../views/content_sources/source_data'; + export const contentSources = [ { id: '123', @@ -34,3 +37,192 @@ export const contentSources = [ boost: 0.5, }, ]; + +export const configuredSources = [ + { + serviceType: 'gmail', + name: 'Gmail', + configured: false, + needsPermissions: false, + accountContextOnly: true, + supportedByLicense: false, + privateSourcesEnabled: false, + }, + { + serviceType: 'confluence_cloud', + name: 'Confluence', + configured: true, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'confluence_server', + name: 'Confluence (Server)', + configured: true, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'dropbox', + name: 'Dropbox', + configured: true, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'github', + name: 'GitHub', + configured: true, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'github_enterprise_server', + name: 'GitHub Enterprise Server', + configured: true, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, +]; + +export const availableSources = [ + { + serviceType: 'google_drive', + name: 'Google Drive', + configured: false, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'jira_cloud', + name: 'Jira', + configured: false, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'jira_server', + name: 'Jira (Server)', + configured: false, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'one_drive', + name: 'OneDrive', + configured: false, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'salesforce', + name: 'Salesforce', + configured: false, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'salesforce_sandbox', + name: 'Salesforce Sandbox', + configured: false, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'service_now', + name: 'ServiceNow', + configured: false, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'share_point', + name: 'SharePoint Online', + configured: false, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'slack', + name: 'Slack', + configured: false, + needsPermissions: false, + accountContextOnly: true, + supportedByLicense: false, + privateSourcesEnabled: false, + }, + { + serviceType: 'zendesk', + name: 'Zendesk', + configured: false, + needsPermissions: false, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, + { + serviceType: 'custom', + name: 'Custom API Source', + configured: false, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + }, +]; + +export const mergedAvailableSources = mergeServerAndStaticData( + availableSources, + staticSourceData, + contentSources +); +export const mergedConfiguredSources = mergeServerAndStaticData( + configuredSources, + staticSourceData, + contentSources +); + +export const sourceConfigData = { + serviceType: 'confluence_cloud', + name: 'Confluence', + configured: true, + needsPermissions: true, + accountContextOnly: false, + supportedByLicense: true, + privateSourcesEnabled: false, + categories: ['wiki', 'atlassian', 'intranet'], + configuredFields: { + clientId: 'CyztADsSECRETCSAUCEh1a', + clientSecret: 'GSjJxqSECRETCSAUCEksHk', + baseUrl: 'https://mine.atlassian.net', + privateKey: '-----BEGIN PRIVATE KEY-----\nkeykeykeykey==\n-----END PRIVATE KEY-----\n', + publicKey: '-----BEGIN PUBLIC KEY-----\nkeykeykeykey\n-----END PUBLIC KEY-----\n', + consumerKey: 'elastic_enterprise_search_123', + }, +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx new file mode 100644 index 000000000000..c729ced8a1a4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.test.tsx @@ -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 React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiText, EuiTextColor } from '@elastic/eui'; + +import { SourceIcon } from '../../../../components/shared/source_icon'; + +import { AddSourceHeader } from './add_source_header'; + +describe('AddSourceHeader', () => { + const props = { + name: 'foo', + serviceType: 'gmail', + categories: ['bar', 'baz'], + }; + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(SourceIcon)).toHaveLength(1); + expect(wrapper.find(EuiTextColor).prop('children')).toEqual(props.name); + expect(wrapper.find(EuiText).last().prop('children')).toEqual('Bar, Baz'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx new file mode 100644 index 000000000000..184cd7ad4864 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.test.tsx @@ -0,0 +1,159 @@ +/* + * 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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockActions, setMockValues } from '../../../../../__mocks__'; +import { + contentSources, + configuredSources, + availableSources, +} from '../../../../__mocks__/content_sources.mock'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiEmptyPrompt, EuiFieldSearch } from '@elastic/eui'; + +import { Loading } from '../../../../../../applications/shared/loading'; +import { ViewContentHeader } from '../../../../components/shared/view_content_header'; + +import { + ADD_SOURCE_NEW_SOURCE_DESCRIPTION, + ADD_SOURCE_ORG_SOURCE_DESCRIPTION, + ADD_SOURCE_PRIVATE_SOURCE_DESCRIPTION, +} from './constants'; + +import { AddSourceList } from './add_source_list'; +import { AvailableSourcesList } from './available_sources_list'; +import { ConfiguredSourcesList } from './configured_sources_list'; + +describe('AddSourceList', () => { + const initializeSources = jest.fn(); + const resetSourcesState = jest.fn(); + + const mockValues = { + contentSources, + configuredSources, + availableSources, + dataLoading: false, + isOrganization: true, + }; + + beforeEach(() => { + setMockActions({ initializeSources, resetSourcesState }); + setMockValues(mockValues); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(AvailableSourcesList)).toHaveLength(1); + }); + + it('returns loading when loading', () => { + setMockValues({ + ...mockValues, + dataLoading: true, + }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + describe('filters sources', () => { + it('filters available sources', () => { + const wrapper = shallow(); + const input = wrapper.find('[data-test-subj="FilterSourcesInput"]'); + input.simulate('change', { target: { value: 'jira' } }); + + expect(wrapper.find(AvailableSourcesList).prop('sources')).toHaveLength(2); + expect(wrapper.find(ConfiguredSourcesList).prop('sources')).toHaveLength(0); + }); + + it('filters configured sources', () => { + const wrapper = shallow(); + const input = wrapper.find('[data-test-subj="FilterSourcesInput"]'); + input.simulate('change', { target: { value: 'confluence' } }); + + expect(wrapper.find(ConfiguredSourcesList).prop('sources')).toHaveLength(2); + expect(wrapper.find(AvailableSourcesList).prop('sources')).toHaveLength(0); + }); + + it('handles case where source has no name', () => { + setMockValues({ + ...mockValues, + configuredSources: [{ ...configuredSources[0], name: undefined }], + }); + const wrapper = shallow(); + const input = wrapper.find('[data-test-subj="FilterSourcesInput"]'); + input.simulate('change', { target: { value: 'not a real connector' } }); + + expect(wrapper.find(ConfiguredSourcesList).prop('sources')).toHaveLength(0); + }); + }); + + describe('content headings', () => { + it('should render correct organization heading with sources', () => { + const wrapper = shallow(); + + expect(wrapper.find(ViewContentHeader).prop('description')).toEqual( + ADD_SOURCE_ORG_SOURCE_DESCRIPTION + ); + }); + + it('should render correct organization heading without sources', () => { + setMockValues({ + ...mockValues, + contentSources: [], + }); + const wrapper = shallow(); + + expect(wrapper.find(ViewContentHeader).prop('description')).toEqual( + ADD_SOURCE_NEW_SOURCE_DESCRIPTION + ADD_SOURCE_ORG_SOURCE_DESCRIPTION + ); + }); + + it('should render correct account heading with sources', () => { + const wrapper = shallow(); + setMockValues({ + ...mockValues, + isOrganization: false, + }); + + expect(wrapper.find(ViewContentHeader).prop('description')).toEqual( + ADD_SOURCE_ORG_SOURCE_DESCRIPTION + ); + }); + + it('should render correct account heading without sources', () => { + setMockValues({ + ...mockValues, + isOrganization: false, + contentSources: [], + }); + const wrapper = shallow(); + + expect(wrapper.find(ViewContentHeader).prop('description')).toEqual( + ADD_SOURCE_NEW_SOURCE_DESCRIPTION + ADD_SOURCE_PRIVATE_SOURCE_DESCRIPTION + ); + }); + }); + + it('handles empty state for personal dashboard', () => { + setMockValues({ + ...mockValues, + isOrganization: false, + configuredSources: [], + }); + + const wrapper = shallow(); + + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + expect(wrapper.find(EuiFieldSearch)).toHaveLength(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.tsx new file mode 100644 index 000000000000..bb024178ea2f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.test.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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockValues } from '../../../../../__mocks__'; + +import { mergedAvailableSources } from '../../../../__mocks__/content_sources.mock'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiCard, EuiToolTip, EuiTitle } from '@elastic/eui'; + +import { AvailableSourcesList } from './available_sources_list'; + +describe('AvailableSourcesList', () => { + beforeEach(() => { + setMockValues({ hasPlatinumLicense: true }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiCard)).toHaveLength(11); + expect(wrapper.find(EuiTitle)).toHaveLength(1); + expect(wrapper.find('[data-test-subj="CustomAPISourceLink"]')).toHaveLength(1); + }); + + it('handles disabled federated sources for platinum licenses', () => { + setMockValues({ hasPlatinumLicense: false }); + const wrapper = shallow(); + + expect(wrapper.find(EuiToolTip)).toHaveLength(1); + }); + + it('handles empty state', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="AvailableSourceEmptyState"]')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.tsx new file mode 100644 index 000000000000..27c532ebaa63 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.test.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 from 'react'; +import { shallow } from 'enzyme'; + +import { ConfigCompleted } from './config_completed'; + +describe('ConfigCompleted', () => { + const advanceStep = jest.fn(); + const props = { + header:

Header

, + name: 'foo', + accountContextOnly: false, + privateSourcesEnabled: true, + advanceStep, + }; + + it('renders org context', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="OrgCanConnectMessage"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="PersonalConnectLinkMessage"]')).toHaveLength(0); + }); + + it('renders account context', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="ConfigCompletedPrivateSourcesDocsLink"]')).toHaveLength( + 1 + ); + expect(wrapper.find('[data-test-subj="OrgCanConnectMessage"]')).toHaveLength(0); + expect(wrapper.find('[data-test-subj="PersonalConnectLinkMessage"]')).toHaveLength(1); + }); + + it('renders private sources disabled message', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find('[data-test-subj="PrivateDisabledMessage"]')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx index 75d4f174c0aa..54c9440a05be 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx @@ -80,7 +80,7 @@ export const ConfigCompleted: React.FC = ({ {!accountContextOnly ? ( -

+

{i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.contentSource.configCompleted.orgCanConnect.message', { @@ -90,7 +90,7 @@ export const ConfigCompleted: React.FC = ({ )}

) : ( - +

{i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.contentSource.configCompleted.personalConnectLink.message', @@ -102,7 +102,7 @@ export const ConfigCompleted: React.FC = ({ )}

{!privateSourcesEnabled && ( -

+

= ({

)}

- + {CONFIG_COMPLETED_PRIVATE_SOURCES_DOCS_LINK}

@@ -143,7 +147,13 @@ export const ConfigCompleted: React.FC = ({ {!accountContextOnly && ( - + {i18n.translate( 'xpack.enterpriseSearch.workplaceSearch.contentSource.configCompleted.connect.button', { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.tsx new file mode 100644 index 000000000000..051f5cdfd44a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.test.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 from 'react'; +import { shallow } from 'enzyme'; + +import { EuiButtonEmpty } from '@elastic/eui'; + +import { ConfigDocsLinks } from './config_docs_links'; + +describe('ConfigDocsLinks', () => { + const props = { + name: 'foo', + documentationUrl: 'http://docs.elastic', + }; + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiButtonEmpty)).toHaveLength(1); + }); + + it('renders with applicationPortalUrl', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(EuiButtonEmpty)).toHaveLength(2); + expect(wrapper.find(EuiButtonEmpty).last().prop('children')).toEqual('foo Application Portal'); + }); + + it('renders with applicationLinkTitle', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(EuiButtonEmpty).last().prop('children')).toEqual('My App'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx new file mode 100644 index 000000000000..5aa1b1156776 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.test.tsx @@ -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 React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiText, EuiTitle } from '@elastic/eui'; + +import { ConfigurationIntro } from './configuration_intro'; + +describe('ConfigurationIntro', () => { + const advanceStep = jest.fn(); + const props = { + header:

Header

, + name: 'foo', + advanceStep, + }; + + it('renderscontext', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="ConfigureStepButton"]')).toHaveLength(1); + expect(wrapper.find(EuiText)).toHaveLength(5); + expect(wrapper.find(EuiTitle)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx new file mode 100644 index 000000000000..45c0e0eb9d2a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.test.tsx @@ -0,0 +1,58 @@ +/* + * 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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockActions, setMockValues } from '../../../../../__mocks__'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiForm, EuiFieldText } from '@elastic/eui'; + +import { ConfigureCustom } from './configure_custom'; + +describe('ConfigureCustom', () => { + const advanceStep = jest.fn(); + const setCustomSourceNameValue = jest.fn(); + + const props = { + header:

Header

, + helpText: 'I bet you could use a hand.', + advanceStep, + }; + + beforeEach(() => { + setMockActions({ setCustomSourceNameValue }); + setMockValues({ customSourceNameValue: 'name', buttonLoading: false }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiForm)).toHaveLength(1); + }); + + it('handles input change', () => { + const wrapper = shallow(); + const TEXT = 'changed for the better'; + const input = wrapper.find(EuiFieldText); + input.simulate('change', { target: { value: TEXT } }); + + expect(setCustomSourceNameValue).toHaveBeenCalledWith(TEXT); + }); + + it('handles form submission', () => { + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(advanceStep).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx new file mode 100644 index 000000000000..37cf516f1791 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.test.tsx @@ -0,0 +1,92 @@ +/* + * 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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockActions, setMockValues } from '../../../../../__mocks__'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiCheckboxGroup } from '@elastic/eui'; + +import { Loading } from '../../../../../../applications/shared/loading'; + +import { ConfigureOauth } from './configure_oauth'; + +describe('ConfigureOauth', () => { + const onFormCreated = jest.fn(); + const getPreContentSourceConfigData = jest.fn(); + const setSelectedGithubOrganizations = jest.fn(); + const createContentSource = jest.fn((_, formSubmitSuccess, handleFormSubmitError) => { + formSubmitSuccess(); + handleFormSubmitError(); + }); + + const values = { + currentServiceType: 'github', + githubOrganizations: ['foo', 'bar'], + selectedGithubOrganizationsMap: {}, + sectionLoading: false, + }; + + const props = { + header:

Header

, + name: 'Name', + onFormCreated, + }; + + beforeEach(() => { + setMockValues({ ...values }); + setMockActions({ + getPreContentSourceConfigData, + setSelectedGithubOrganizations, + createContentSource, + }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find('form')).toHaveLength(1); + }); + + it('handles loading state', () => { + setMockValues({ ...values, sectionLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + it('handles checkbox change', () => { + const wrapper = shallow(); + const checkboxGroup = wrapper.find(EuiCheckboxGroup); + checkboxGroup.simulate('change'); + + expect(checkboxGroup.prop('options')).toEqual([ + { + id: 'foo', + label: 'foo', + }, + { + id: 'bar', + label: 'bar', + }, + ]); + expect(setSelectedGithubOrganizations).toHaveBeenCalled(); + }); + + it('handles form submission', () => { + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(createContentSource).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx index da5434bf4fe7..555c7c7858be 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx @@ -64,14 +64,14 @@ export const ConfigureOauth: React.FC = ({ name, onFormCrea const handleChange = (option: string) => setSelectedGithubOrganizations(option); const formSubmitSuccess = () => onFormCreated(name); const handleFormSubmitError = () => setFormLoading(false); - const handleFormSubmut = (e: FormEvent) => { + const handleFormSubmit = (e: FormEvent) => { setFormLoading(true); e.preventDefault(); createContentSource(currentServiceType, formSubmitSuccess, handleFormSubmitError); }; const configfieldsForm = ( -
+ { + const props = { + sources: mergedConfiguredSources, + isOrganization: true, + }; + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="UnConnectedTooltip"]')).toHaveLength(5); + expect(wrapper.find('[data-test-subj="AccountOnlyTooltip"]')).toHaveLength(1); + expect(wrapper.find(EuiPanel)).toHaveLength(6); + }); + + it('handles empty state', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="ConfiguredSourceEmptyState"]')).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index a24951a8e54c..0f7d35590583 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -42,7 +42,10 @@ export const ConfiguredSourcesList: React.FC = ({ isOrganization, }) => { const unConnectedTooltip = ( - + @@ -50,7 +53,10 @@ export const ConfiguredSourcesList: React.FC = ({ ); const accountOnlyTooltip = ( - + @@ -107,7 +113,9 @@ export const ConfiguredSourcesList: React.FC = ({ ); - const emptyState =

{CONFIGURED_SOURCES_EMPTY_STATE}

; + const emptyState = ( +

{CONFIGURED_SOURCES_EMPTY_STATE}

+ ); return ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx new file mode 100644 index 000000000000..43adc0e68177 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.test.tsx @@ -0,0 +1,177 @@ +/* + * 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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockActions, setMockValues } from '../../../../../__mocks__'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiBadge, EuiCallOut, EuiSwitch } from '@elastic/eui'; + +import { FeatureIds } from '../../../../types'; +import { staticSourceData } from '../../source_data'; +import { ConnectInstance } from './connect_instance'; + +describe('ConnectInstance', () => { + // Needed to mock redirect window.location.replace(oauthUrl) + const mockReplace = jest.fn(); + const mockWindow = { + value: { + replace: mockReplace, + }, + writable: true, + }; + Object.defineProperty(window, 'location', mockWindow); + + const onFormCreated = jest.fn(); + const setSourceLoginValue = jest.fn(); + const setSourcePasswordValue = jest.fn(); + const setSourceSubdomainValue = jest.fn(); + const setSourceIndexPermissionsValue = jest.fn(); + const getSourceConnectData = jest.fn((_, redirectOauth) => { + redirectOauth(); + }); + const createContentSource = jest.fn((_, redirectFormCreated, handleFormSubmitError) => { + redirectFormCreated(); + handleFormSubmitError(); + }); + + const credentialsSourceData = staticSourceData[13]; + const oauthSourceData = staticSourceData[0]; + const subdomainSourceData = staticSourceData[16]; + const privateSourceData = staticSourceData[6]; + + const props = { + ...credentialsSourceData, + needsPermissions: true, + onFormCreated, + header:

Header

, + }; + + const oauthProps = { + ...oauthSourceData, + needsPermissions: true, + onFormCreated, + header:

Header

, + }; + + const values = { + loginValue: 'login', + passwordValue: 'pw123', + indexPermissionsValue: true, + subdomainValue: 'foo', + isOrganization: true, + hasPlatinumLicense: true, + }; + + beforeEach(() => { + setMockActions({ + getSourceConnectData, + createContentSource, + setSourceLoginValue, + setSourcePasswordValue, + setSourceSubdomainValue, + setSourceIndexPermissionsValue, + }); + setMockValues({ ...values }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find('form')).toHaveLength(1); + }); + + it('handles form submission with credentials source', () => { + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(createContentSource).toHaveBeenCalled(); + }); + + it('handles username input change', () => { + const wrapper = shallow(); + const TEXT = 'username'; + const input = wrapper.find('EuiFieldText[name="login"]'); + input.simulate('change', { target: { value: TEXT } }); + + expect(setSourceLoginValue).toHaveBeenCalledWith(TEXT); + }); + + it('handles password input change', () => { + const wrapper = shallow(); + const TEXT = 'password'; + const input = wrapper.find('EuiFieldText[name="password"]'); + input.simulate('change', { target: { value: TEXT } }); + + expect(setSourcePasswordValue).toHaveBeenCalledWith(TEXT); + }); + + it('handles subdomain input change', () => { + const wrapper = shallow( + + ); + const TEXT = 'subdomain'; + const input = wrapper.find('EuiFieldText[name="subdomain"]'); + input.simulate('change', { target: { value: TEXT } }); + + expect(setSourceSubdomainValue).toHaveBeenCalledWith(TEXT); + }); + + it('shows correct feature badges', () => { + setMockValues({ ...values, isOrganization: false }); + const wrapper = shallow(); + + expect(wrapper.find(EuiBadge)).toHaveLength(2); + }); + + it('shows no feature badges', () => { + setMockValues({ ...values, isOrganization: false }); + const features = { ...privateSourceData.features }; + features.platinumPrivateContext = [FeatureIds.SyncFrequency]; + const wrapper = shallow(); + + expect(wrapper.find(EuiBadge)).toHaveLength(0); + }); + + it('calls handler on click', () => { + const wrapper = shallow(); + wrapper.find(EuiSwitch).simulate('change', { target: { checked: true } }); + + expect(setSourceIndexPermissionsValue).toHaveBeenCalledWith(true); + }); + + it('handles form submission with oauth source', () => { + jest.spyOn(window.location, 'replace').mockImplementationOnce(mockReplace); + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(getSourceConnectData).toHaveBeenCalled(); + expect(mockReplace).toHaveBeenCalled(); + }); + + it('renders permissions link', () => { + const wrapper = shallow(); + + expect(wrapper.find('[data-test-subj="NeedsPermissionsMessage"]')).toHaveLength(1); + }); + + it('shows permissions callout', () => { + setMockValues({ ...values, indexPermissionsValue: false }); + const wrapper = shallow(); + + expect(wrapper.find(EuiCallOut)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx index 31c1d901a894..6fe87290737f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx @@ -95,7 +95,7 @@ export const ConnectInstance: React.FC = ({ setSourceIndexPermissionsValue(needsPermissions && isOrganization && hasPlatinumLicense); }, []); - const redirectOauth = (oauthUrl: string) => (window.location.href = oauthUrl); + const redirectOauth = (oauthUrl: string) => window.location.replace(oauthUrl); const redirectFormCreated = () => onFormCreated(name); const onOauthFormSubmit = () => getSourceConnectData(serviceType, redirectOauth); const handleFormSubmitError = () => setFormLoading(false); @@ -199,7 +199,7 @@ export const ConnectInstance: React.FC = ({ {!needsPermissions && ( - + { + // Needed to mock redirect window.location.replace(oauthUrl) + const mockReplace = jest.fn(); + const mockWindow = { + value: { + replace: mockReplace, + }, + writable: true, + }; + Object.defineProperty(window, 'location', mockWindow); + + const getSourceReConnectData = jest.fn(); + + const values = { + sourceConnectData: { oauthUrl: 'http://oau.th' }, + }; + + const props = { + header:

Header

, + name: 'Name', + }; + + beforeEach(() => { + setMockValues({ ...values }); + setMockActions({ + getSourceReConnectData, + }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find('form')).toHaveLength(1); + }); + + it('handles form submission', () => { + jest.spyOn(window.location, 'replace').mockImplementationOnce(mockReplace); + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(mockReplace).toHaveBeenCalledWith(values.sourceConnectData.oauthUrl); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx index a7ccbf221b53..480092388c1a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx @@ -43,7 +43,7 @@ export const ReAuthenticate: React.FC = ({ name, header }) const handleFormSubmit = (e: FormEvent) => { e.preventDefault(); setFormLoading(true); - window.location.href = oauthUrl; + window.location.replace(oauthUrl); }; return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx new file mode 100644 index 000000000000..c92427035646 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.test.tsx @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { setMockActions, setMockValues } from '../../../../../__mocks__'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiSteps, EuiButton, EuiButtonEmpty } from '@elastic/eui'; + +import { sourceConfigData } from '../../../../__mocks__/content_sources.mock'; +import { staticSourceData } from '../../source_data'; + +import { ApiKey } from '../../../../components/shared/api_key'; +import { ConfigDocsLinks } from './config_docs_links'; + +import { SaveConfig } from './save_config'; + +describe('SaveConfig', () => { + const advanceStep = jest.fn(); + const goBackStep = jest.fn(); + const onDeleteConfig = jest.fn(); + const setClientIdValue = jest.fn(); + const setClientSecretValue = jest.fn(); + const setBaseUrlValue = jest.fn(); + + const credentialsSourceConfig = staticSourceData[0].configuration; + const needsBaseUrlSourceConfig = staticSourceData[1].configuration; + const publicKeySourceConfig = staticSourceData[2].configuration; + const accountContextOnlySourceConfig = staticSourceData[6].configuration; + + const props = { + name: 'foo', + configuration: credentialsSourceConfig, + advanceStep, + goBackStep, + onDeleteConfig, + header:

Header

, + }; + + const values = { + sourceConfigData, + buttonLoading: false, + clientIdValue: 'foo', + clientSecretValue: 'bar', + baseUrlValue: 'http://foo.baz', + hasPlatinumLicense: true, + }; + + beforeEach(() => { + setMockActions({ + setClientIdValue, + setClientSecretValue, + setBaseUrlValue, + }); + setMockValues({ ...values }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiSteps)).toHaveLength(1); + }); + + it('handles form submission', () => { + const wrapper = shallow(); + + const preventDefault = jest.fn(); + wrapper.find('form').simulate('submit', { preventDefault }); + + expect(preventDefault).toHaveBeenCalled(); + expect(advanceStep).toHaveBeenCalled(); + }); + + describe('credentials item', () => { + it('handles Client Id change', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + const input = steps.dive().find('[name="client-id"]'); + input.simulate('change', { target: { value: 'client-id' } }); + + expect(setClientIdValue).toHaveBeenCalledWith('client-id'); + }); + + it('handles Client secret change', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + const input = steps.dive().find('[name="client-secret"]'); + input.simulate('change', { target: { value: 'client-secret' } }); + + expect(setClientSecretValue).toHaveBeenCalledWith('client-secret'); + }); + }); + + describe('public key item', () => { + const publicProps = { + ...props, + configuration: publicKeySourceConfig, + }; + + it('renders form controls', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + + expect(steps.dive().find(EuiButton)).toHaveLength(2); + expect(steps.dive().find(EuiButtonEmpty)).toHaveLength(1); + }); + + it('renders ApiKeys', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + + expect(steps.dive().find(ApiKey)).toHaveLength(2); + expect(steps.dive().find(ConfigDocsLinks)).toHaveLength(1); + }); + + it('handles Base URI change', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + const input = steps.dive().find('[name="base-uri"]'); + input.simulate('change', { target: { value: 'base-uri' } }); + + expect(setBaseUrlValue).toHaveBeenCalledWith('base-uri'); + }); + }); + + it('handles Base URL change', () => { + const wrapper = shallow(); + const steps = wrapper.find(EuiSteps); + const input = steps.dive().find('[name="base-url"]'); + input.simulate('change', { target: { value: 'base-url' } }); + + expect(setBaseUrlValue).toHaveBeenCalledWith('base-url'); + }); + + it('hides form controls for non-platinum users on account-only source', () => { + setMockValues({ ...values, hasPlatinumLicense: false }); + + const wrapper = shallow( + + ); + const steps = wrapper.find(EuiSteps); + + expect(steps.dive().find(EuiButton)).toHaveLength(2); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.tsx new file mode 100644 index 000000000000..65a4fd2757c0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.test.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 { shallow } from 'enzyme'; + +import { EuiLink, EuiPanel, EuiTitle } from '@elastic/eui'; + +import { EuiLinkTo } from '../../../../../shared/react_router_helpers'; + +import { SaveCustom } from './save_custom'; + +describe('SaveCustom', () => { + const props = { + documentationUrl: 'http://string.boolean', + newCustomSource: { + accessToken: 'dsgfsd', + key: 'sdfs', + name: 'source', + id: '12e1', + }, + isOrganization: true, + header:

Header

, + }; + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiPanel)).toHaveLength(1); + expect(wrapper.find(EuiTitle)).toHaveLength(5); + expect(wrapper.find(EuiLinkTo)).toHaveLength(1); + expect(wrapper.find(EuiLink)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx new file mode 100644 index 000000000000..f5bcfe1354c0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.test.tsx @@ -0,0 +1,61 @@ +/* + * 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 '../../../../../__mocks__/kea.mock'; +import '../../../../../__mocks__/shallow_useeffect.mock'; + +import { mountAsync, setMockValues } from '../../../../../__mocks__'; + +import React from 'react'; + +import { EuiPanel } from '@elastic/eui'; + +import { SourceFeatures } from './source_features'; + +import { staticSourceData } from '../../source_data'; + +describe('SourceFeatures', () => { + const { features, objTypes } = staticSourceData[0]; + + const props = { + features, + objTypes, + name: 'foo', + }; + + it('renders hasPlatinumLicense & isOrganization', async () => { + setMockValues({ hasPlatinumLicense: true, isOrganization: true }); + const wrapper = await mountAsync(, { i18n: true }); + + expect(wrapper.find('FeaturesRouter[featureId="SyncFrequency"]')).toHaveLength(1); + expect(wrapper.find('FeaturesRouter[featureId="SyncedItems"]')).toHaveLength(1); + }); + + it('renders !hasPlatinumLicense & isOrganization', async () => { + setMockValues({ hasPlatinumLicense: false, isOrganization: true }); + const wrapper = await mountAsync(, { i18n: true }); + + expect(wrapper.find('FeaturesRouter[featureId="SyncFrequency"]')).toHaveLength(1); + expect(wrapper.find('FeaturesRouter[featureId="SyncedItems"]')).toHaveLength(1); + expect(wrapper.find('FeaturesRouter[featureId="GlobalAccessPermissions"]')).toHaveLength(1); + }); + + it('renders hasPlatinumLicense & !isOrganization', async () => { + setMockValues({ hasPlatinumLicense: true, isOrganization: false }); + const wrapper = await mountAsync(, { i18n: true }); + + expect(wrapper.find('FeaturesRouter[featureId="Private"]')).toHaveLength(1); + expect(wrapper.find('FeaturesRouter[featureId="SyncedItems"]')).toHaveLength(1); + expect(wrapper.find('FeaturesRouter[featureId="SyncedItems"]')).toHaveLength(1); + }); + + it('renders !hasPlatinumLicense & !isOrganization', async () => { + setMockValues({ hasPlatinumLicense: false, isOrganization: false }); + const wrapper = await mountAsync(, { i18n: true }); + + expect(wrapper.find('IncludedFeatures').find(EuiPanel)).toHaveLength(0); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts index 4a7d44a936d9..cb8df1d31219 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/sources_logic.ts @@ -282,8 +282,8 @@ const updateSourcesOnToggle = ( * can diplay "Add New" instead of "Connect", the latter of which is displated only when a connector * has been configured but there are no connected sources yet. */ -const mergeServerAndStaticData = ( - serverData: ContentSourceDetails[], +export const mergeServerAndStaticData = ( + serverData: Connector[], staticData: SourceDataItem[], contentSources: ContentSourceDetails[] ) => { From e863bfb1981bb0a367fe6582a2c74db2e2fc6d2b Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 16 Dec 2020 15:51:51 -0500 Subject: [PATCH 14/38] [Alerting UI] Fixing bug when switching between threshold comparators (#85844) * Fixing bug when switching between comparators with different number of inputs * Triggering onThresholdChange call on next render cycle --- .../expression_items/threshold.test.tsx | 30 ++++++++++++++ .../common/expression_items/threshold.tsx | 39 ++++++++++--------- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.test.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.test.tsx index c8d2b10274cd..2a31537f9655 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.test.tsx @@ -108,4 +108,34 @@ describe('threshold expression', () => { expect(onChangeSelectedThreshold).toHaveBeenCalled(); expect(onChangeSelectedThresholdComparator).toHaveBeenCalled(); }); + + it('renders the correct number of threshold inputs', async () => { + const wrapper = mountWithIntl( + '} + threshold={[10]} + errors={{ threshold0: [], threshold1: [] }} + onChangeSelectedThreshold={jest.fn()} + onChangeSelectedThresholdComparator={jest.fn()} + /> + ); + + wrapper.find('[data-test-subj="thresholdPopover"]').first().simulate('click'); + expect(wrapper.find('[data-test-subj="comparatorOptionsComboBox"]').exists()).toBeTruthy(); + expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(1); + + wrapper + .find('[data-test-subj="comparatorOptionsComboBox"]') + .last() + .simulate('change', { target: { value: 'between' } }); + wrapper.update(); + expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(2); + + wrapper + .find('[data-test-subj="comparatorOptionsComboBox"]') + .last() + .simulate('change', { target: { value: '<' } }); + wrapper.update(); + expect(wrapper.find('input[data-test-subj="alertThresholdInput"]').length).toEqual(1); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx index bdf30414b68b..8fabf4e9aeb2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/threshold.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, Fragment } from 'react'; +import React, { useEffect, useState, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiExpression, @@ -58,6 +58,10 @@ export const ThresholdExpression = ({ }: ThresholdExpressionProps) => { const comparators = customComparators ?? builtInComparators; const [alertThresholdPopoverOpen, setAlertThresholdPopoverOpen] = useState(false); + const [comparator, setComparator] = useState(thresholdComparator); + const [numRequiredThresholds, setNumRequiredThresholds] = useState( + comparators[thresholdComparator].requiredValues + ); const andThresholdText = i18n.translate( 'xpack.triggersActionsUI.common.expressionItems.threshold.andLabel', @@ -66,15 +70,23 @@ export const ThresholdExpression = ({ } ); + useEffect(() => { + const updateThresholdValue = comparators[comparator].requiredValues !== numRequiredThresholds; + if (updateThresholdValue) { + const thresholdValues = threshold.slice(0, comparators[comparator].requiredValues); + onChangeSelectedThreshold(thresholdValues); + setNumRequiredThresholds(comparators[comparator].requiredValues); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [comparator]); + return (
setAlertThresholdPopoverOpen(false)}> - <>{comparators[thresholdComparator].text} + <>{comparators[comparator].text} { - const updateThresholdValue = - comparators[thresholdComparator].requiredValues !== - comparators[e.target.value].requiredValues; + setComparator(e.target.value); onChangeSelectedThresholdComparator(e.target.value); - if (updateThresholdValue) { - const thresholdValues = threshold.slice( - 0, - comparators[e.target.value].requiredValues - ); - onChangeSelectedThreshold(thresholdValues); - } }} options={Object.values(comparators).map(({ text, value }) => { return { text, value }; })} /> - {Array.from(Array(comparators[thresholdComparator].requiredValues)).map((_notUsed, i) => { + {Array.from(Array(numRequiredThresholds)).map((_notUsed, i) => { return ( {i > 0 ? ( From 5b9e2855820108bb535d8122999ba9141d79c026 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Wed, 16 Dec 2020 21:58:14 +0100 Subject: [PATCH 15/38] [Lens] (Accessibility) focus on adding/removing layers (#84900) --- .../config_panel/config_panel.test.tsx | 169 ++++ .../config_panel/config_panel.tsx | 59 +- .../config_panel/layer_panel.scss | 5 + .../config_panel/layer_panel.test.tsx | 1 + .../editor_frame/config_panel/layer_panel.tsx | 814 +++++++++--------- .../editor_frame/editor_frame.test.tsx | 6 +- .../editor_frame/frame_layout.scss | 2 +- 7 files changed, 643 insertions(+), 413 deletions(-) create mode 100644 x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx new file mode 100644 index 000000000000..70c4fb556722 --- /dev/null +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx @@ -0,0 +1,169 @@ +/* + * 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 { act } from 'react-dom/test-utils'; +import { + createMockVisualization, + createMockFramePublicAPI, + createMockDatasource, + DatasourceMock, +} from '../../mocks'; +import { Visualization } from '../../../types'; +import { mountWithIntl } from '@kbn/test/jest'; +import { LayerPanels } from './config_panel'; +import { LayerPanel } from './layer_panel'; +import { coreMock } from 'src/core/public/mocks'; +import { generateId } from '../../../id_generator'; + +jest.mock('../../../id_generator'); + +describe('ConfigPanel', () => { + let mockVisualization: jest.Mocked; + let mockVisualization2: jest.Mocked; + let mockDatasource: DatasourceMock; + const frame = createMockFramePublicAPI(); + + function getDefaultProps() { + frame.datasourceLayers = { + first: mockDatasource.publicAPIMock, + }; + return { + activeVisualizationId: 'vis1', + visualizationMap: { + vis1: mockVisualization, + vis2: mockVisualization2, + }, + activeDatasourceId: 'ds1', + datasourceMap: { + ds1: mockDatasource, + }, + activeVisualization: ({ + ...mockVisualization, + getLayerIds: () => Object.keys(frame.datasourceLayers), + appendLayer: true, + } as unknown) as Visualization, + datasourceStates: { + ds1: { + isLoading: false, + state: 'state', + }, + }, + visualizationState: 'state', + updateVisualization: jest.fn(), + updateDatasource: jest.fn(), + updateAll: jest.fn(), + framePublicAPI: frame, + dispatch: jest.fn(), + core: coreMock.createStart(), + }; + } + + beforeEach(() => { + mockVisualization = { + ...createMockVisualization(), + id: 'testVis', + visualizationTypes: [ + { + icon: 'empty', + id: 'testVis', + label: 'TEST1', + }, + ], + }; + + mockVisualization2 = { + ...createMockVisualization(), + + id: 'testVis2', + visualizationTypes: [ + { + icon: 'empty', + id: 'testVis2', + label: 'TEST2', + }, + ], + }; + + mockVisualization.getLayerIds.mockReturnValue(Object.keys(frame.datasourceLayers)); + mockDatasource = createMockDatasource('ds1'); + }); + + describe('focus behavior when adding or removing layers', () => { + it('should focus the only layer when resetting the layer', () => { + const component = mountWithIntl(); + const firstLayerFocusable = component + .find(LayerPanel) + .first() + .find('section') + .first() + .instance(); + act(() => { + component.find('[data-test-subj="lnsLayerRemove"]').first().simulate('click'); + }); + const focusedEl = document.activeElement; + expect(focusedEl).toEqual(firstLayerFocusable); + }); + + it('should focus the second layer when removing the first layer', () => { + const defaultProps = getDefaultProps(); + // overwriting datasourceLayers to test two layers + frame.datasourceLayers = { + first: mockDatasource.publicAPIMock, + second: mockDatasource.publicAPIMock, + }; + const component = mountWithIntl(); + const secondLayerFocusable = component + .find(LayerPanel) + .at(1) + .find('section') + .first() + .instance(); + act(() => { + component.find('[data-test-subj="lnsLayerRemove"]').at(0).simulate('click'); + }); + const focusedEl = document.activeElement; + expect(focusedEl).toEqual(secondLayerFocusable); + }); + + it('should focus the first layer when removing the second layer', () => { + const defaultProps = getDefaultProps(); + // overwriting datasourceLayers to test two layers + frame.datasourceLayers = { + first: mockDatasource.publicAPIMock, + second: mockDatasource.publicAPIMock, + }; + const component = mountWithIntl(); + const firstLayerFocusable = component + .find(LayerPanel) + .first() + .find('section') + .first() + .instance(); + act(() => { + component.find('[data-test-subj="lnsLayerRemove"]').at(2).simulate('click'); + }); + const focusedEl = document.activeElement; + expect(focusedEl).toEqual(firstLayerFocusable); + }); + + it('should focus the added layer', () => { + (generateId as jest.Mock).mockReturnValue(`second`); + const dispatch = jest.fn((x) => { + if (x.subType === 'ADD_LAYER') { + frame.datasourceLayers.second = mockDatasource.publicAPIMock; + } + }); + + const component = mountWithIntl(); + act(() => { + component.find('[data-test-subj="lnsLayerAddButton"]').first().simulate('click'); + }); + const focusedEl = document.activeElement; + expect(focusedEl?.children[0].getAttribute('data-test-subj')).toEqual('lns-layerPanel-1'); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx index 608a7b110b7d..ec1a5c226d35 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx @@ -5,7 +5,7 @@ */ import './config_panel.scss'; -import React, { useMemo, memo } from 'react'; +import React, { useMemo, memo, useEffect, useState, useCallback } from 'react'; import { EuiFlexItem, EuiToolTip, EuiButton, EuiForm } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Visualization } from '../../../types'; @@ -24,7 +24,51 @@ export const ConfigPanelWrapper = memo(function ConfigPanelWrapper(props: Config ) : null; }); -function LayerPanels( +function useFocusUpdate(layerIds: string[]) { + const [nextFocusedLayerId, setNextFocusedLayerId] = useState(null); + const [layerRefs, setLayersRefs] = useState>({}); + + useEffect(() => { + const focusable = nextFocusedLayerId && layerRefs[nextFocusedLayerId]; + if (focusable) { + focusable.focus(); + setNextFocusedLayerId(null); + } + }, [layerIds, layerRefs, nextFocusedLayerId]); + + const setLayerRef = useCallback((layerId, el) => { + if (el) { + setLayersRefs((refs) => ({ + ...refs, + [layerId]: el, + })); + } + }, []); + + const removeLayerRef = useCallback( + (layerId) => { + if (layerIds.length <= 1) { + return setNextFocusedLayerId(layerId); + } + + const removedLayerIndex = layerIds.findIndex((l) => l === layerId); + const nextFocusedLayerIdId = + removedLayerIndex === 0 ? layerIds[1] : layerIds[removedLayerIndex - 1]; + + setLayersRefs((refs) => { + const newLayerRefs = { ...refs }; + delete newLayerRefs[layerId]; + return newLayerRefs; + }); + return setNextFocusedLayerId(nextFocusedLayerIdId); + }, + [layerIds] + ); + + return { setNextFocusedLayerId, removeLayerRef, setLayerRef }; +} + +export function LayerPanels( props: ConfigPanelWrapperProps & { activeDatasourceId: string; activeVisualization: Visualization; @@ -37,6 +81,10 @@ function LayerPanels( activeDatasourceId, datasourceMap, } = props; + + const layerIds = activeVisualization.getLayerIds(visualizationState); + const { setNextFocusedLayerId, removeLayerRef, setLayerRef } = useFocusUpdate(layerIds); + const setVisualizationState = useMemo( () => (newState: unknown) => { dispatch({ @@ -85,13 +133,13 @@ function LayerPanels( }, [dispatch] ); - const layerIds = activeVisualization.getLayerIds(visualizationState); return ( {layerIds.map((layerId, index) => ( ))} @@ -138,18 +187,20 @@ function LayerPanels( defaultMessage: 'Add layer', })} onClick={() => { + const id = generateId(); dispatch({ type: 'UPDATE_STATE', subType: 'ADD_LAYER', updater: (state) => appendLayer({ activeVisualization, - generateId, + generateId: () => id, trackUiEvent, activeDatasource: datasourceMap[activeDatasourceId], state, }), }); + setNextFocusedLayerId(id); }} iconType="plusInCircleFilled" /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.scss index 0f512e535c9d..2ed91b962ff1 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.scss @@ -1,5 +1,10 @@ .lnsLayerPanel { margin-bottom: $euiSizeS; + + // disable focus ring for mouse clicks, leave it for keyboard users + &:focus:not(:focus-visible) { + animation: none !important; // sass-lint:disable-line no-important + } } .lnsLayerPanel__sourceFlexItem { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx index bdf6f9aa4164..bbc801ba01b7 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx @@ -59,6 +59,7 @@ describe('LayerPanel', () => { dispatch: jest.fn(), core: coreMock.createStart(), index: 0, + setLayerRef: jest.fn(), }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index 5a068e711ff5..43c44dc3c07f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -74,6 +74,7 @@ export function LayerPanel( newVisualizationState: unknown ) => void; onRemoveLayer: () => void; + setLayerRef: (layerId: string, instance: HTMLDivElement | null) => void; } ) { const dragDropContext = useContext(DragContext); @@ -81,13 +82,18 @@ export function LayerPanel( initialActiveDimensionState ); - const { framePublicAPI, layerId, isOnlyLayer, onRemoveLayer, index } = props; + const { framePublicAPI, layerId, isOnlyLayer, onRemoveLayer, setLayerRef, index } = props; const datasourcePublicAPI = framePublicAPI.datasourceLayers[layerId]; useEffect(() => { setActiveDimension(initialActiveDimensionState); }, [props.activeVisualizationId]); + const setLayerRefMemoized = React.useCallback((el) => setLayerRef(layerId, el), [ + layerId, + setLayerRef, + ]); + if ( !datasourcePublicAPI || !props.activeVisualizationId || @@ -131,467 +137,465 @@ export function LayerPanel( const columnLabelMap = layerDatasource.uniqueLabels(layerDatasourceConfigProps.state); return ( - - - - - - - {layerDatasource && ( - - { - const newState = - typeof updater === 'function' ? updater(layerDatasourceState) : updater; - // Look for removed columns - const nextPublicAPI = layerDatasource.getPublicAPI({ - state: newState, - layerId, - }); - const nextTable = new Set( - nextPublicAPI.getTableSpec().map(({ columnId }) => columnId) - ); - const removed = datasourcePublicAPI - .getTableSpec() - .map(({ columnId }) => columnId) - .filter((columnId) => !nextTable.has(columnId)); - let nextVisState = props.visualizationState; - removed.forEach((columnId) => { - nextVisState = activeVisualization.removeDimension({ - layerId, - columnId, - prevState: nextVisState, - }); - }); - - props.updateAll(datasourceId, newState, nextVisState); - }, +
+ + + + - )} - - + {layerDatasource && ( + + { + const newState = + typeof updater === 'function' ? updater(layerDatasourceState) : updater; + // Look for removed columns + const nextPublicAPI = layerDatasource.getPublicAPI({ + state: newState, + layerId, + }); + const nextTable = new Set( + nextPublicAPI.getTableSpec().map(({ columnId }) => columnId) + ); + const removed = datasourcePublicAPI + .getTableSpec() + .map(({ columnId }) => columnId) + .filter((columnId) => !nextTable.has(columnId)); + let nextVisState = props.visualizationState; + removed.forEach((columnId) => { + nextVisState = activeVisualization.removeDimension({ + layerId, + columnId, + prevState: nextVisState, + }); + }); - {groups.map((group, groupIndex) => { - const newId = generateId(); - const isMissing = !isEmptyLayer && group.required && group.accessors.length === 0; + props.updateAll(datasourceId, newState, nextVisState); + }, + }} + /> + + )} + - return ( - {group.groupLabel}
} - labelType="legend" - key={groupIndex} - isInvalid={isMissing} - error={ - isMissing ? ( -
- {i18n.translate('xpack.lens.editorFrame.requiredDimensionWarningLabel', { - defaultMessage: 'Required dimension', - })} -
- ) : ( - [] - ) - } - > - <> - - {group.accessors.map((accessorConfig) => { - const accessor = accessorConfig.columnId; - const { dragging } = dragDropContext; - const dragType = - isDraggedOperation(dragging) && accessor === dragging.columnId - ? 'move' - : isDraggedOperation(dragging) && group.groupId === dragging.groupId - ? 'reorder' - : 'copy'; + - const dropType = isDraggedOperation(dragging) - ? group.groupId !== dragging.groupId - ? 'replace' - : 'reorder' - : 'add'; + {groups.map((group, groupIndex) => { + const newId = generateId(); + const isMissing = !isEmptyLayer && group.required && group.accessors.length === 0; - const isFromCompatibleGroup = - dragging?.groupId !== group.groupId && - layerDatasource.canHandleDrop({ - ...layerDatasourceDropProps, - columnId: accessor, - filterOperations: group.filterOperations, - }); + return ( + {group.groupLabel}
} + labelType="legend" + key={groupIndex} + isInvalid={isMissing} + error={ + isMissing ? ( +
+ {i18n.translate('xpack.lens.editorFrame.requiredDimensionWarningLabel', { + defaultMessage: 'Required dimension', + })} +
+ ) : ( + [] + ) + } + > + <> + + {group.accessors.map((accessorConfig) => { + const accessor = accessorConfig.columnId; + const { dragging } = dragDropContext; + const dragType = + isDraggedOperation(dragging) && accessor === dragging.columnId + ? 'move' + : isDraggedOperation(dragging) && group.groupId === dragging.groupId + ? 'reorder' + : 'copy'; - const isFromTheSameGroup = - isDraggedOperation(dragging) && - dragging.groupId === group.groupId && - dragging.columnId !== accessor; + const dropType = isDraggedOperation(dragging) + ? group.groupId !== dragging.groupId + ? 'replace' + : 'reorder' + : 'add'; - const isDroppable = isDraggedOperation(dragging) - ? dragType === 'reorder' - ? isFromTheSameGroup - : isFromCompatibleGroup - : layerDatasource.canHandleDrop({ + const isFromCompatibleGroup = + dragging?.groupId !== group.groupId && + layerDatasource.canHandleDrop({ ...layerDatasourceDropProps, columnId: accessor, filterOperations: group.filterOperations, }); - return ( + const isFromTheSameGroup = + isDraggedOperation(dragging) && + dragging.groupId === group.groupId && + dragging.columnId !== accessor; + + const isDroppable = isDraggedOperation(dragging) + ? dragType === 'reorder' + ? isFromTheSameGroup + : isFromCompatibleGroup + : layerDatasource.canHandleDrop({ + ...layerDatasourceDropProps, + columnId: accessor, + filterOperations: group.filterOperations, + }); + + return ( + + typeof a === 'string' ? a : a.columnId + )} + className={'lnsLayerPanel__dimensionContainer'} + value={{ + columnId: accessor, + groupId: group.groupId, + layerId, + id: accessor, + }} + isValueEqual={isSameConfiguration} + label={columnLabelMap[accessor]} + droppable={dragging && isDroppable} + dropTo={(dropTargetId: string) => { + layerDatasource.onDrop({ + isReorder: true, + ...layerDatasourceDropProps, + droppedItem: { + columnId: accessor, + groupId: group.groupId, + layerId, + id: accessor, + }, + columnId: dropTargetId, + filterOperations: group.filterOperations, + }); + }} + onDrop={(droppedItem) => { + const isReorder = + isDraggedOperation(droppedItem) && + droppedItem.groupId === group.groupId && + droppedItem.columnId !== accessor; + + const dropResult = layerDatasource.onDrop({ + isReorder, + ...layerDatasourceDropProps, + droppedItem, + columnId: accessor, + filterOperations: group.filterOperations, + }); + if (typeof dropResult === 'object') { + // When a column is moved, we delete the reference to the old + props.updateVisualization( + activeVisualization.removeDimension({ + layerId, + columnId: dropResult.deleted, + prevState: props.visualizationState, + }) + ); + } + }} + > +
+ { + if (activeId) { + setActiveDimension(initialActiveDimensionState); + } else { + setActiveDimension({ + isNew: false, + activeGroup: group, + activeId: accessor, + }); + } + }} + aria-label={triggerLinkA11yText(columnLabelMap[accessor])} + title={triggerLinkA11yText(columnLabelMap[accessor])} + > + + + + + { + trackUiEvent('indexpattern_dimension_removed'); + props.updateAll( + datasourceId, + layerDatasource.removeColumn({ + layerId, + columnId: accessor, + prevState: layerDatasourceState, + }), + activeVisualization.removeDimension({ + layerId, + columnId: accessor, + prevState: props.visualizationState, + }) + ); + }} + /> + +
+
+ ); + })} +
+ {group.supportsMoreColumns ? ( +
- typeof a === 'string' ? a : a.columnId - )} - className={'lnsLayerPanel__dimensionContainer'} - value={{ - columnId: accessor, - groupId: group.groupId, - layerId, - id: accessor, - }} - isValueEqual={isSameConfiguration} - label={columnLabelMap[accessor]} - droppable={dragging && isDroppable} - dropTo={(dropTargetId: string) => { - layerDatasource.onDrop({ - isReorder: true, + droppable={ + Boolean(dragDropContext.dragging) && + // Verify that the dragged item is not coming from the same group + // since this would be a reorder + (!isDraggedOperation(dragDropContext.dragging) || + dragDropContext.dragging.groupId !== group.groupId) && + layerDatasource.canHandleDrop({ ...layerDatasourceDropProps, - droppedItem: { - columnId: accessor, - groupId: group.groupId, - layerId, - id: accessor, - }, - columnId: dropTargetId, + columnId: newId, filterOperations: group.filterOperations, - }); - }} + }) + } onDrop={(droppedItem) => { - const isReorder = - isDraggedOperation(droppedItem) && - droppedItem.groupId === group.groupId && - droppedItem.columnId !== accessor; - const dropResult = layerDatasource.onDrop({ - isReorder, ...layerDatasourceDropProps, droppedItem, - columnId: accessor, + columnId: newId, filterOperations: group.filterOperations, }); - if (typeof dropResult === 'object') { - // When a column is moved, we delete the reference to the old + if (dropResult) { props.updateVisualization( - activeVisualization.removeDimension({ + activeVisualization.setDimension({ layerId, - columnId: dropResult.deleted, + groupId: group.groupId, + columnId: newId, prevState: props.visualizationState, }) ); + + if (typeof dropResult === 'object') { + // When a column is moved, we delete the reference to the old + props.updateVisualization( + activeVisualization.removeDimension({ + layerId, + columnId: dropResult.deleted, + prevState: props.visualizationState, + }) + ); + } } }} > -
- + { if (activeId) { setActiveDimension(initialActiveDimensionState); } else { setActiveDimension({ - isNew: false, + isNew: true, activeGroup: group, - activeId: accessor, + activeId: newId, }); } }} - aria-label={triggerLinkA11yText(columnLabelMap[accessor])} - title={triggerLinkA11yText(columnLabelMap[accessor])} > - - - - - { - trackUiEvent('indexpattern_dimension_removed'); - props.updateAll( - datasourceId, - layerDatasource.removeColumn({ - layerId, - columnId: accessor, - prevState: layerDatasourceState, - }), - activeVisualization.removeDimension({ - layerId, - columnId: accessor, - prevState: props.visualizationState, - }) - ); - }} - /> - + +
- ); - })} - - {group.supportsMoreColumns ? ( -
- { - const dropResult = layerDatasource.onDrop({ - ...layerDatasourceDropProps, - droppedItem, - columnId: newId, - filterOperations: group.filterOperations, - }); - if (dropResult) { - props.updateVisualization( +
+ ) : null} + + + ); + })} + { + if (layerDatasource.updateStateOnCloseDimension) { + const newState = layerDatasource.updateStateOnCloseDimension({ + state: layerDatasourceState, + layerId, + columnId: activeId!, + }); + if (newState) { + props.updateDatasource(datasourceId, newState); + } + } + setActiveDimension(initialActiveDimensionState); + }} + panel={ + <> + {activeGroup && activeId && ( + { + if (shouldUpdateVisualization) { + props.updateAll( + datasourceId, + newState, activeVisualization.setDimension({ layerId, - groupId: group.groupId, - columnId: newId, + groupId: activeGroup.groupId, + columnId: activeId, prevState: props.visualizationState, }) ); - - if (typeof dropResult === 'object') { - // When a column is moved, we delete the reference to the old - props.updateVisualization( - activeVisualization.removeDimension({ - layerId, - columnId: dropResult.deleted, - prevState: props.visualizationState, - }) - ); - } + } else { + props.updateDatasource(datasourceId, newState); } - }} - > -
- { - if (activeId) { - setActiveDimension(initialActiveDimensionState); - } else { - setActiveDimension({ - isNew: true, - activeGroup: group, - activeId: newId, - }); - } - }} - > - - -
- -
- ) : null} + setActiveDimension({ + ...activeDimension, + isNew: false, + }); + }, + }} + /> + )} + {activeGroup && + activeId && + !activeDimension.isNew && + activeVisualization.renderDimensionEditor && + activeGroup?.enableDimensionEditor && ( +
+ +
+ )} - - ); - })} - { - if (layerDatasource.updateStateOnCloseDimension) { - const newState = layerDatasource.updateStateOnCloseDimension({ - state: layerDatasourceState, - layerId, - columnId: activeId!, - }); - if (newState) { - props.updateDatasource(datasourceId, newState); - } } - setActiveDimension(initialActiveDimensionState); - }} - panel={ - <> - {activeGroup && activeId && ( - { - if (shouldUpdateVisualization) { - props.updateAll( - datasourceId, - newState, - activeVisualization.setDimension({ - layerId, - groupId: activeGroup.groupId, - columnId: activeId, - prevState: props.visualizationState, - }) - ); - } else { - props.updateDatasource(datasourceId, newState); - } - setActiveDimension({ - ...activeDimension, - isNew: false, - }); - }, - }} - /> - )} - {activeGroup && - activeId && - !activeDimension.isNew && - activeVisualization.renderDimensionEditor && - activeGroup?.enableDimensionEditor && ( -
- -
- )} - - } - /> - - + /> - - - { - // If we don't blur the remove / clear button, it remains focused - // which is a strange UX in this case. e.target.blur doesn't work - // due to who knows what, but probably event re-writing. Additionally, - // activeElement does not have blur so, we need to do some casting + safeguards. - const el = (document.activeElement as unknown) as { blur: () => void }; + - if (el?.blur) { - el.blur(); + + + { + // If we don't blur the remove / clear button, it remains focused + // which is a strange UX in this case. e.target.blur doesn't work + // due to who knows what, but probably event re-writing. Additionally, + // activeElement does not have blur so, we need to do some casting + safeguards. + const el = (document.activeElement as unknown) as { blur: () => void }; + + if (el?.blur) { + el.blur(); + } - onRemoveLayer(); - }} - > - {isOnlyLayer - ? i18n.translate('xpack.lens.resetLayer', { - defaultMessage: 'Reset layer', - }) - : i18n.translate('xpack.lens.deleteLayer', { - defaultMessage: `Delete layer`, - })} - - - - + onRemoveLayer(); + }} + > + {isOnlyLayer + ? i18n.translate('xpack.lens.resetLayer', { + defaultMessage: 'Reset layer', + }) + : i18n.translate('xpack.lens.deleteLayer', { + defaultMessage: `Delete layer`, + })} + + + + + ); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index 7402a712793f..b0879ac8cb88 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -602,7 +602,7 @@ describe('editor_frame', () => { }); // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(6); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ state: updatedState, @@ -682,7 +682,7 @@ describe('editor_frame', () => { }); // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(6); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(7); expect(mockVisualization.getConfiguration).toHaveBeenLastCalledWith( expect.objectContaining({ frame: expect.objectContaining({ @@ -1196,7 +1196,7 @@ describe('editor_frame', () => { }); // validation requires to calls this getConfiguration API - expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(4); + expect(mockVisualization.getConfiguration).toHaveBeenCalledTimes(5); expect(mockVisualization.getConfiguration).toHaveBeenCalledWith( expect.objectContaining({ state: suggestionVisState, diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.scss index 3599254a285b..a8d8146afebb 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/frame_layout.scss @@ -52,7 +52,7 @@ .lnsConfigPanel { @include euiScrollBar; - padding: $euiSize 0 $euiSize $euiSize; + padding: $euiSize $euiSizeXS $euiSize $euiSize; overflow-x: hidden; overflow-y: scroll; } From 364a1c18f9a9d7e22128e6c702cbc828bb2237c7 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Wed, 16 Dec 2020 15:40:35 -0600 Subject: [PATCH 16/38] Set default for agent icons (#86023) * Make `getAgentIcon` return a default icon instead of `undefined` when no icon is matched. * Have the service map icon method check for the agent name to determine whether to use an agent or span icon. Both functions return the default icon when no match is found * Remove the IE11 conditionals for service map icons * Set a width on the icons used in the lists to prevent them from being stretched out * Use EUI theme for icon sizing Fixes #85150. --- .../public/components/app/ServiceMap/icons.ts | 19 ++----------------- .../shared/AgentIcon/get_agent_icon.ts | 3 ++- .../components/shared/AgentIcon/index.tsx | 7 ++++--- .../shared/span_icon/get_span_icon.ts | 4 +--- .../components/shared/span_icon/index.tsx | 6 ++++-- 5 files changed, 13 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts b/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts index e64c84f130c4..9717b42f2ddf 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts @@ -11,27 +11,12 @@ import { SPAN_TYPE, } from '../../../../common/elasticsearch_fieldnames'; import { getAgentIcon } from '../../shared/AgentIcon/get_agent_icon'; -import { defaultIcon, getSpanIcon } from '../../shared/span_icon/get_span_icon'; - -// IE 11 does not properly load some SVGs, which causes a runtime error and the -// map to not work at all. We would prefer to do some kind of feature detection -// rather than browser detection, but IE 11 does support SVG, just not well -// enough for our use in loading icons. -// -// This method of detecting IE is from a Stack Overflow answer: -// https://stackoverflow.com/a/21825207 -// -// @ts-expect-error `documentMode` is not recognized as a valid property of `document`. -const isIE11 = !!window.MSInputMethodContext && !!document.documentMode; +import { getSpanIcon } from '../../shared/span_icon/get_span_icon'; export function iconForNode(node: cytoscape.NodeSingular) { const agentName = node.data(AGENT_NAME); const subtype = node.data(SPAN_SUBTYPE); const type = node.data(SPAN_TYPE); - if (isIE11) { - return defaultIcon; - } - - return getAgentIcon(agentName) || getSpanIcon(type, subtype) || defaultIcon; + return agentName ? getAgentIcon(agentName) : getSpanIcon(type, subtype); } diff --git a/x-pack/plugins/apm/public/components/shared/AgentIcon/get_agent_icon.ts b/x-pack/plugins/apm/public/components/shared/AgentIcon/get_agent_icon.ts index 939b55f6ae6f..12f84a1f3509 100644 --- a/x-pack/plugins/apm/public/components/shared/AgentIcon/get_agent_icon.ts +++ b/x-pack/plugins/apm/public/components/shared/AgentIcon/get_agent_icon.ts @@ -9,6 +9,7 @@ import { RUM_AGENT_NAMES, } from '../../../../common/agent_name'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; +import defaultIcon from '../span_icon/icons/default.svg'; import dotNetIcon from './icons/dot-net.svg'; import goIcon from './icons/go.svg'; import javaIcon from './icons/java.svg'; @@ -60,5 +61,5 @@ export function getAgentIconKey(agentName: string) { export function getAgentIcon(agentName?: string) { const key = agentName && getAgentIconKey(agentName); - return key && agentIcons[key]; + return (key && agentIcons[key]) ?? defaultIcon; } diff --git a/x-pack/plugins/apm/public/components/shared/AgentIcon/index.tsx b/x-pack/plugins/apm/public/components/shared/AgentIcon/index.tsx index 5646fc05bd28..26f1a662d386 100644 --- a/x-pack/plugins/apm/public/components/shared/AgentIcon/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/AgentIcon/index.tsx @@ -5,17 +5,18 @@ */ import React from 'react'; import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent'; +import { useTheme } from '../../../hooks/use_theme'; import { getAgentIcon } from './get_agent_icon'; -import { px } from '../../../style/variables'; interface Props { agentName: AgentName; } export function AgentIcon(props: Props) { + const theme = useTheme(); const { agentName } = props; - + const size = theme.eui.euiIconSizes.large; const icon = getAgentIcon(agentName); - return {agentName}; + return {agentName}; } diff --git a/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts b/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts index d1062d1044ea..aebe0d6c1adf 100644 --- a/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts +++ b/x-pack/plugins/apm/public/components/shared/span_icon/get_span_icon.ts @@ -8,7 +8,7 @@ import { maybe } from '../../../../common/utils/maybe'; import awsIcon from './icons/aws.svg'; import cassandraIcon from './icons/cassandra.svg'; import databaseIcon from './icons/database.svg'; -import defaultIconImport from './icons/default.svg'; +import defaultIcon from './icons/default.svg'; import documentsIcon from './icons/documents.svg'; import elasticsearchIcon from './icons/elasticsearch.svg'; import globeIcon from './icons/globe.svg'; @@ -58,8 +58,6 @@ const typeIcons: { [key: string]: { [key: string]: string } } = { }, }; -export const defaultIcon = defaultIconImport; - export function getSpanIcon(type?: string, subtype?: string) { if (!type) { return defaultIcon; diff --git a/x-pack/plugins/apm/public/components/shared/span_icon/index.tsx b/x-pack/plugins/apm/public/components/shared/span_icon/index.tsx index 98b076db6551..5c14623ac77b 100644 --- a/x-pack/plugins/apm/public/components/shared/span_icon/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/span_icon/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { px } from '../../../style/variables'; +import { useTheme } from '../../../hooks/use_theme'; import { getSpanIcon } from './get_span_icon'; interface Props { @@ -13,7 +13,9 @@ interface Props { } export function SpanIcon({ type, subType }: Props) { + const theme = useTheme(); + const size = theme.eui.euiIconSizes.large; const icon = getSpanIcon(type, subType); - return {type; + return {type; } From 1fddf942743081b780a68056043adbda2f146c88 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Wed, 16 Dec 2020 16:58:06 -0500 Subject: [PATCH 17/38] Closes #83663 by adding a prepend label to the search bar in service overview (#86143) --- .../components/app/service_overview/index.tsx | 10 +++++++++- .../shared/KueryBar/Typeahead/index.js | 16 ++++++++++++---- .../public/components/shared/KueryBar/index.tsx | 3 ++- .../apm/public/components/shared/search_bar.tsx | 4 ++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index 6db5b1ae7bc7..976fb127604a 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -5,10 +5,12 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiPage, EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import React from 'react'; import { useTrackPageview } from '../../../../../observability/public'; import { isRumAgentName } from '../../../../common/agent_name'; import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context'; +import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context'; import { LatencyChart } from '../../shared/charts/latency_chart'; import { TransactionBreakdownChart } from '../../shared/charts/transaction_breakdown_chart'; @@ -38,10 +40,16 @@ export function ServiceOverview({ useTrackPageview({ app: 'apm', path: 'service_overview' }); useTrackPageview({ app: 'apm', path: 'service_overview', delay: 15000 }); + const { transactionType } = useApmServiceContext(); + const transactionTypeLabel = i18n.translate( + 'xpack.apm.serviceOverview.searchBar.transactionTypeLabel', + { defaultMessage: 'Type: {transactionType}', values: { transactionType } } + ); + return ( - + diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js index 741df4ca2eb8..58039bce6621 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js @@ -156,7 +156,13 @@ export class Typeahead extends Component { }; render() { - const { placeholder } = this.props; + const { + disabled, + isLoading, + placeholder, + prepend, + suggestions, + } = this.props; return ( - {this.props.isLoading && ( + {isLoading && ( ); diff --git a/x-pack/plugins/apm/public/components/shared/search_bar.tsx b/x-pack/plugins/apm/public/components/shared/search_bar.tsx index 686df42cf3b8..6382f4937ac0 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar.tsx @@ -15,11 +15,11 @@ const SearchBarFlexGroup = styled(EuiFlexGroup)` `${theme.eui.euiSizeM} ${theme.eui.euiSizeM} -${theme.eui.gutterTypes.gutterMedium} ${theme.eui.euiSizeM}`}; `; -export function SearchBar() { +export function SearchBar(props: { prepend?: React.ReactNode | string }) { return ( - + From 53da425c8e8b884da2076bbcf5c2180597c570bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Wed, 16 Dec 2020 23:08:17 +0100 Subject: [PATCH 18/38] [APM] Updated header icons (#84760) * creating service name header * fixing icons * removing unused api import * fixing some stuff * adding API tests * refactoring some stuff * fixing tests * refactoring some stuff * fixing i18n * reverting * renaming * applying min width * addressing PR comments and adding test * sorting service version * changing sort type to desc * addressing pr comments * changing to show total and not avg * addressing pr comments * addressing pr comments * addressing pr comments Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../elasticsearch_fieldnames.test.ts.snap | 109 ++++++++ .../apm/common/elasticsearch_fieldnames.ts | 7 + x-pack/plugins/apm/common/service_metadata.ts | 7 + .../components/app/service_details/index.tsx | 16 +- .../service_icons/cloud_details.tsx | 94 +++++++ .../service_icons/container_details.tsx | 81 ++++++ .../service_icons/icon_popover.tsx | 64 +++++ .../service_icons/index.test.tsx | 232 ++++++++++++++++++ .../service_details/service_icons/index.tsx | 161 ++++++++++++ .../service_icons/service_details.tsx | 88 +++++++ .../services/get_service_metadata_details.ts | 170 +++++++++++++ .../services/get_service_metadata_icons.ts | 85 +++++++ .../apm/server/routes/create_apm_api.ts | 4 + x-pack/plugins/apm/server/routes/services.ts | 32 +++ .../typings/es_schemas/raw/fields/cloud.ts | 29 +++ .../typings/es_schemas/raw/transaction_raw.ts | 2 + .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../basic/tests/feature_controls.ts | 14 ++ .../apm_api_integration/basic/tests/index.ts | 2 + .../basic/tests/services/service_details.ts | 134 ++++++++++ .../basic/tests/services/service_icons.ts | 88 +++++++ .../typings/elasticsearch/aggregations.d.ts | 8 + 23 files changed, 1423 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/apm/common/service_metadata.ts create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/cloud_details.tsx create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/container_details.tsx create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/icon_popover.tsx create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/index.test.tsx create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx create mode 100644 x-pack/plugins/apm/public/components/app/service_details/service_icons/service_details.tsx create mode 100644 x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts create mode 100644 x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts create mode 100644 x-pack/plugins/apm/typings/es_schemas/raw/fields/cloud.ts create mode 100644 x-pack/test/apm_api_integration/basic/tests/services/service_details.ts create mode 100644 x-pack/test/apm_api_integration/basic/tests/services/service_icons.ts diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index c15fb7110c47..982b9c76934e 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -1,5 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Error AGENT 1`] = ` +Object { + "name": "java", + "version": "agent version", +} +`; + exports[`Error AGENT_NAME 1`] = `"java"`; exports[`Error AGENT_VERSION 1`] = `"agent version"`; @@ -8,14 +15,26 @@ exports[`Error CLIENT_GEO 1`] = `undefined`; exports[`Error CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; +exports[`Error CLOUD 1`] = ` +Object { + "availability_zone": "europe-west1-c", + "provider": "gcp", + "region": "europe-west1", +} +`; + exports[`Error CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`; +exports[`Error CLOUD_MACHINE_TYPE 1`] = `undefined`; + exports[`Error CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Error CLOUD_REGION 1`] = `"europe-west1"`; exports[`Error CLS_FIELD 1`] = `undefined`; +exports[`Error CONTAINER 1`] = `undefined`; + exports[`Error CONTAINER_ID 1`] = `undefined`; exports[`Error DESTINATION_ADDRESS 1`] = `undefined`; @@ -42,12 +61,20 @@ exports[`Error FCP_FIELD 1`] = `undefined`; exports[`Error FID_FIELD 1`] = `undefined`; +exports[`Error HOST 1`] = ` +Object { + "hostname": "my hostname", +} +`; + exports[`Error HOST_NAME 1`] = `"my hostname"`; exports[`Error HTTP_REQUEST_METHOD 1`] = `undefined`; exports[`Error HTTP_RESPONSE_STATUS_CODE 1`] = `undefined`; +exports[`Error KUBERNETES 1`] = `undefined`; + exports[`Error LABEL_NAME 1`] = `undefined`; exports[`Error LCP_FIELD 1`] = `undefined`; @@ -94,6 +121,16 @@ exports[`Error POD_NAME 1`] = `undefined`; exports[`Error PROCESSOR_EVENT 1`] = `"error"`; +exports[`Error SERVICE 1`] = ` +Object { + "language": Object { + "name": "nodejs", + "version": "v1337", + }, + "name": "service name", +} +`; + exports[`Error SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Error SERVICE_FRAMEWORK_NAME 1`] = `undefined`; @@ -176,6 +213,13 @@ exports[`Error USER_AGENT_OS 1`] = `undefined`; exports[`Error USER_ID 1`] = `undefined`; +exports[`Span AGENT 1`] = ` +Object { + "name": "java", + "version": "agent version", +} +`; + exports[`Span AGENT_NAME 1`] = `"java"`; exports[`Span AGENT_VERSION 1`] = `"agent version"`; @@ -184,14 +228,26 @@ exports[`Span CLIENT_GEO 1`] = `undefined`; exports[`Span CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; +exports[`Span CLOUD 1`] = ` +Object { + "availability_zone": "europe-west1-c", + "provider": "gcp", + "region": "europe-west1", +} +`; + exports[`Span CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`; +exports[`Span CLOUD_MACHINE_TYPE 1`] = `undefined`; + exports[`Span CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Span CLOUD_REGION 1`] = `"europe-west1"`; exports[`Span CLS_FIELD 1`] = `undefined`; +exports[`Span CONTAINER 1`] = `undefined`; + exports[`Span CONTAINER_ID 1`] = `undefined`; exports[`Span DESTINATION_ADDRESS 1`] = `undefined`; @@ -218,12 +274,16 @@ exports[`Span FCP_FIELD 1`] = `undefined`; exports[`Span FID_FIELD 1`] = `undefined`; +exports[`Span HOST 1`] = `undefined`; + exports[`Span HOST_NAME 1`] = `undefined`; exports[`Span HTTP_REQUEST_METHOD 1`] = `undefined`; exports[`Span HTTP_RESPONSE_STATUS_CODE 1`] = `undefined`; +exports[`Span KUBERNETES 1`] = `undefined`; + exports[`Span LABEL_NAME 1`] = `undefined`; exports[`Span LCP_FIELD 1`] = `undefined`; @@ -270,6 +330,12 @@ exports[`Span POD_NAME 1`] = `undefined`; exports[`Span PROCESSOR_EVENT 1`] = `"span"`; +exports[`Span SERVICE 1`] = ` +Object { + "name": "service name", +} +`; + exports[`Span SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Span SERVICE_FRAMEWORK_NAME 1`] = `undefined`; @@ -352,6 +418,13 @@ exports[`Span USER_AGENT_OS 1`] = `undefined`; exports[`Span USER_ID 1`] = `undefined`; +exports[`Transaction AGENT 1`] = ` +Object { + "name": "java", + "version": "agent version", +} +`; + exports[`Transaction AGENT_NAME 1`] = `"java"`; exports[`Transaction AGENT_VERSION 1`] = `"agent version"`; @@ -360,14 +433,26 @@ exports[`Transaction CLIENT_GEO 1`] = `undefined`; exports[`Transaction CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; +exports[`Transaction CLOUD 1`] = ` +Object { + "availability_zone": "europe-west1-c", + "provider": "gcp", + "region": "europe-west1", +} +`; + exports[`Transaction CLOUD_AVAILABILITY_ZONE 1`] = `"europe-west1-c"`; +exports[`Transaction CLOUD_MACHINE_TYPE 1`] = `undefined`; + exports[`Transaction CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Transaction CLOUD_REGION 1`] = `"europe-west1"`; exports[`Transaction CLS_FIELD 1`] = `undefined`; +exports[`Transaction CONTAINER 1`] = `"container1234567890abcdef"`; + exports[`Transaction CONTAINER_ID 1`] = `"container1234567890abcdef"`; exports[`Transaction DESTINATION_ADDRESS 1`] = `undefined`; @@ -394,12 +479,26 @@ exports[`Transaction FCP_FIELD 1`] = `undefined`; exports[`Transaction FID_FIELD 1`] = `undefined`; +exports[`Transaction HOST 1`] = ` +Object { + "hostname": "my hostname", +} +`; + exports[`Transaction HOST_NAME 1`] = `"my hostname"`; exports[`Transaction HTTP_REQUEST_METHOD 1`] = `"GET"`; exports[`Transaction HTTP_RESPONSE_STATUS_CODE 1`] = `200`; +exports[`Transaction KUBERNETES 1`] = ` +Object { + "pod": Object { + "uid": "pod1234567890abcdef", + }, +} +`; + exports[`Transaction LABEL_NAME 1`] = `undefined`; exports[`Transaction LCP_FIELD 1`] = `undefined`; @@ -446,6 +545,16 @@ exports[`Transaction POD_NAME 1`] = `undefined`; exports[`Transaction PROCESSOR_EVENT 1`] = `"transaction"`; +exports[`Transaction SERVICE 1`] = ` +Object { + "language": Object { + "name": "nodejs", + "version": "v1337", + }, + "name": "service name", +} +`; + exports[`Transaction SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Transaction SERVICE_FRAMEWORK_NAME 1`] = `undefined`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index 18b8dc57c88d..a25566bced00 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -4,10 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +export const CLOUD = 'cloud'; export const CLOUD_AVAILABILITY_ZONE = 'cloud.availability_zone'; export const CLOUD_PROVIDER = 'cloud.provider'; export const CLOUD_REGION = 'cloud.region'; +export const CLOUD_MACHINE_TYPE = 'cloud.machine.type'; +export const SERVICE = 'service'; export const SERVICE_NAME = 'service.name'; export const SERVICE_ENVIRONMENT = 'service.environment'; export const SERVICE_FRAMEWORK_NAME = 'service.framework.name'; @@ -19,6 +22,7 @@ export const SERVICE_RUNTIME_VERSION = 'service.runtime.version'; export const SERVICE_NODE_NAME = 'service.node.name'; export const SERVICE_VERSION = 'service.version'; +export const AGENT = 'agent'; export const AGENT_NAME = 'agent.name'; export const AGENT_VERSION = 'agent.version'; @@ -102,8 +106,11 @@ export const METRIC_JAVA_GC_TIME = 'jvm.gc.time'; export const LABEL_NAME = 'labels.name'; +export const HOST = 'host'; export const HOST_NAME = 'host.hostname'; +export const CONTAINER = 'container.id'; export const CONTAINER_ID = 'container.id'; +export const KUBERNETES = 'kubernetes'; export const POD_NAME = 'kubernetes.pod.name'; export const CLIENT_GEO_COUNTRY_ISO_CODE = 'client.geo.country_iso_code'; diff --git a/x-pack/plugins/apm/common/service_metadata.ts b/x-pack/plugins/apm/common/service_metadata.ts new file mode 100644 index 000000000000..050f3055ac16 --- /dev/null +++ b/x-pack/plugins/apm/common/service_metadata.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export type ContainerType = 'Kubernetes' | 'Docker' | undefined; diff --git a/x-pack/plugins/apm/public/components/app/service_details/index.tsx b/x-pack/plugins/apm/public/components/app/service_details/index.tsx index 70acc2038e1a..bccce6e82366 100644 --- a/x-pack/plugins/apm/public/components/app/service_details/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_details/index.tsx @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { ApmHeader } from '../../shared/ApmHeader'; +import { ServiceIcons } from './service_icons'; import { ServiceDetailTabs } from './service_detail_tabs'; interface Props extends RouteComponentProps<{ serviceName: string }> { @@ -20,9 +21,16 @@ export function ServiceDetails({ match, tab }: Props) { return (
- -

{serviceName}

-
+ + + +

{serviceName}

+
+
+ + + +
diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/cloud_details.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/cloud_details.tsx new file mode 100644 index 000000000000..637a9d57344b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/cloud_details.tsx @@ -0,0 +1,94 @@ +/* + * 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 { EuiBadge, EuiDescriptionList } from '@elastic/eui'; +import { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { APIReturnType } from '../../../../services/rest/createCallApmApi'; + +type ServiceDetailsReturnType = APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + +interface Props { + cloud: ServiceDetailsReturnType['cloud']; +} + +export function CloudDetails({ cloud }: Props) { + if (!cloud) { + return null; + } + + const listItems: EuiDescriptionListProps['listItems'] = []; + if (cloud.provider) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.cloud.providerLabel', + { + defaultMessage: 'Cloud provider', + } + ), + description: cloud.provider, + }); + } + + if (!!cloud.availabilityZones?.length) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.cloud.availabilityZoneLabel', + { + defaultMessage: + '{zones, plural, =0 {Availability zone} one {Availability zone} other {Availability zones}} ', + values: { zones: cloud.availabilityZones.length }, + } + ), + description: ( +
    + {cloud.availabilityZones.map((zone, index) => ( +
  • + {zone} +
  • + ))} +
+ ), + }); + } + + if (cloud.machineTypes) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.cloud.machineTypesLabel', + { + defaultMessage: + '{machineTypes, plural, =0{Machine type} one {Machine type} other {Machine types}} ', + values: { machineTypes: cloud.machineTypes.length }, + } + ), + description: ( +
    + {cloud.machineTypes.map((type, index) => ( +
  • + {type} +
  • + ))} +
+ ), + }); + } + + if (cloud.projectName) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.cloud.projectIdLabel', + { + defaultMessage: 'Project ID', + } + ), + description: cloud.projectName, + }); + } + + return ; +} diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/container_details.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/container_details.tsx new file mode 100644 index 000000000000..4c0f476da4c2 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/container_details.tsx @@ -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 { EuiDescriptionList } from '@elastic/eui'; +import { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { asInteger } from '../../../../../common/utils/formatters'; +import { APIReturnType } from '../../../../services/rest/createCallApmApi'; + +type ServiceDetailsReturnType = APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + +interface Props { + container: ServiceDetailsReturnType['container']; +} + +export function ContainerDetails({ container }: Props) { + if (!container) { + return null; + } + + const listItems: EuiDescriptionListProps['listItems'] = []; + if (container.os) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.osLabel', + { + defaultMessage: 'OS', + } + ), + description: container.os, + }); + } + + if (container.isContainerized !== undefined) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.containerizedLabel', + { defaultMessage: 'Containerized' } + ), + description: container.isContainerized + ? i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.yesLabel', + { + defaultMessage: 'Yes', + } + ) + : i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.noLabel', + { + defaultMessage: 'No', + } + ), + }); + } + + if (container.totalNumberInstances) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.totalNumberInstancesLabel', + { defaultMessage: 'Total number of instances' } + ), + description: asInteger(container.totalNumberInstances), + }); + } + + if (container.type) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.container.orchestrationLabel', + { defaultMessage: 'Orchestration' } + ), + description: container.type, + }); + } + + return ; +} diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/icon_popover.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/icon_popover.tsx new file mode 100644 index 000000000000..fa890260a306 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/icon_popover.tsx @@ -0,0 +1,64 @@ +/* + * 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 { + EuiButtonEmpty, + EuiIcon, + EuiLoadingContent, + EuiPopover, + EuiPopoverTitle, +} from '@elastic/eui'; +import React from 'react'; +import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; +import { px } from '../../../../style/variables'; + +interface IconPopoverProps { + title: string; + children: React.ReactChild; + onOpen: () => void; + onClose: () => void; + detailsFetchStatus: FETCH_STATUS; + isOpen: boolean; + icon?: string; +} +export function IconPopover({ + icon, + title, + children, + onOpen, + onClose, + detailsFetchStatus, + isOpen, +}: IconPopoverProps) { + if (!icon) { + return null; + } + const isLoading = + detailsFetchStatus === FETCH_STATUS.LOADING || + detailsFetchStatus === FETCH_STATUS.PENDING; + + return ( + + + + } + isOpen={isOpen} + closePopover={onClose} + > + {title} +
+ {isLoading ? ( + + ) : ( + children + )} +
+
+ ); +} diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.test.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.test.tsx new file mode 100644 index 000000000000..5981e7408ef2 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.test.tsx @@ -0,0 +1,232 @@ +/* + * 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 { fireEvent, render } from '@testing-library/react'; +import { CoreStart } from 'kibana/public'; +import { merge } from 'lodash'; +// import { renderWithTheme } from '../../../../utils/testHelpers'; +import React, { ReactNode } from 'react'; +import { createKibanaReactContext } from 'src/plugins/kibana_react/public'; +import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider'; +import { ApmPluginContextValue } from '../../../../context/apm_plugin/apm_plugin_context'; +import { + mockApmPluginContextValue, + MockApmPluginContextWrapper, +} from '../../../../context/apm_plugin/mock_apm_plugin_context'; +import * as fetcherHook from '../../../../hooks/use_fetcher'; +import { ServiceIcons } from './'; + +const KibanaReactContext = createKibanaReactContext({ + usageCollection: { reportUiCounter: () => {} }, +} as Partial); + +const addWarning = jest.fn(); +const httpGet = jest.fn(); + +function Wrapper({ children }: { children?: ReactNode }) { + const mockPluginContext = (merge({}, mockApmPluginContextValue, { + core: { http: { get: httpGet }, notifications: { toasts: { addWarning } } }, + }) as unknown) as ApmPluginContextValue; + + return ( + + + + {children} + + + + ); +} + +describe('ServiceIcons', () => { + describe('icons', () => { + it('Shows loading spinner while fetching data', () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: undefined, + status: fetcherHook.FETCH_STATUS.LOADING, + refetch: jest.fn(), + }); + const { getByTestId, queryAllByTestId } = render( + + + + ); + expect(getByTestId('loading')).toBeInTheDocument(); + expect(queryAllByTestId('service')).toHaveLength(0); + expect(queryAllByTestId('container')).toHaveLength(0); + expect(queryAllByTestId('cloud')).toHaveLength(0); + }); + it("doesn't show any icons", () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: {}, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const { queryAllByTestId } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(queryAllByTestId('service')).toHaveLength(0); + expect(queryAllByTestId('container')).toHaveLength(0); + expect(queryAllByTestId('cloud')).toHaveLength(0); + }); + it('shows service icon', () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: { + agentName: 'java', + }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const { queryAllByTestId, getByTestId } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(getByTestId('service')).toBeInTheDocument(); + expect(queryAllByTestId('container')).toHaveLength(0); + expect(queryAllByTestId('cloud')).toHaveLength(0); + }); + it('shows service and container icons', () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: { + agentName: 'java', + containerType: 'Kubernetes', + }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const { queryAllByTestId, getByTestId } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(queryAllByTestId('cloud')).toHaveLength(0); + expect(getByTestId('service')).toBeInTheDocument(); + expect(getByTestId('container')).toBeInTheDocument(); + }); + it('shows service, container and cloud icons', () => { + jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({ + data: { + agentName: 'java', + containerType: 'Kubernetes', + cloudProvider: 'gcp', + }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const { queryAllByTestId, getByTestId } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(getByTestId('service')).toBeInTheDocument(); + expect(getByTestId('container')).toBeInTheDocument(); + expect(getByTestId('cloud')).toBeInTheDocument(); + }); + }); + + describe('details', () => { + const callApmApi = (apisMockData: Record) => ({ + endpoint, + }: { + endpoint: string; + }) => { + return apisMockData[endpoint]; + }; + it('Shows loading spinner while fetching data', () => { + const apisMockData = { + 'GET /api/apm/services/{serviceName}/metadata/icons': { + data: { + agentName: 'java', + containerType: 'Kubernetes', + cloudProvider: 'gcp', + }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }, + 'GET /api/apm/services/{serviceName}/metadata/details': { + data: undefined, + status: fetcherHook.FETCH_STATUS.LOADING, + refetch: jest.fn(), + }, + }; + jest + .spyOn(fetcherHook, 'useFetcher') + .mockImplementation((func: Function, deps: string[]) => { + return func(callApmApi(apisMockData)) || {}; + }); + + const { queryAllByTestId, getByTestId } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(getByTestId('service')).toBeInTheDocument(); + expect(getByTestId('container')).toBeInTheDocument(); + expect(getByTestId('cloud')).toBeInTheDocument(); + fireEvent.click(getByTestId('popover_Service')); + expect(getByTestId('loading-content')).toBeInTheDocument(); + }); + + it('shows service content', () => { + const apisMockData = { + 'GET /api/apm/services/{serviceName}/metadata/icons': { + data: { + agentName: 'java', + containerType: 'Kubernetes', + cloudProvider: 'gcp', + }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }, + 'GET /api/apm/services/{serviceName}/metadata/details': { + data: { service: { versions: ['v1.0.0'] } }, + status: fetcherHook.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }, + }; + jest + .spyOn(fetcherHook, 'useFetcher') + .mockImplementation((func: Function, deps: string[]) => { + return func(callApmApi(apisMockData)) || {}; + }); + + const { queryAllByTestId, getByTestId, getByText } = render( + + + + ); + expect(queryAllByTestId('loading')).toHaveLength(0); + expect(getByTestId('service')).toBeInTheDocument(); + expect(getByTestId('container')).toBeInTheDocument(); + expect(getByTestId('cloud')).toBeInTheDocument(); + + fireEvent.click(getByTestId('popover_Service')); + expect(queryAllByTestId('loading-content')).toHaveLength(0); + expect(getByText('Service')).toBeInTheDocument(); + expect(getByText('v1.0.0')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx new file mode 100644 index 000000000000..327198e46131 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/index.tsx @@ -0,0 +1,161 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { ReactChild, useState } from 'react'; +import { ContainerType } from '../../../../../common/service_metadata'; +import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { getAgentIcon } from '../../../shared/AgentIcon/get_agent_icon'; +import { CloudDetails } from './cloud_details'; +import { ContainerDetails } from './container_details'; +import { IconPopover } from './icon_popover'; +import { ServiceDetails } from './service_details'; + +interface Props { + serviceName: string; +} + +const cloudIcons: Record = { + gcp: 'logoGCP', + aws: 'logoAWS', + azure: 'logoAzure', +}; + +function getCloudIcon(provider?: string) { + if (provider) { + return cloudIcons[provider]; + } +} + +function getContainerIcon(container?: ContainerType) { + if (!container) { + return; + } + switch (container) { + case 'Kubernetes': + return 'logoKubernetes'; + default: + return 'logoDocker'; + } +} + +type Icons = 'service' | 'container' | 'cloud'; +interface PopoverItem { + key: Icons; + icon?: string; + isVisible: boolean; + title: string; + component: ReactChild; +} + +export function ServiceIcons({ serviceName }: Props) { + const { + urlParams: { start, end }, + uiFilters, + } = useUrlParams(); + const [ + selectedIconPopover, + setSelectedIconPopover, + ] = useState(); + + const { data: icons, status: iconsFetchStatus } = useFetcher( + (callApmApi) => { + if (serviceName && start && end) { + return callApmApi({ + endpoint: 'GET /api/apm/services/{serviceName}/metadata/icons', + params: { + path: { serviceName }, + query: { start, end, uiFilters: JSON.stringify(uiFilters) }, + }, + }); + } + }, + [serviceName, start, end, uiFilters] + ); + + const { data: details, status: detailsFetchStatus } = useFetcher( + (callApmApi) => { + if (selectedIconPopover && serviceName && start && end) { + return callApmApi({ + endpoint: 'GET /api/apm/services/{serviceName}/metadata/details', + params: { + path: { serviceName }, + query: { start, end, uiFilters: JSON.stringify(uiFilters) }, + }, + }); + } + }, + [selectedIconPopover, serviceName, start, end, uiFilters] + ); + + const isLoading = + !icons && + (iconsFetchStatus === FETCH_STATUS.LOADING || + iconsFetchStatus === FETCH_STATUS.PENDING); + + if (isLoading) { + return ; + } + + const popoverItems: PopoverItem[] = [ + { + key: 'service', + icon: getAgentIcon(icons?.agentName) || 'node', + isVisible: !!icons?.agentName, + title: i18n.translate('xpack.apm.serviceIcons.service', { + defaultMessage: 'Service', + }), + component: , + }, + { + key: 'container', + icon: getContainerIcon(icons?.containerType), + isVisible: !!icons?.containerType, + title: i18n.translate('xpack.apm.serviceIcons.container', { + defaultMessage: 'Container', + }), + component: , + }, + { + key: 'cloud', + icon: getCloudIcon(icons?.cloudProvider), + isVisible: !!icons?.cloudProvider, + title: i18n.translate('xpack.apm.serviceIcons.cloud', { + defaultMessage: 'Cloud', + }), + component: , + }, + ]; + + return ( + + {popoverItems.map((item) => { + if (item.isVisible) { + return ( + + { + setSelectedIconPopover(item.key); + }} + onClose={() => { + setSelectedIconPopover(null); + }} + > + {item.component} + + + ); + } + })} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/service_details/service_icons/service_details.tsx b/x-pack/plugins/apm/public/components/app/service_details/service_icons/service_details.tsx new file mode 100644 index 000000000000..d9525f825692 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_details/service_icons/service_details.tsx @@ -0,0 +1,88 @@ +/* + * 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 { EuiDescriptionList } from '@elastic/eui'; +import { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { APIReturnType } from '../../../../services/rest/createCallApmApi'; + +type ServiceDetailsReturnType = APIReturnType<'GET /api/apm/services/{serviceName}/metadata/details'>; + +interface Props { + service: ServiceDetailsReturnType['service']; +} + +export function ServiceDetails({ service }: Props) { + if (!service) { + return null; + } + + const listItems: EuiDescriptionListProps['listItems'] = []; + if (!!service.versions?.length) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.service.versionLabel', + { + defaultMessage: 'Service version', + } + ), + description: ( +
    + {service.versions.map((version, index) => ( +
  • {version}
  • + ))} +
+ ), + }); + } + + if (service.runtime) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.service.runtimeLabel', + { + defaultMessage: 'Runtime name & version', + } + ), + description: ( + <> + {service.runtime.name} {service.runtime.version} + + ), + }); + } + + if (service.framework) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.service.frameworkLabel', + { + defaultMessage: 'Framework name', + } + ), + description: service.framework, + }); + } + + if (service.agent) { + listItems.push({ + title: i18n.translate( + 'xpack.apm.serviceIcons.serviceDetails.service.agentLabel', + { + defaultMessage: 'Agent name & version', + } + ), + description: ( + <> + {service.agent.name} {service.agent.version} + + ), + }); + } + + return ; +} diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts new file mode 100644 index 000000000000..6b17b0248fc1 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_details.ts @@ -0,0 +1,170 @@ +/* + * 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 { SortOptions } from '../../../../../typings/elasticsearch'; +import { + AGENT, + CLOUD, + CLOUD_AVAILABILITY_ZONE, + CLOUD_MACHINE_TYPE, + CONTAINER, + HOST, + KUBERNETES, + PROCESSOR_EVENT, + SERVICE, + SERVICE_NAME, + SERVICE_NODE_NAME, + SERVICE_VERSION, +} from '../../../common/elasticsearch_fieldnames'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { ContainerType } from '../../../common/service_metadata'; +import { rangeFilter } from '../../../common/utils/range_filter'; +import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; + +type ServiceMetadataDetailsRaw = Pick< + TransactionRaw, + 'service' | 'agent' | 'host' | 'container' | 'kubernetes' | 'cloud' +>; + +interface ServiceMetadataDetails { + service?: { + versions?: string[]; + runtime?: { + name: string; + version: string; + }; + framework?: string; + agent: { + name: string; + version: string; + }; + }; + container?: { + os?: string; + isContainerized?: boolean; + totalNumberInstances?: number; + type?: ContainerType; + }; + cloud?: { + provider?: string; + availabilityZones?: string[]; + machineTypes?: string[]; + projectName?: string; + }; +} + +export async function getServiceMetadataDetails({ + serviceName, + setup, +}: { + serviceName: string; + setup: Setup & SetupTimeRange; +}): Promise { + const { start, end, apmEventClient } = setup; + + const filter = [ + { term: { [SERVICE_NAME]: serviceName } }, + { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, + { range: rangeFilter(start, end) }, + ...setup.esFilter, + ]; + + const should = [ + { exists: { field: CONTAINER } }, + { exists: { field: KUBERNETES } }, + { exists: { field: CLOUD } }, + { exists: { field: HOST } }, + { exists: { field: AGENT } }, + ]; + + const params = { + apm: { + events: [ProcessorEvent.transaction], + }, + body: { + size: 1, + _source: [SERVICE, AGENT, HOST, CONTAINER, KUBERNETES, CLOUD], + query: { bool: { filter, should } }, + aggs: { + serviceVersions: { + terms: { + field: SERVICE_VERSION, + size: 10, + order: { _key: 'desc' } as SortOptions, + }, + }, + availabilityZones: { + terms: { + field: CLOUD_AVAILABILITY_ZONE, + size: 10, + }, + }, + machineTypes: { + terms: { + field: CLOUD_MACHINE_TYPE, + size: 10, + }, + }, + totalNumberInstances: { cardinality: { field: SERVICE_NODE_NAME } }, + }, + }, + }; + + const response = await apmEventClient.search(params); + + if (response.hits.total.value === 0) { + return { + service: undefined, + container: undefined, + cloud: undefined, + }; + } + + const { service, agent, host, kubernetes, container, cloud } = response.hits + .hits[0]._source as ServiceMetadataDetailsRaw; + + const serviceMetadataDetails = { + versions: response.aggregations?.serviceVersions.buckets.map( + (bucket) => bucket.key as string + ), + runtime: service.runtime, + framework: service.framework?.name, + agent, + }; + + const totalNumberInstances = + response.aggregations?.totalNumberInstances.value; + + const containerDetails = + host || container || totalNumberInstances || kubernetes + ? { + os: host?.os?.platform, + type: (!!kubernetes ? 'Kubernetes' : 'Docker') as ContainerType, + isContainerized: !!container?.id, + totalNumberInstances, + } + : undefined; + + const cloudDetails = cloud + ? { + provider: cloud.provider, + projectName: cloud.project?.name, + availabilityZones: response.aggregations?.availabilityZones.buckets.map( + (bucket) => bucket.key as string + ), + machineTypes: response.aggregations?.machineTypes.buckets.map( + (bucket) => bucket.key as string + ), + } + : undefined; + + return { + service: serviceMetadataDetails, + container: containerDetails, + cloud: cloudDetails, + }; +} diff --git a/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts new file mode 100644 index 000000000000..d9d62fef084a --- /dev/null +++ b/x-pack/plugins/apm/server/lib/services/get_service_metadata_icons.ts @@ -0,0 +1,85 @@ +/* + * 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 { + AGENT_NAME, + CLOUD_PROVIDER, + CONTAINER_ID, + KUBERNETES, + PROCESSOR_EVENT, + SERVICE_NAME, +} from '../../../common/elasticsearch_fieldnames'; +import { ProcessorEvent } from '../../../common/processor_event'; +import { ContainerType } from '../../../common/service_metadata'; +import { rangeFilter } from '../../../common/utils/range_filter'; +import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw'; +import { Setup, SetupTimeRange } from '../helpers/setup_request'; + +type ServiceMetadataIconsRaw = Pick< + TransactionRaw, + 'kubernetes' | 'cloud' | 'container' | 'agent' +>; + +interface ServiceMetadataIcons { + agentName?: string; + containerType?: ContainerType; + cloudProvider?: string; +} + +export async function getServiceMetadataIcons({ + serviceName, + setup, +}: { + serviceName: string; + setup: Setup & SetupTimeRange; +}): Promise { + const { start, end, apmEventClient } = setup; + + const filter = [ + { term: { [SERVICE_NAME]: serviceName } }, + { term: { [PROCESSOR_EVENT]: ProcessorEvent.transaction } }, + { range: rangeFilter(start, end) }, + ...setup.esFilter, + ]; + + const params = { + apm: { + events: [ProcessorEvent.transaction], + }, + terminateAfter: 1, + body: { + size: 1, + _source: [KUBERNETES, CLOUD_PROVIDER, CONTAINER_ID, AGENT_NAME], + query: { bool: { filter } }, + }, + }; + + const response = await apmEventClient.search(params); + + if (response.hits.total.value === 0) { + return { + agentName: undefined, + containerType: undefined, + cloudProvider: undefined, + }; + } + + const { kubernetes, cloud, container, agent } = response.hits.hits[0] + ._source as ServiceMetadataIconsRaw; + + let containerType: ContainerType; + if (!!kubernetes) { + containerType = 'Kubernetes'; + } else if (!!container) { + containerType = 'Docker'; + } + + return { + agentName: agent?.name, + containerType, + cloudProvider: cloud?.provider, + }; +} diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 5e26371b043e..aeaa6f90a742 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -24,6 +24,8 @@ import { serviceErrorGroupsRoute, serviceThroughputRoute, serviceDependenciesRoute, + serviceMetadataDetailsRoute, + serviceMetadataIconsRoute, serviceInstancesRoute, } from './services'; import { @@ -130,6 +132,8 @@ const createApmApi = () => { .add(serviceErrorGroupsRoute) .add(serviceThroughputRoute) .add(serviceDependenciesRoute) + .add(serviceMetadataDetailsRoute) + .add(serviceMetadataIconsRoute) .add(serviceInstancesRoute) // Agent configuration diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index bba6afc33224..17430e64d6c9 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -22,6 +22,8 @@ import { getServiceDependencies } from '../lib/services/get_service_dependencies import { toNumberRt } from '../../common/runtime_types/to_number_rt'; import { getThroughput } from '../lib/services/get_throughput'; import { getServiceInstances } from '../lib/services/get_service_instances'; +import { getServiceMetadataDetails } from '../lib/services/get_service_metadata_details'; +import { getServiceMetadataIcons } from '../lib/services/get_service_metadata_icons'; export const servicesRoute = createRoute({ endpoint: 'GET /api/apm/services', @@ -46,6 +48,36 @@ export const servicesRoute = createRoute({ }, }); +export const serviceMetadataDetailsRoute = createRoute({ + endpoint: 'GET /api/apm/services/{serviceName}/metadata/details', + params: t.type({ + path: t.type({ serviceName: t.string }), + query: t.intersection([uiFiltersRt, rangeRt]), + }), + options: { tags: ['access:apm'] }, + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + + return getServiceMetadataDetails({ serviceName, setup }); + }, +}); + +export const serviceMetadataIconsRoute = createRoute({ + endpoint: 'GET /api/apm/services/{serviceName}/metadata/icons', + params: t.type({ + path: t.type({ serviceName: t.string }), + query: t.intersection([uiFiltersRt, rangeRt]), + }), + options: { tags: ['access:apm'] }, + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + const { serviceName } = context.params.path; + + return getServiceMetadataIcons({ serviceName, setup }); + }, +}); + export const serviceAgentNameRoute = createRoute({ endpoint: 'GET /api/apm/services/{serviceName}/agent_name', params: t.type({ diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/fields/cloud.ts b/x-pack/plugins/apm/typings/es_schemas/raw/fields/cloud.ts new file mode 100644 index 000000000000..97e564a7beaa --- /dev/null +++ b/x-pack/plugins/apm/typings/es_schemas/raw/fields/cloud.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. + */ + +export interface Cloud { + availability_zone?: string; + instance?: { + name: string; + id: string; + }; + machine?: { + type: string; + }; + project?: { + id: string; + name: string; + }; + provider?: string; + region?: string; + account?: { + id: string; + name: string; + }; + image?: { + id: string; + }; +} diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts index 68db3bca9464..c87bab4957b3 100644 --- a/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts +++ b/x-pack/plugins/apm/typings/es_schemas/raw/transaction_raw.ts @@ -5,6 +5,7 @@ */ import { APMBaseDoc } from './apm_base_doc'; +import { Cloud } from './fields/cloud'; import { Container } from './fields/container'; import { Host } from './fields/host'; import { Http } from './fields/http'; @@ -64,4 +65,5 @@ export interface TransactionRaw extends APMBaseDoc { url?: Url; user?: User; user_agent?: UserAgent; + cloud?: Cloud; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 94eb0ef35a43..377e38b71d45 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5014,7 +5014,6 @@ "xpack.apm.servicesTable.7xUpgradeServerMessage": "バージョン7.xより前からのアップグレードですか?また、\n APMサーバーインスタンスを7.0以降にアップグレードしていることも確認してください。", "xpack.apm.servicesTable.avgResponseTimeColumnLabel": "平均応答時間", "xpack.apm.servicesTable.environmentColumnLabel": "環境", - "xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, one {1 個の環境} other {# 個の環境}}", "xpack.apm.servicesTable.healthColumnLabel": "ヘルス", "xpack.apm.servicesTable.nameColumnLabel": "名前", "xpack.apm.servicesTable.noServicesLabel": "APM サービスがインストールされていないようです。追加しましょう!", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9e5d998e124b..7c9fa7f0fd1f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5018,7 +5018,6 @@ "xpack.apm.servicesTable.7xUpgradeServerMessage": "从 7.x 之前的版本升级?另外,确保您已将\n APM Server 实例升级到至少 7.0。", "xpack.apm.servicesTable.avgResponseTimeColumnLabel": "平均响应时间", "xpack.apm.servicesTable.environmentColumnLabel": "环境", - "xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, one {1 个环境} other {# 个环境}}", "xpack.apm.servicesTable.healthColumnLabel": "运行状况", "xpack.apm.servicesTable.nameColumnLabel": "名称", "xpack.apm.servicesTable.noServicesLabel": "似乎您没有安装任何 APM 服务。让我们添加一些!", diff --git a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts index 4e1fc3957a6e..94d8f65bb6dc 100644 --- a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts +++ b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts @@ -170,6 +170,20 @@ export default function featureControlsTests({ getService }: FtrProviderContext) expectForbidden: expect403, expectResponse: expect200, }, + { + req: { + url: `/api/apm/services/foo/metadata/details?start=${start}&end=${end}&uiFilters=%7B%7D`, + }, + expectForbidden: expect403, + expectResponse: expect200, + }, + { + req: { + url: `/api/apm/services/foo/metadata/icons?start=${start}&end=${end}&uiFilters=%7B%7D`, + }, + expectForbidden: expect403, + expectResponse: expect200, + }, ]; const elasticsearchPrivileges = { diff --git a/x-pack/test/apm_api_integration/basic/tests/index.ts b/x-pack/test/apm_api_integration/basic/tests/index.ts index f50868ee76c1..645d4078f933 100644 --- a/x-pack/test/apm_api_integration/basic/tests/index.ts +++ b/x-pack/test/apm_api_integration/basic/tests/index.ts @@ -25,6 +25,8 @@ export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderCont loadTestFile(require.resolve('./services/throughput')); loadTestFile(require.resolve('./services/top_services')); loadTestFile(require.resolve('./services/transaction_types')); + loadTestFile(require.resolve('./services/service_details')); + loadTestFile(require.resolve('./services/service_icons')); }); describe('Service overview', function () { diff --git a/x-pack/test/apm_api_integration/basic/tests/services/service_details.ts b/x-pack/test/apm_api_integration/basic/tests/services/service_details.ts new file mode 100644 index 000000000000..7aff62c07094 --- /dev/null +++ b/x-pack/test/apm_api_integration/basic/tests/services/service_details.ts @@ -0,0 +1,134 @@ +/* + * 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 expect from '@kbn/expect'; +import url from 'url'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import archives from '../../../common/archives_metadata'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + const archiveName = 'apm_8.0.0'; + const { start, end } = archives[archiveName]; + + describe('Service details', () => { + describe('when data is not loaded ', () => { + it('handles the empty state', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/metadata/details`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + expect(response.body).to.eql({}); + }); + }); + + describe('when data is loaded', () => { + before(() => esArchiver.load(archiveName)); + after(() => esArchiver.unload(archiveName)); + + it('returns java service details', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/metadata/details`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + + expectSnapshot(response.body).toMatchInline(` + Object { + "container": Object { + "isContainerized": true, + "os": "Linux", + "totalNumberInstances": 1, + "type": "Kubernetes", + }, + "service": Object { + "agent": Object { + "ephemeral_id": "d27b2271-06b4-48c8-a02a-cfd963c0b4d0", + "name": "java", + "version": "1.19.1-SNAPSHOT.null", + }, + "framework": "Servlet API", + "runtime": Object { + "name": "Java", + "version": "11.0.9.1", + }, + "versions": Array [ + "2020-12-08 03:35:36", + ], + }, + } + `); + }); + + it('returns python service details', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-python/metadata/details`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + + expectSnapshot(response.body).toMatchInline(` + Object { + "cloud": Object { + "availabilityZones": Array [ + "europe-west1-c", + ], + "machineTypes": Array [ + "n1-standard-4", + ], + "projectName": "elastic-observability", + "provider": "gcp", + }, + "container": Object { + "isContainerized": true, + "os": "linux", + "totalNumberInstances": 1, + "type": "Kubernetes", + }, + "service": Object { + "agent": Object { + "name": "python", + "version": "5.10.0", + }, + "framework": "django", + "runtime": Object { + "name": "CPython", + "version": "3.8.6", + }, + "versions": Array [ + "2020-12-08 03:35:35", + ], + }, + } + `); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/basic/tests/services/service_icons.ts b/x-pack/test/apm_api_integration/basic/tests/services/service_icons.ts new file mode 100644 index 000000000000..22fda1068581 --- /dev/null +++ b/x-pack/test/apm_api_integration/basic/tests/services/service_icons.ts @@ -0,0 +1,88 @@ +/* + * 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 expect from '@kbn/expect'; +import url from 'url'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import archives from '../../../common/archives_metadata'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + const archiveName = 'apm_8.0.0'; + const { start, end } = archives[archiveName]; + + describe('Service icons', () => { + describe('when data is not loaded ', () => { + it('handles the empty state', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/metadata/icons`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + expect(response.body).to.eql({}); + }); + }); + + describe('when data is loaded', () => { + before(() => esArchiver.load(archiveName)); + after(() => esArchiver.unload(archiveName)); + + it('returns java service icons', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-java/metadata/icons`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + + expectSnapshot(response.body).toMatchInline(` + Object { + "agentName": "java", + "containerType": "Kubernetes", + } + `); + }); + + it('returns python service icons', async () => { + const response = await supertest.get( + url.format({ + pathname: `/api/apm/services/opbeans-python/metadata/icons`, + query: { + start, + end, + uiFilters: '{}', + }, + }) + ); + + expect(response.status).to.be(200); + + expectSnapshot(response.body).toMatchInline(` + Object { + "agentName": "python", + "cloudProvider": "gcp", + "containerType": "Kubernetes", + } + `); + }); + }); + }); +} diff --git a/x-pack/typings/elasticsearch/aggregations.d.ts b/x-pack/typings/elasticsearch/aggregations.d.ts index acd36b0a7812..12542363fa8e 100644 --- a/x-pack/typings/elasticsearch/aggregations.d.ts +++ b/x-pack/typings/elasticsearch/aggregations.d.ts @@ -183,6 +183,11 @@ export interface AggregationOptionsByType { metrics: { field: string } | MaybeReadonlyArray<{ field: string }>; sort: SortOptions; }; + avg_bucket: { + buckets_path: string; + gap_policy?: 'skip' | 'insert_zeros'; + format?: string; + }; } type AggregationType = keyof AggregationOptionsByType; @@ -390,6 +395,9 @@ interface AggregationResponsePart; } ]; + avg_bucket: { + value: number | null; + }; } type TopMetricsMap = TFieldName extends string From 7cbc295d76df7c5e1e495419d9d3aec892df7875 Mon Sep 17 00:00:00 2001 From: Constance Date: Wed, 16 Dec 2020 14:28:22 -0800 Subject: [PATCH 19/38] Revert "[App Search] Temporarily remove sidebar layout and internal engine links for 7.11 release (#85820)" (#86138) This reverts commit 4d398f24613c0ec9c88677dc97e184441f7a1d17. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/engines/engines_table.test.tsx | 7 +-- .../components/engines/engines_table.tsx | 15 +++--- .../applications/app_search/index.test.tsx | 2 +- .../public/applications/app_search/index.tsx | 50 +++++++++---------- 4 files changed, 35 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx index a30b5c6858f7..ea7eeea750cc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx @@ -9,7 +9,8 @@ import '../../../__mocks__/enterprise_search_url.mock'; import { mockTelemetryActions, mountWithIntl } from '../../../__mocks__/'; import React from 'react'; -import { EuiBasicTable, EuiPagination, EuiButtonEmpty, EuiLink } from '@elastic/eui'; +import { EuiBasicTable, EuiPagination, EuiButtonEmpty } from '@elastic/eui'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { EnginesTable } from './engines_table'; @@ -54,10 +55,10 @@ describe('EnginesTable', () => { }); it('contains engine links which send telemetry', () => { - const engineLinks = wrapper.find(EuiLink); + const engineLinks = wrapper.find(EuiLinkTo); engineLinks.forEach((link) => { - expect(link.prop('href')).toEqual('http://localhost:3002/as/engines/test-engine'); + expect(link.prop('to')).toEqual('/engines/test-engine'); link.simulate('click'); expect(mockTelemetryActions.sendAppSearchTelemetry).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx index 58922e439fc7..e9805ab8f271 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx @@ -6,12 +6,12 @@ import React from 'react'; import { useActions } from 'kea'; -import { EuiBasicTable, EuiBasicTableColumn, EuiLink } from '@elastic/eui'; +import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; import { FormattedMessage, FormattedDate, FormattedNumber } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { TelemetryLogic } from '../../../shared/telemetry'; -import { getAppSearchUrl } from '../../../shared/enterprise_search_url'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { getEngineRoute } from '../../routes'; import { ENGINES_PAGE_SIZE } from '../../../../../common/constants'; @@ -47,8 +47,7 @@ export const EnginesTable: React.FC = ({ const { sendAppSearchTelemetry } = useActions(TelemetryLogic); const engineLinkProps = (name: string) => ({ - href: getAppSearchUrl(getEngineRoute(name)), - target: '_blank', + to: getEngineRoute(name), onClick: () => sendAppSearchTelemetry({ action: 'clicked', @@ -63,9 +62,9 @@ export const EnginesTable: React.FC = ({ defaultMessage: 'Name', }), render: (name: string) => ( - + {name} - + ), width: '30%', truncateText: true, @@ -138,12 +137,12 @@ export const EnginesTable: React.FC = ({ ), dataType: 'string', render: (name: string) => ( - + - + ), align: 'right', width: '100px', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index ce1e82ab2d57..11387734e9f9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -55,7 +55,7 @@ describe('AppSearchConfigured', () => { it('renders with layout', () => { const wrapper = shallow(); - expect(wrapper.find(Layout)).toHaveLength(1); + expect(wrapper.find(Layout)).toHaveLength(2); expect(wrapper.find(Layout).last().prop('readOnlyMode')).toBeFalsy(); expect(wrapper.find(EnginesOverview)).toHaveLength(1); expect(wrapper.find(EngineRouter)).toHaveLength(1); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index efa95d2033c1..769230ccffd2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -8,8 +8,6 @@ import React, { useEffect } from 'react'; import { Route, Redirect, Switch } from 'react-router-dom'; import { useActions, useValues } from 'kea'; -import { EuiPage, EuiPageBody } from '@elastic/eui'; - import { getAppSearchUrl } from '../shared/enterprise_search_url'; import { KibanaLogic } from '../shared/kibana'; import { HttpLogic } from '../shared/http'; @@ -81,31 +79,29 @@ export const AppSearchConfigured: React.FC = (props) => { - - - {errorConnecting ? ( - - ) : ( - - - - - - - - - - - - - - - - - - )} - - + } readOnlyMode={readOnlyMode}> + {errorConnecting ? ( + + ) : ( + + + + + + + + + + + + + + + + + + )} + ); From 2ea75487a660b8d4f661a7c02483afed856a77c0 Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 16 Dec 2020 14:58:06 -0800 Subject: [PATCH 20/38] [CI] Increase instance size for functional tests (#86192) Signed-off-by: Tyler Smalley --- vars/workers.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars/workers.groovy b/vars/workers.groovy index a1d569595ab4..365c30204ebd 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -147,7 +147,7 @@ def intake(jobName, String script) { // Worker for running functional tests. Runs a setup process (e.g. the kibana build) then executes a map of closures in parallel (e.g. one for each ciGroup) def functional(name, Closure setup, Map processes) { return { - parallelProcesses(name: name, setup: setup, processes: processes, delayBetweenProcesses: 20, size: 'xl') + parallelProcesses(name: name, setup: setup, processes: processes, delayBetweenProcesses: 20, size: 'xl-highmem') } } From c5e9543fc950a46b0e7e5c8cefeaad3524f7710f Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 16 Dec 2020 15:28:53 -0800 Subject: [PATCH 21/38] Revert "chore(NA): rebalance x-pack cigroups (#85797)" This reverts commit 1e3a483b06846d276cd26535bda287bbd4457c55. --- .ci/es-snapshots/Jenkinsfile_verify_es | 2 - .ci/jobs.yml | 2 - test/functional/apps/visualize/index.ts | 2 +- test/scripts/jenkins_xpack_build_kibana.sh | 4 +- vars/kibanaCoverage.groovy | 2 - vars/tasks.groovy | 2 +- .../test/api_integration_basic/apis/index.ts | 2 +- .../exception_operators_data_types/index.ts | 36 ++++------- .../security_and_spaces/tests/index.ts | 59 +++++++++---------- .../tests/index.ts | 2 +- .../apps/api_keys/feature_controls/index.ts | 2 +- .../feature_controls/index.ts | 2 +- .../test/functional/apps/dev_tools/index.ts | 2 +- .../functional/apps/grok_debugger/index.js | 2 +- .../functional/apps/index_management/index.ts | 2 +- x-pack/test/functional_cors/tests/index.ts | 2 +- x-pack/test/licensing_plugin/public/index.ts | 2 +- .../test_suites/event_log/index.ts | 2 +- .../test_suites/task_manager/index.ts | 2 +- .../test_suites/task_manager/index.ts | 2 +- .../test_suites/global_search/index.ts | 2 +- 21 files changed, 55 insertions(+), 80 deletions(-) diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index 11a39faa9aed..3c38d6279a03 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -56,8 +56,6 @@ kibanaPipeline(timeoutMinutes: 150) { 'xpack-ciGroup9': kibanaPipeline.xpackCiGroupProcess(9), 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), 'xpack-ciGroup11': kibanaPipeline.xpackCiGroupProcess(11), - 'xpack-ciGroup12': kibanaPipeline.xpackCiGroupProcess(12), - 'xpack-ciGroup13': kibanaPipeline.xpackCiGroupProcess(13), ]), ]) } diff --git a/.ci/jobs.yml b/.ci/jobs.yml index d6ffb7d8f90a..d4ec8a3d5a69 100644 --- a/.ci/jobs.yml +++ b/.ci/jobs.yml @@ -32,8 +32,6 @@ JOB: - x-pack-ciGroup9 - x-pack-ciGroup10 - x-pack-ciGroup11 - - x-pack-ciGroup12 - - x-pack-ciGroup13 - x-pack-accessibility - x-pack-visualRegression diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 1e4349ea5e8a..de73b2deabbd 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -66,7 +66,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); describe('', function () { - this.tags('ciGroup4'); + this.tags('ciGroup11'); loadTestFile(require.resolve('./_line_chart')); loadTestFile(require.resolve('./_pie_chart')); diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index a9e603f63bd4..8bb6effbec89 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -23,9 +23,7 @@ node scripts/functional_tests --assert-none-excluded \ --include-tag ciGroup8 \ --include-tag ciGroup9 \ --include-tag ciGroup10 \ - --include-tag ciGroup11 \ - --include-tag ciGroup12 \ - --include-tag ciGroup13 + --include-tag ciGroup11 # Do not build kibana for code coverage run if [[ -z "$CODE_COVERAGE" ]] ; then diff --git a/vars/kibanaCoverage.groovy b/vars/kibanaCoverage.groovy index b566bbcc6aee..521672e4bf48 100644 --- a/vars/kibanaCoverage.groovy +++ b/vars/kibanaCoverage.groovy @@ -250,8 +250,6 @@ def xpackProks() { 'xpack-ciGroup9' : kibanaPipeline.xpackCiGroupProcess(9), 'xpack-ciGroup10': kibanaPipeline.xpackCiGroupProcess(10), 'xpack-ciGroup11': kibanaPipeline.xpackCiGroupProcess(11), - 'xpack-ciGroup12': kibanaPipeline.xpackCiGroupProcess(12), - 'xpack-ciGroup13': kibanaPipeline.xpackCiGroupProcess(13), ] } diff --git a/vars/tasks.groovy b/vars/tasks.groovy index 73d7bb4088b3..a01e63e21814 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -95,7 +95,7 @@ def functionalXpack(Map params = [:]) { kibanaPipeline.buildXpack(10) if (config.ciGroups) { - def ciGroups = 1..13 + def ciGroups = 1..11 tasks(ciGroups.collect { kibanaPipeline.xpackCiGroupProcess(it) }) } diff --git a/x-pack/test/api_integration_basic/apis/index.ts b/x-pack/test/api_integration_basic/apis/index.ts index 4c797b21c6fe..66b3a45c12df 100644 --- a/x-pack/test/api_integration_basic/apis/index.ts +++ b/x-pack/test/api_integration_basic/apis/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('apis', function () { - this.tags('ciGroup11'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./transform')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts index 78450ccd70c2..6b32eb19c83d 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/exception_operators_data_types/index.ts @@ -9,30 +9,18 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { describe('Detection exceptions data types and operators', function () { - describe('', function () { - this.tags('ciGroup11'); + this.tags('ciGroup11'); - loadTestFile(require.resolve('./date')); - loadTestFile(require.resolve('./double')); - loadTestFile(require.resolve('./float')); - loadTestFile(require.resolve('./integer')); - }); - - describe('', function () { - this.tags('ciGroup12'); - - loadTestFile(require.resolve('./ip')); - loadTestFile(require.resolve('./ip_array')); - loadTestFile(require.resolve('./keyword')); - loadTestFile(require.resolve('./keyword_array')); - loadTestFile(require.resolve('./long')); - }); - - describe('', function () { - this.tags('ciGroup13'); - - loadTestFile(require.resolve('./text')); - loadTestFile(require.resolve('./text_array')); - }); + loadTestFile(require.resolve('./date')); + loadTestFile(require.resolve('./double')); + loadTestFile(require.resolve('./float')); + loadTestFile(require.resolve('./integer')); + loadTestFile(require.resolve('./ip')); + loadTestFile(require.resolve('./ip_array')); + loadTestFile(require.resolve('./keyword')); + loadTestFile(require.resolve('./keyword_array')); + loadTestFile(require.resolve('./long')); + loadTestFile(require.resolve('./text')); + loadTestFile(require.resolve('./text_array')); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts index 719ae136dc56..6eb74af91060 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/index.ts @@ -9,38 +9,33 @@ import { FtrProviderContext } from '../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default ({ loadTestFile }: FtrProviderContext): void => { describe('detection engine api security and spaces enabled', function () { - describe('', function () { - this.tags('ciGroup11'); + this.tags('ciGroup11'); - loadTestFile(require.resolve('./add_actions')); - loadTestFile(require.resolve('./add_prepackaged_rules')); - loadTestFile(require.resolve('./create_rules')); - loadTestFile(require.resolve('./create_rules_bulk')); - loadTestFile(require.resolve('./create_threat_matching')); - loadTestFile(require.resolve('./create_exceptions')); - loadTestFile(require.resolve('./delete_rules')); - loadTestFile(require.resolve('./delete_rules_bulk')); - loadTestFile(require.resolve('./export_rules')); - loadTestFile(require.resolve('./find_rules')); - loadTestFile(require.resolve('./find_statuses')); - loadTestFile(require.resolve('./generating_signals')); - loadTestFile(require.resolve('./get_prepackaged_rules_status')); - loadTestFile(require.resolve('./import_rules')); - loadTestFile(require.resolve('./read_rules')); - loadTestFile(require.resolve('./update_rules')); - loadTestFile(require.resolve('./update_rules_bulk')); - loadTestFile(require.resolve('./patch_rules_bulk')); - loadTestFile(require.resolve('./patch_rules')); - loadTestFile(require.resolve('./query_signals')); - loadTestFile(require.resolve('./open_close_signals')); - loadTestFile(require.resolve('./get_signals_migration_status')); - loadTestFile(require.resolve('./create_signals_migrations')); - loadTestFile(require.resolve('./finalize_signals_migrations')); - loadTestFile(require.resolve('./delete_signals_migrations')); - }); - - describe('', function () { - loadTestFile(require.resolve('./exception_operators_data_types/index')); - }); + loadTestFile(require.resolve('./add_actions')); + loadTestFile(require.resolve('./add_prepackaged_rules')); + loadTestFile(require.resolve('./create_rules')); + loadTestFile(require.resolve('./create_rules_bulk')); + loadTestFile(require.resolve('./create_threat_matching')); + loadTestFile(require.resolve('./create_exceptions')); + loadTestFile(require.resolve('./delete_rules')); + loadTestFile(require.resolve('./delete_rules_bulk')); + loadTestFile(require.resolve('./exception_operators_data_types/index')); + loadTestFile(require.resolve('./export_rules')); + loadTestFile(require.resolve('./find_rules')); + loadTestFile(require.resolve('./find_statuses')); + loadTestFile(require.resolve('./generating_signals')); + loadTestFile(require.resolve('./get_prepackaged_rules_status')); + loadTestFile(require.resolve('./import_rules')); + loadTestFile(require.resolve('./read_rules')); + loadTestFile(require.resolve('./update_rules')); + loadTestFile(require.resolve('./update_rules_bulk')); + loadTestFile(require.resolve('./patch_rules_bulk')); + loadTestFile(require.resolve('./patch_rules')); + loadTestFile(require.resolve('./query_signals')); + loadTestFile(require.resolve('./open_close_signals')); + loadTestFile(require.resolve('./get_signals_migration_status')); + loadTestFile(require.resolve('./create_signals_migrations')); + loadTestFile(require.resolve('./finalize_signals_migrations')); + loadTestFile(require.resolve('./delete_signals_migrations')); }); }; diff --git a/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts b/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts index 83c4e5a48b89..4948bee7e6f5 100644 --- a/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts +++ b/x-pack/test/encrypted_saved_objects_api_integration/tests/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('encryptedSavedObjects', function encryptedSavedObjectsSuite() { - this.tags('ciGroup13'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./encrypted_saved_objects_api')); }); } diff --git a/x-pack/test/functional/apps/api_keys/feature_controls/index.ts b/x-pack/test/functional/apps/api_keys/feature_controls/index.ts index 4cd95e5966bb..169b5c7fb0a7 100644 --- a/x-pack/test/functional/apps/api_keys/feature_controls/index.ts +++ b/x-pack/test/functional/apps/api_keys/feature_controls/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('feature controls', function () { - this.tags(['ciGroup8']); + this.tags(['ciGroup2']); loadTestFile(require.resolve('./api_keys_security')); }); diff --git a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts index 89690829a0d3..e7be2cb48ce3 100644 --- a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts +++ b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('feature controls', function () { - this.tags(['ciGroup8']); + this.tags(['ciGroup2']); loadTestFile(require.resolve('./ccr_security')); }); diff --git a/x-pack/test/functional/apps/dev_tools/index.ts b/x-pack/test/functional/apps/dev_tools/index.ts index 121d9effc2b6..767829d4494b 100644 --- a/x-pack/test/functional/apps/dev_tools/index.ts +++ b/x-pack/test/functional/apps/dev_tools/index.ts @@ -7,7 +7,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('console', function () { - this.tags('ciGroup13'); + this.tags('ciGroup10'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./searchprofiler_editor')); diff --git a/x-pack/test/functional/apps/grok_debugger/index.js b/x-pack/test/functional/apps/grok_debugger/index.js index 948509f650e9..75c05f35abd2 100644 --- a/x-pack/test/functional/apps/grok_debugger/index.js +++ b/x-pack/test/functional/apps/grok_debugger/index.js @@ -6,7 +6,7 @@ export default function ({ loadTestFile }) { describe('logstash', function () { - this.tags('ciGroup13'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./grok_debugger')); }); diff --git a/x-pack/test/functional/apps/index_management/index.ts b/x-pack/test/functional/apps/index_management/index.ts index 4b585b4d698d..97b23cbf82c3 100644 --- a/x-pack/test/functional/apps/index_management/index.ts +++ b/x-pack/test/functional/apps/index_management/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile }: FtrProviderContext) => { describe('Index Management app', function () { - this.tags('ciGroup13'); + this.tags('ciGroup3'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./home_page')); }); diff --git a/x-pack/test/functional_cors/tests/index.ts b/x-pack/test/functional_cors/tests/index.ts index 673cb464c860..7e16e1339b1e 100644 --- a/x-pack/test/functional_cors/tests/index.ts +++ b/x-pack/test/functional_cors/tests/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Kibana cors', function () { - this.tags('ciGroup12'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./cors')); }); } diff --git a/x-pack/test/licensing_plugin/public/index.ts b/x-pack/test/licensing_plugin/public/index.ts index e771098ecd36..268a74c56bd7 100644 --- a/x-pack/test/licensing_plugin/public/index.ts +++ b/x-pack/test/licensing_plugin/public/index.ts @@ -9,7 +9,7 @@ import { FtrProviderContext } from '../services'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile }: FtrProviderContext) { describe('Licensing plugin public client', function () { - this.tags('ciGroup5'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./feature_usage')); // MUST BE LAST! CHANGES LICENSE TYPE! loadTestFile(require.resolve('./updates')); diff --git a/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts b/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts index 4965e1aa7d2d..c73820536120 100644 --- a/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/event_log/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('event_log', function taskManagerSuite() { - this.tags('ciGroup6'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./public_api_integration')); loadTestFile(require.resolve('./service_api_integration')); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts index 69fbb6be3ad5..c1e7aad8ac36 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('task_manager', function taskManagerSuite() { - this.tags('ciGroup12'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./health_route')); loadTestFile(require.resolve('./task_management')); loadTestFile(require.resolve('./task_management_removed_types')); diff --git a/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts b/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts index 302ddf071bc3..648890a2b543 100644 --- a/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts +++ b/x-pack/test/plugin_api_perf/test_suites/task_manager/index.ts @@ -14,7 +14,7 @@ export default function ({ loadTestFile }: { loadTestFile: (file: string) => voi * worth keeping around for future use, rather than being rewritten time and time again. */ describe.skip('task_manager_perf', function taskManagerSuite() { - this.tags('ciGroup12'); + this.tags('ciGroup2'); loadTestFile(require.resolve('./task_manager_perf_integration')); }); } diff --git a/x-pack/test/plugin_functional/test_suites/global_search/index.ts b/x-pack/test/plugin_functional/test_suites/global_search/index.ts index f05aebd26cc8..f3557ee8cc8d 100644 --- a/x-pack/test/plugin_functional/test_suites/global_search/index.ts +++ b/x-pack/test/plugin_functional/test_suites/global_search/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('GlobalSearch API', function () { - this.tags('ciGroup7'); + this.tags('ciGroup10'); loadTestFile(require.resolve('./global_search_providers')); loadTestFile(require.resolve('./global_search_bar')); }); From 6671cf3c2255c89bc1d2913e62bd06a59d2bd2df Mon Sep 17 00:00:00 2001 From: Tyler Smalley Date: Wed, 16 Dec 2020 15:30:21 -0800 Subject: [PATCH 22/38] Revert "[CI] Increase instance size for functional tests (#86192)" This reverts commit 2ea75487a660b8d4f661a7c02483afed856a77c0. --- vars/workers.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars/workers.groovy b/vars/workers.groovy index 365c30204ebd..a1d569595ab4 100644 --- a/vars/workers.groovy +++ b/vars/workers.groovy @@ -147,7 +147,7 @@ def intake(jobName, String script) { // Worker for running functional tests. Runs a setup process (e.g. the kibana build) then executes a map of closures in parallel (e.g. one for each ciGroup) def functional(name, Closure setup, Map processes) { return { - parallelProcesses(name: name, setup: setup, processes: processes, delayBetweenProcesses: 20, size: 'xl-highmem') + parallelProcesses(name: name, setup: setup, processes: processes, delayBetweenProcesses: 20, size: 'xl') } } From 25548bbae4c58e607c42811fb4c3b7befe280c9e Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Thu, 17 Dec 2020 10:38:03 +0300 Subject: [PATCH 23/38] Date histogram timestamps on daily are getting displayed as epoch times (#85565) * Add formattedkey so that we can use it in tooltip * Fixed remarks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/vislib/helpers/point_series/_get_point.ts | 4 ++-- src/plugins/vis_type_vislib/public/vislib/response_handler.js | 4 +++- src/plugins/vis_type_vislib/public/vislib/types.ts | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts index 5eb1e6596531..fb42416abe24 100644 --- a/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts +++ b/src/plugins/vis_type_vislib/public/vislib/helpers/point_series/_get_point.ts @@ -41,7 +41,7 @@ export interface Point { table: Table; column: number; row: number; - value: number; + value: string; title: string; }; parent: Aspect | null; @@ -94,7 +94,7 @@ export function getPoint( table: table.$parent.table, column: table.$parent.column, row: table.$parent.row, - value: table.$parent.key, + value: table.$parent.formattedKey, title: table.$parent.name, }, parent: series ? series[0] : null, diff --git a/src/plugins/vis_type_vislib/public/vislib/response_handler.js b/src/plugins/vis_type_vislib/public/vislib/response_handler.js index 871ce97ad448..9028b53fbd00 100644 --- a/src/plugins/vis_type_vislib/public/vislib/response_handler.js +++ b/src/plugins/vis_type_vislib/public/vislib/response_handler.js @@ -34,14 +34,16 @@ function tableResponseHandler(table, dimensions) { table.rows.forEach((row, rowIndex) => { const splitValue = row[splitColumn.id]; + const formattedValue = splitColumnFormatter.convert(splitValue); if (!splitMap.hasOwnProperty(splitValue)) { splitMap[splitValue] = splitIndex++; const tableGroup = { $parent: converted, - title: `${splitColumnFormatter.convert(splitValue)}: ${splitColumn.name}`, + title: `${formattedValue}: ${splitColumn.name}`, name: splitColumn.name, key: splitValue, + formattedKey: formattedValue, column: splitColumnIndex, row: rowIndex, table, diff --git a/src/plugins/vis_type_vislib/public/vislib/types.ts b/src/plugins/vis_type_vislib/public/vislib/types.ts index ad59603663b8..5096015c99a9 100644 --- a/src/plugins/vis_type_vislib/public/vislib/types.ts +++ b/src/plugins/vis_type_vislib/public/vislib/types.ts @@ -33,6 +33,7 @@ export interface TableParent { column: number; row: number; key: number; + formattedKey: string; name: string; } export interface Table { From b201843e684ee5626648c83091a2395a77e47d8c Mon Sep 17 00:00:00 2001 From: Pierre Gayvallet Date: Thu, 17 Dec 2020 08:50:31 +0100 Subject: [PATCH 24/38] Add user doc for SO tagging (#85557) * Add user doc for SO tagging * add link to new page * handle review feedbacks * second pass --- .../images/tags/bulk-assign-selection.png | Bin 0 -> 173188 bytes docs/management/images/tags/create-tag.png | Bin 0 -> 87931 bytes .../images/tags/manage-assignments-flyout.png | Bin 0 -> 213896 bytes .../images/tags/tag-management-section.png | Bin 0 -> 345823 bytes docs/management/managing-tags.asciidoc | 75 ++++++++++++++++++ docs/user/management.asciidoc | 5 ++ 6 files changed, 80 insertions(+) create mode 100644 docs/management/images/tags/bulk-assign-selection.png create mode 100644 docs/management/images/tags/create-tag.png create mode 100644 docs/management/images/tags/manage-assignments-flyout.png create mode 100644 docs/management/images/tags/tag-management-section.png create mode 100644 docs/management/managing-tags.asciidoc diff --git a/docs/management/images/tags/bulk-assign-selection.png b/docs/management/images/tags/bulk-assign-selection.png new file mode 100644 index 0000000000000000000000000000000000000000..1c8687226b51fe9c8b61ec62e78f43594fa0bd8e GIT binary patch literal 173188 zcmeEucT|(zvUfm0iXeiBfJjk5LX+Mh0!r_pH>Gz3LN5VDRFqEWy?3OBgl47p-Vy1& z_x3%!=iGbFTHjsw&A;Eb4r`gjB+q{Ko;@@BH@}(5M>Q2$VnS*{5C}vpFDIh`0uiWz zKsc%Rc)&a0owzFyh_Ka0T3StBTAE(X#mUmf-U0-Y`-q6U3Dq3C7u?ez*wBl8CxXnI zJR2Vecv^1ws33<;z!V&m{!;emod-l<#`Mq2`5)exVVSdkz@4Cf`Ay;(9);UoA_3?$ z?!#A$4F}T(TPAD8XBJjz4M(W8^8;o8-0yA6I;2O2f;~3r~{rE}2wLXH0X!rY=G&gsHk6wfK!v z1wx;qui%YgS0(H0W9B59Fg2X0uTS8Il&iRJYYVeoW*wcR9x%f!nOYqq7># z*CrO`^u^RsTetOb9>K*}h!AQ$UVc&WB9le0f?gq#P5IA{MDs9na2Y$V_AAQmv5;fj zH}S{v-Q>;hlq>jnMLgSEWM9R#X5Ky6dyX}&>2*P2*Ashb(I8c0>R3w8tXA&c4ZZNa zV+YRVd!|kkzO^Q}Kwh*>x#Z2}^0AWf?&Wzg=$%m_Wl4O}C&$(T)SVEI_-_Ou@#du1 z*q|Ff->^pzJr1~W9!UBDBpKIaZ6A)EhWp3&<5Q!Ej+YsEpL=@DhvQ z$ql#kcmB6O2MB+`JN!yei^cW(<{OC62ds}TAO6P1YJI_Gf*%`zNWUNRCiEp+J`Vp& z!O`0!fsfLul5woQJ%3FB3pDsG5%Csl8~aw^?Uy)j=*48-Sx4N(>tNZuuKGQIhl7E^tb$QzHbnPi3{vw{a z)2owMiOv##k5=*5>dTTZrMdzFSV>_is3sWGiy z0M#s{93K=I`*U-;i=GpD2z#r@s2TOB}XX7=(X>~5XE#L!oemw z{smG{Zmk{l*?e}*0uAAe{vw`Y1Vj8t-iJSv+T)5hw zT8cOGq_?(8t4h3zs0zz18J!?vATHeiy@>G6JBnsH z*vi^+4Ne#MJv&=~9jrJGpav9k=@R@^Zw{9ae(cvPt~6Lm?EX@k>KIU}>ruBUJQe2+ z6X$BU)xhDMcYt?bbNcX9>Vo6cYCnya?>_sBds%OsQ@PF4%}A~3c}FdJZJwH1Ti&rthD}G1;$JvwkVAsCUFQ5Y{6oao2V0`P%(D zfgw>{G;1W$w5y`KvJ|;lnK2PGdUu>}qCU|^jMru{H-VP7X+mV&a%{7_!70y@(p<-S z#P(=-xmTLt10Jf;b4(cXM2zH#rgHe&bF_qVFKcujs|#x#mrA05w5-c>3iQ| zelP!S|J}k6%McYYtR}?w1m?Q@_G$D}bzN5>e5?0PB=GyM?nRRC*gfXtVXOe}%EuTD zM&*ZD>+hd0-{_+=tv3_+IT_9$j`&s6!rH>rGW5&u^HC_*r#O~QCEdi={OY3W@uN{e zsv(NwNqk~0PTj-8H`>D5ezhT&61$A}j&{X1y!7@|x^z-|65xEeNn~j*^b2e($(kKh zDi(R#c_hw$wG*{mp2qbY_0Jkbn?7Ihb%~d-Z|I?YP8au|1?Ht2Zfh(*D!$v;hToar zb{tQYisEwRW0NT2PKrp0@{`JDZoivil8$`Y_r|dtQLD?|it$orTeb{!$rkLr&# zbgL3ZGxNrk#2zeo&1)_A>EB0gFEb83&wM_z%dt1ID9N$Sb?n7$$?f5MM)sD8EpDH~ zf@7-smVPX{*bmjWo4Ig<4O@HNL|#7uwTqOR_+Ih-sOXPQ^}UsQB~MmOXuqHvbqjPg zChM9Vl)G-n(*;SwO5Jqp{5ForjN1?z6aBmWWoxx-rRUa1X1~I-)&_<>9AA%raed^N zWj(i{oSJkPR}f1PbKpcWHCgqpJjcA_tYi;q%$cTTTp3!WT%&A!N29M|%JZyw!-NeN zfh?>qqAqeP9MOhPew*m49I&&J4s}$v>55AWlAIc&_)=6bTvg*M=;$%M$>Q_p5O&^q zj&dwJobGR!IsACob|kwYX|iOf;{jRv8th$btS#yJ^yK9T!;CZs@i1{6^-5^Y`){wt zW|x|>&t1;swj&R-IBE(c5m?gL%64~rMD)$To;5>sxTS94-ZqO=Z#Njr&FvvDmNQZaUM?dmmxPtZ!+E1dKfF&?*%=p`?VG7!g5j| zG1F)lo<%pawRG5YEPdKC5}3&{$g-e%kTxt{33qqtg@0K)NnX0a^^@y`@x7~pQ>z2E zJ)IU~pN2+(n5TT(FLo{WH_#sXTZav42aSG0rpJBn*Ka?fQ`X83O#^Y@e2rJD7steOqRuVCDa^QSr?qq7g>FMwq_%;Y6<|zWa zbg+QEqW5&LcXSo;6leVF8zR8#>$kZW>Hqo)%ubw9S6Pi-+R4R&o}ZJC^C_bQAw504 zn2Wikh=$CIe_js!Pn^*j274{S#pU7Q!Rf)v>EvR?#Vsr>%=MIqi-(5;_y&iomm};8L;ccSY1}JT2^XWo#TQ99@BXNbv9q@rnI)!T4a>zlASBsFhV(0_?{F8yQt7@Qi)E zIlz-D@bKgx&%kReXDV|hmv9gW0+N?`2KB^RpTdpT8lrCA34ay5`2zi%m0*SJZVV|a zVmtFqU|;|vL%L~ZK*$>oGVrUwfDcb-Gv(gzgUF)#m0ph^TN;Fg#a~-?!>5R>TJ%Nz zeE^`9aCD-L?#Lw|#=;?mfG~T&mkNa80rEY<)>FCl3<;kay1=p#(GA^?O1p2mDWr1<)PV4s~Wqnt6<5qiikQOxIq z{frF~0Jf$R7YxHtoq(}%@;z^2tg{e$Yg~La+>NZI<~tZGVE~9?3-kHlLaVQ>g!(6qp?s|F54E^uKT}NBs;f&+l<| zT#0~ZTe=m@2N&*&Qr>(43M^tHO_WHv+mocVis)gXb>igYS6D!yDI=7u9zhUF5fAV% z64E3tp0W{Jblj%%Oe-}uezsnqBe6nzk%x|=+mUPlcu1Uw^F9Ux1%9Pm7H~wdkGnkH z=89pH0R@^X>4his-vs8=|NQ|SCPUGar|&`|#9up7V%-iL)czO(LbTj4 zr@-J+EF3bf?Uv2Ce#iYkKj{J@@#!O&aT?b~KN`{Xyv9bc`m%Tc6 z7P}SV1#_k-1sqa2?m))_#rC2jsABmX%TgeL8dDx~ixdXvi~a*Hr%5BbvavpWU05=K zDXt?e77jEW7HD6wjk1j5G(rd5WPng?hkqcF!DKi$e3>MWRzjYog8BZ!pz}9FCSc#< zA=YvtV<*}M1Pl;_Y4Zb2HVq30TMkmBY75L!UUnnJ;K%wXosePZNO@M*D#1;G>al%i3to~;M*AC*@#8ls#7QoS{1V@%GNc* zCinq_y+b}Ko*NpJeVgFe<~$!l(X=Gbh0#&+;W^|6RGk^3l?c*eS6G*#uf=gs0BLz+ zL%$vLq6{z@qImq^_%Ek*Cp2*2|uyOSSP;iLE{P!Kbst$(`QxBtleMrI>;mWyoMeP$7FbV000vP z<$dL+C-npXJ@$NpuY_~Ot%p3Fs6?_~pE`Ceh*I3{VX#P22)zw3K-6N3HBNsauwal^ z#r1g4UQ=PPeKy*FToV1NChud*lhH#Ej~nM{lmfsf?80Q2xUNPZW;@Y%MRN`32_rm! zu`tw6`Ys@NQ>YA&rIDtWzn=cjIN!H`pG#ws#l+8jjRPV%6R^GXb>xe+OJW!b(lR&C zUY~(O4uju!OgGHBZ2x}NhG2`k%b_6?au=nd5c7l+<+`Mz9hsm1WDM!lbRgT~v;CW) zEuQ=B-6v`gLQ2lZ)lQ{M2|O0NB1^MB-Y@*gQS3gH!X;7&zD1RMaLm3wR;g3tIKeD? zB@DiLAP(;9iz{)x$EFW0tt&!75)`Cguw>(x2>CC3ey|1jG9{q{%^(T@1DPGj)?!w3A6!@8}766AC>w!!78 zWk;-*h}$~-jWoX(urWuDEo(L!0sAT)i^F249R2FTZgkVT0jus-t2E^pr=|9W6Ej$@+UfOeZ-h%<@UU1(?WT<2=yjKS(5sVP+cU&Ulw#?3-;fSBW zb;qy5Zc&MdeLE_8R(RCh$U#g!_-SjQ|MuUzH+l-f>>AL}9xb@zMrg-lIq!i$&E5SN z{tBC`0-R7q`=vz$p?q2_MYeS+dlav0d{FM~$kt_RVK}RTz@{iu8s|9c-Y}ig`YhG^ zuUdfDa?^^RlaP10nQwf5r^5Gmmc=Ic2QEzNtdR zmL#)~h{uC|3t?IPCn-4uw6W=z%HVr39+x`OE>>NnOSN6hgG2tEWWqk&Jl%~2C}}w~ ztb0Lrt>Yej*8zGz3VUT7J4gKG z(a|ib?VD3R=3Qxa7T?~OG&Ebg<^Cdq#{z!edt-0%>B6V7;&#o{3Ac;bTxBKFqQtv` z6uIBOOEHQ0HrY?tKj(YBFwQ4aZQh5CDwFN;RGpH=wn0OJy-YN;j`gW%-CuOE8*sc zmLa1qT6*Lgmf#BIH;0RCsHnVkES%ejetDJhQZnXT7<{tm2!zkACsB)v^%p1Kvhm1r zTVd%ojso9U!s&GI-GfROXfc<$i4zIZ#cs~&;B;2ww!gb}UM!J@ScN%?aUD}f?t5sq zl&Gx)tJAiwYFqD(O2J~?at*xORGe^!8AqoIi8_xha9IPHj~ff^z<%sK$2nMz|AjY? z=Wkw(5`C>QKlH1u>DN?yhq?(87j{-xMjPYpVJUTgDALiem8ii&qZzyLMp-&9xqa2? zdavX;G^h1z`+1tI=Tk-om6pmDe}b~LHeJLYVnQ+oK8m2mhJGYg9c!Q6s;a#AN%AD6 zfmKh^Cvkgl`w%e|R)EOKEhCI$nz)RVX6aE(sW{12LHYLQOZm6mkDXpALWFN#z05hU zSou=PQNj*5f+!%t?pFM%)r1am+>dN^V<_u)QeI<=U2ya5GkO6K-W@|uvXix)3m$PZW|+e(e5MgqHOVdZ(fI7d+3t4Pql$4l&^2scW3(yKNA)79XDp{FsKwa_pBHMqt2rp4f zm^JvKt>Y>;on{*z^5-~&W_EA(xz>bOZFh{Vlt=KJ<rP|Z$y?upAwFUE^LTdSJ`3&cZWr&2es zV)p%3<$Z=WDiHKGyCrYH<{x`d+(yA9}z2^sJ=6{YURyaUu`uZWO+HSqcqa+E8XZUJ4_;%lK zCmLdb&pJiKrxGfyn0#vN4|8$+4&kSIC$_6Ft4_ZoH-wJK!`b2qqW2`UvDDS3{=e59 z-rgjRXz`XbEn{AG-3;H$wknftXg(%V^TKOLrMpbtUp)yJIUW^Q9(+&9WgOF)z}qq$ z>W6_96&QX!2ODvkgvH8{tFaDjy$`5OIu6R?W9RpPX!2ed1r5?(M)Uin8T;mq|0-d< z(B2fXeHR8ZP{7Skb<|Qnttw8>`=Vd{%ynTj;nSgQa$2cYJ|8{wv>>57o zT1T*!3OKhpQt@<&j8 zO{HnVpe7<*l6ni+rRY3g)*g}vre*qR6G(>`cD;&PhfiA}culrLrCc{}qw@qVaPuF+ z|F8lGmd&KlquP#bE6k6rF)xb_1EfSsfTJG(mY8Mr6LafWh%Qj&i})uHa7m4C@T*K{ zE?a;P9Opm-YeON5VmaV-@S!nIJZnuy+hp?vugDKnt%PTOz4pZ!CgzYLnU#xIh4WyM# zI%*a7H z6Q=Vrw1(Oa9{wqW3}q_3Dym3W`{vfUvKN`Dc?+$*)Gtxw@i6+(iNkrrk>h=0p`l%9 zs5Ymo!{OZk_iBzQk8veL{1mjlf(8q0@coQ8g<$xn@m`0IQsFq6HCADqiI-7x=+#&5 z`h#Ihp4ox$WH+DL#)r4t-{3Zl7xfqGX(kBGl3R&$6G^{spilEZL`|pxZnS(WEN;XY z{-b1zQd1(XIg}cW(NPP+Qhtb|fLnMRoVT8rtN9D1G7|U5HD1ZDB5?9}rpo_e#|Wgld%MEmACSUo89HPA1Zq`^m63iYWDb^4RC}uVqdOc->rDkX z)dM$)+*|Dy$M>nM*&-fA6Ik*`^y8LxesJ&TAd)FkM+u}vl`9`Gb~6(<9-Lbv>`%9- z7Q15AU%1uD?^AgSU_(O+o4@dwG)0ZS39z`T*fFaduB{gK0g@iT(Ut+bj6iOGV()%Im zT?~?^Db$-w-;f`I^Q&y!vfZ;NJJNhqJdIRPQezh1ep{+oJn3Nt(b;RfI87=bs6LHs zq@h(}${DH)^P1AW8@yHdSG1e5CoHj{jt?B!aPlXGqO2AM3p6X7 zX8gyH@TT?Y2HBdeQP!rb%lGT!)e~ztfOMaSAl%nPtqzYgs@oBC#>kW%Lt)?JFVHf* zkrHGR2;sh)+}!g}7vRWN2Fu@8p|f&gSm*px-037Rpe*0W(vxEU7eu>C4gYfKDM3Z7 zzT#OTlcQWjc92%lT(Fuop}`2rp-4Gwbj^D>ZA;B}+NCrVYuLpL8FC+FObdJ>o~9y; z+~^We5n?HQIwE>i#NaXXxnLgl`=?g{uYKx>#RxcMMCpu@vE%Zz#V)Pk)zO59$WZaa zwCy@Aj`r!iYnj?;F%z@e3>@t+le3GsFJ@M6u9azV)x5@5o++MY0g%RQkwNjqADZ-v z+nHPG+SC1eCw4?>cAOT3&CrZf=c#8a2RqeLQuhqNIgP(u--xX9C8j^uh1yZw(x4r#T8Y$s}(%sXOBD*S)oAqh2|X?t}7R)Hu& z_w;4)I8L7Jb|Gh4s5wK<Aa2COn7SHBJ*x^eW8Db;vJP^v1w7AVjK+G}P}@g5whvOL7zJs$lP}w;Ni+?z#*HNMsQc|M zwVEq?EqfF8fQCXS9m$DLYz$t3Row(A@=fhF>?opFw7uw3ie5 znV!xChB;9&e41m3C+boPahyyPWo7gLl~m=elq4a2dPwv8!4JTJY|sACXs|TO3+H4v zK|gI9m^(?Neky?l9w8e0@+zw{ncu*&CzU4eo%m+P`-d^FdWZ$~vYQ`UZfy86{{7LJ zO&n-PkzSEEG!UYpAK6lA^DC7RRVjDHYG;00xQ+8Z-|&YfuRl?ofAolFDr4K4ow1{h z7G3|1i^j9sNq%qVsBjxPdIqe*Yq09Qus0@6em*vLfv9*nz+h+C{AHiHc7Sgpbm>xs;3k}>>?7;~qcGQ1F{1>C< zc^JN^kxLBRGYD91IDxm>@d}=aCRaB^5s-HK)f5c82O*?qt04jHpMLsCo14e*Ik+eF ztSXLGSRmeeAH;aO*>w;LLSb(-re!~lk)?sOWMqP3*p0qzkPhUjM0y`gN^3dN{wdF7 z_|mNG9@ zhgH5wB*{^A%D9C9NmDzE!b?AYm%l206+I#({$Xu2hER3It9i;qaU9B(`6)9avtPBV zDt7KHE;u{Y{!TQv5O8)?(N+GWN{j#vjb07KxbuI~H&ZqF5Yxg^>>frwA_d*I&_i#~ z^{G0f4i)n~sIu%K&@;`&HMDu-xOS8h!@KxkTp-lm0(Sx?%!*YAoPiN*E>^=oTGJK{ zoi1vJ^uu~gMBb%^$y$to`*QpSARjw&_J7Pmg-i=^mfw{=Gh*L9I>RLpd z!ea$Ww&Z#Ty@9M!g#Seu&PQLZ^!_;?m1;rDeYus%f-JvP89z?_dKonAB5h(c8^AIo z=Gr6=#U8uDlUe4P;V(ISHdVV_y&fjHVIX?DzeHa;u*<|JbKqPyo~e00M7v3wj@AdF zD$`W0H`577<>}*BiuH7h!6RD{hJe6I2k6xhfv(Br1O#g06N`9W=QX>-qkD0g*}hkL z-Ogm_-y%cFcyINa%H>E>#kTgIindfCZe=hGHv+S*>W|X59e4_zQ2$iC5OdDfh*ii6 z#H%kxD8Fz%mv)(&HsI{=gDMS>lpf7erJpv!9~Bt$gu6X(E8(7(wHuo;**eH)b+G#x z^rz}J78tI^Z9?Z{#`QsOb}He2VEt5~AXKUwq3YGLYVI!?!gW(9UYnQrSp zL0e(bf#93h^h=GfO5I%htl0TIhO03O$VIr*B$8$1@>+Gb_s(*)@{!+jbwDER8R+1A z({ALLaIQ9x-}<=uF`VTLVEDQYub73&Tf5(KMf^i>|HgGm|L*CHBh50mss!q8$I9Uc z5z}c#1rHDrAVhGRKP+KW`G#D%mPLQBW`hu=~2QVmMbZvd`s5z}Peuo30rGY#>Ag!KU3vZk>gvYx3SAf{(hjBOJ)LW^F&UhU^cx_B)8RGve6AJFxe`mrGARulljYJYSOZcHz}xs~%t z#h~fXqb*4=ys{e`0}^JHvUV5?O!3+2!|FF?i|jp7#f6!@JC55UV88}`#sL&M9>wlN zQ6?ha|0zXIFudVeSmM*@sX|06M^9DhvJ!!nQ(CP#@>W7kw{f)uId%G~pPew(;Ngp< z`*l~sW`$smqr%_=m!(1%lOGx?O|^7;1X$BY~D5@AIq{o}q*@c=DwBfb!`Cj=+#>X z1_kFL1%I7Y+94lSyzVnCy9B~hpC3N}6B}twgO?)CHrK!axxGhCGZNgDglsM0&_}r$ z?63K<8q|EA5YWaT1FeCC(BtGopGq)*P5MVf#BxTmHD|hLdw+6_nwb=-Joo6sajLK) zjJ_fi9jhzu>AANN^@_Lt284iEZROiNi4nv0yPpXpSI`m$DJrkS6AH`ZHaj)MOtg_U zvsK|sFgO>inEf_iV-#_(*#j{zW4;KjQKd5-0Ep+g#D*c0$_Sxor?sS#=S45Zl*KbU zxo1wClj;SpxO^(jdmb>`nV^iSu%o9KKPMTVWoS}nOUg`4uwX@x9BjrH(3uX*fFGM%jbwrNXdXo%s6 zpE`xDz0~%_&9CY?e}-&57+Kg}->fc06d1lW1%jv#$;3GM4+v+7L@10tYHZGClr_db zCZ-ua5~q(Xxh*~kK*^K7>s|Yc4NyfkaPMlZxNJ?K?{C%ko)E6UJap17{BZL{+%_3I zbPN-m_AVbDwJAPIJrb6v36(s5D*MoX-xm8fX+5`g%u=v+``84?f z=Fo<)1-l;}Gd)o)54Yy*;;OrVC}3#hMSI;=!#TvklR}}KZw1vps&Z)`;U82Ym&&T2J}VAa zrdLb~e%F4~v@7ZhH(TEjQBGH3%ZqJHOf|{7Wk~1WKjLUN@fS-o{KQsDgPCcePupG+ zeA~CSAIH}*T5OC**C$ONFs*>?$b0{@-jLeZ#FU*}jgk&nJw?bzzVKG^+>i;IdT2c| zarxqX0_&L=fDQzmE}l{GxTQQ0b+z!8>G9t&8nHQe_;fb^XBOK>qJJLm+A}j@)l^kk;=woH)5`it`ZgN%$2~)}(z}E)HYQpsLa?S_D z;?lYX-%%G1guG%iv47=3`R};ZPkGxWkpP0K`A9AiY1x&CcHFHK^Eov1T8?b--3;e| zv^$Fg&IuU21pt$Ji8VrL7!yk2IAiUK&e366*bfDCk9 z;{>zZWm^%#Dr-Q0BRZikrEb? zxMTOZtWkb!xYiUaVX`jO760F*Oe5$Rbq|T$8RzyMlw0X-ObH4$mKQ|3i};@h70mM) zO9082kuJv$XWV?wB)G+;2V7O}%WoZ|GdhzZ1t#-BUno*AI+Q946l+Q~8}Ix6u+hb19E6jgIT?Z$ip)?4%Dkr|OW zGW7OjMBwi7qucWDLJ)I6(xF%Py~fVe{JMlPQxe6wQlS24}`Xn_M>0a znN?5vHx~~JhAQxG@0MmS41dG~tU_5y^Rd9c_HU_o=~8h1n9!+7wgRfCfh34LV$l%x zn($UbQPjSz{xIRAhVv3>7 z@p!gAwF<&ZjpZ^}E^hId?M$fb?}Iw^N2r-j405p~y&jrz)ZG2W0?An#P=IE&)X&{( z4C!&RMilPMHMespC+SYj(WLixH(fQp*sL$g;^$xihdZ@X0!_Ob0I;r|Q zvbs9to%UGFbiJ2`gL`zjfLg1CVv`b}h(bqEBy8`oPJn`{>wFq~e#Hv!G+BkKrlXg1 zpsK(`ZU~I90CFoI3Dw40X3TPz&wT$pKH1Jv-B9+Iq~W)vcM9`WzNUy*qJdC~M8Dhx zA+}>~B5Yk~%T%@Ecbi%Wg7#QrTp2Jq$xvE$UdEsblXMh2@L{@!II()@ruJ0g>H3_B zhki!%SM7yW((QZJI+gjKFHDrTXe|}1PM*Ptb;eTs1sRI!UU1dul&!L06&AH`T$xu| z^&s9q^y*wuJ6qJ>1**SN4t}!xO1j2=_VcK>AFJRWo~5SuJ};kkF*)Ll;HWY&R5e9}35aLo{LT&)J&z@XVapNb-N|~pOFd4wx$CTlVlB)-x@PXt zqb&38NfeLc`TL#1uQ{4$)lEey`>O{5^F47rdt|y8bPLLvVHW^3+s&=06#9GCx(rRe zyK1yW<52rsr>-Zb#a+A8=S`+-v6+j(Nq>3QCr$!a^~`Nh#Q z;q9ZD3iuV4u=jerc~7kJ?m~y%<$N@aQ~r|?lP!M|c#E0n-+Gw<$oO^Lp+M>*k4SHv z{`c9@smdL40L7f6*4-I3q_jmz>!+uZ5*{Hg+ueHV$70c5AzpFOyJF|9iIZQ-D#>!h z^u@1*#HN2=0BO__#~DM$1f+T~$sT|LgMbQGg%9`q?%+QJN>0D+6>D~-bYD29?yn!@ zPaJHHmp{Kg>1skTa2Y`B03%RI$)LagoZb^CpvCQ}RM`DbY=SgKyRAiKyEg1B z-uGJDDDUQmjW@W#OWlX{fJ*njjh*Safm&L!tmgYT{f$78Y1P$d&2thi!`hd)sm+a| z(;_1iX45fYv=c0=^`h?UG1t@{&BQ;`!$^nXzk{OJ2SJ1yuzmuHEJ^Hd48SUcQe8u) zEs{htfR1V9rk zLXG?M5$OY9NpI$a^OlVoc@M?C{N|sOxr$9)v94S!|A^u?dr{_>O5?sc$@IwBUu&_) zt4d$p=g*&`eCl9v3vAlnDS5CJ z4W8{WtL$eN=xZZJUWgpbq&Cc6CjoeD`tKtB4%`2kL?180gj=SMum5udX{wuKPrvRSp<&T?F7C+Y)%KQub_f3QT{6$S<@bvb`z| zvR}RRj(Q|ZVkL=5xg7rEJisvK2j_M1vuS}HuvyZ}4G~3o?qs^9tPH$Yu(m#hI(K2x zxbrV(6bNx40=$Exdf5BFhe|-&0gDyTHhMZD%6DJ+DS_IWE;=mAzt2Wo8>fzR0BC4P zZSetqwgfQwf~^GSUw?vG2z z`T$4-QBZJpw1ZPkRPR0mz?)qX7)HS2l!+!g=GrkJ9)Mt-}Z6G|O?F z2MhraLZXy*;0jSXs&^&tH<}?xB-Y}t;4~G)ixDa}%TQ4Jvinh^fhF#}C%cRmQP7Ut($qwe2fkj`_8penlk zxWic(ALyu(2n?$Z0qXw{OlG?A*{XDm49pOUR*or)0qhfOl)&GQ4om>w7mFAu*aZ#c zw8{y?ccR43SE%)>*JOU123Jvet%;>1jP_f|2Lr+4qH2Inn#LS#@zY1AY>3}PEhi>Bs1XTK5?Za$vHvA=C~5Q%upug@CYQ1NdpuUgZBwOyz1Ikbehsp2ZU= z+YGT1Yre}><~k02doV&*wEqV1Bl{A#BHMew4QL%OrN56<*W)1angjBBh`OFndm~G zk`ucfBf$u`?1SeEjhHx_+F)$$5ADe&lFFv-r-Pk?7Iq8N#`p7pO`N}T%q3$XVG34W zL2IW}j6^T7>nuD0Kq4V8%QFnjnO+FD7=%E%<^7I1l6w99^$32pEmo*}!s2D5ZSMLf z)G-^JJRNQN4WlM1{Om6Q_p&nqKR8bM6gRJ52B@-Te)vc*5TnE7FZci7r~Lom8~Hpm38XEmaX#dePOeOFiyZKj0@gKXvRBQe%4*UO1Xg~ymKjQ&$nQ!Gpxh&Q$ zj(o?>b_`rzwjM)?8ir6dr~tGGshXhc=|0t1tyj|eI63E1k4cQLm#g9&p4(%f<#pI? z*OgQ)oK4H5v(K!BiIGu*kP;kGxb^na-!NJL*--$LF8?0M8Rm*Qc;O@7`@F)u`@xd< z7V!+%Ojn}Sf!$zw%_Ov1BiU>j5PKlU_R7zK3d@ZbYm7dJwK|1bD26XwLKH?*hbcbh z-Qh&VY>s}iuB@7cGGO#+kV#>1Ua**?hDw?+8_>eWV>&tzHGs2MMJwVfliM9{!GWx= z{s?_y(yZU858vR)C@tTDTfWmb>=`@ym^$oA5R~@z-6x$^G;vZ%hfl4QU|S4#)>=-5 zF9pseKSNy)OHah|@)H}iEz1ID%>|q^t+ct%TZ_7Li8K9bUe4MuVhL1vnq5*4fe^NFojNOGwR05gR{dcj-~Dt}Hs9}}*)uU>jl}}|Q6X+(NC7E~J8qsZ$@UZqzWsMt#yW%P1 z3UATX#RnV{?yWv_zK$Fo_8#x~Y@j16as5Q<>gxSRW0WaJhCO*$WnaFidF>&V9vh)y zWcZRd(^L}}imr66oa+TlBg{JznR0A|8s7(8iVC}Qo(&IAbiwDUc&y>#XYR3r`|*fcdx#SUMBOl;Z>$4N8^ zmP(E!%1NechDuxvDqpa=W`ZPFTl?miCWG?%#CE!qxNwe#j8i(!Y)_T+(5BUH6|z2V zaWrhPO(HBLZz^$sg1icX0^5Mqw5*om*ZrTQ(_+_|s|q*t@$zdfst2HHi7$=bbT(KYZvQ3(#-X@o06r`^eTP6*F3VHYN*-` zC#tpm^7((&iwF&XFVj#EpbAqA0DjJ-@dc1^y?UA=c2Z{EdjDQoftVj%U`Zp+8xDvC z%>xM+=-faxtReabq$hd&II8im?X zr6=+qStSUzqr6LTIAhKbraE*4p7e6MC|jwL;on% z01%=aAn#(_Xlhzh8_q0_reC9AtWvv+Z5%+|L=@hEW9*mSUfo|Fo6~F}7hSWDu3Ay9 zl-aK{ur-RUU)iW3W6iq~nTE?#MXL$h!}lollXR}iyH9Ts5g}}~9IIlbr3Vy8>b5Fk zjjsA_QtojXFr9Tmon$YCEwv(B5o~$T5<_*{Y3MZ}{Cj-LZtP)`*@&^Q`+AUhCn@tn zM_lBoo2|Z<-aQUIR-f-jilxcI^WDQpuh0=&#$WNX@*KwDdMo_SqDvuct=cz;faLC3Ff*LI!SEP1gLZUy?JdLb1*enIo#+bd6$Rnfzax@`eTFB^I9bg~i+oZ2&Ug=imIw~` zIqDm_COYquf9r*1hwMyr=3=U0(sT#qKqGSV+1ApZUy8$<`uv3=Q?NuP@g^(RhGz2S zr%tJc8b2RgEhcI$prvrd>wHS+ME#}y4}0$!*5tOX3){g0h)9vDG64-u1VQPFfYOnK zKxhKeoAerjQw0qID$;umgeJWwDn_K27?2tS0UA%u|gGWT9*opbh@bIt4f_5E1C z^a3=4G463c?S7uYC1rh;#Yu5bW-{C_M5+jumGvzH+PP&>(ZNU6x?0QRc&_`$sjv19xc0#7L{);4V4om+!Wjs zv222GKOH}PFDjs3_tHi&d9;&&fWgOVU4FFKEbh|TWZGAQ&&9Mu|1ZoGd) z^{O&K2zIyrdgp>eT8kxsOkeYX604g<7EQ9s_T3q^@Ff2I`J%0i95twePSX1@zmaMe z2#;YP-F!HrFR^TFcAR>8NC`~+Lh1>`v1GQj4s9v9QIW*iegx5cm{aNsq&x7rYTwUO zMk2GJGBR4_3RKF+w!|I)f!)o%pFn>fC%it#x?0$D5cw{|s=v&EH`NWT^>3X%F{XY;tmqs>*uqv88eQx$9 zwc_>Ez<%h4)BFe}s_}FwIbx5x-YFnio<8Qkry?-cxghIQia-pdkV^nn<$d#wZbg4* z$&~9~^y+^FTOvp=8@X*bi{w41y7Fn{$cZnaqhW|5U&#$G^#VT7j`9{@_8qq4WH|da z>4TJRsO~OSdX1qVSILmf?i0PWZ}EAUUj5f&IxjAtItGu>L0s5bp>d?!fJ0SXStgX# z^0R$L@Ty@uRth2=pbN65anK%lkQKri|_LaF7a7Sf#n6UKa80X;kdJa?4vk z3vBxuGPI65?dtl`ah2HZ&v_Kx;~dwKhIpG&w|gBn_-nU`?V(M}`;^TK!CNtbJ<^qZ zO&;~oP1RkskuI;G_7(0ilwx1%Mm152cd@DKS+E@V$Ecj&HQPbIlM222sVAUKfeTYh zruguqHhx2JN#%`iZPpZy;Tx_IcaJ{4pr_so#rNZDyuw#&yG~tIaTvD=a(GpX?d>5H zjHyi8Vj9YGTxa?6o#H}U(kmr?-ZVHip#dtbc$9TFmUx`F|Ux<>sWy*sCR)h)T?r)Oz@r z%sNKFZTMvFRpEr?N{5FL{md_4yr^MSS}*wcRz%m)26c9r%t4R!Al4P&4dZ0@^X`W; zScYQD`+6=obM1{ZZVx!L8nC?Qx^@^SQ0(4pwrZ!y5OwX_5p&z)o5XYln+tXrH+wee zF($pvR-i!@HaYtF6h+DkGpbrMhQdU_L)0GLdA`EXpCMZX3M}nPSk{kqdDCg8)nrxTk+KQL0XG0v8khg(`Sebp$)_415L;7>trk9gN3GB(;wEYKIz;!I0O~2)H z;04wuZdE`EPxa+XW4(v`ZPM$u3y)+@}8_>VenQ7O%=)OOwsyOlOwh0wio}D`{B(vnw@pgnF-LYJ`Ta4YY zY7B{iq_ksBu)Lq`NgG=%gap9kyq3-kgob&1yE$(e(z?rE3rjlTx@0q0l6Qiq1_Ze? zMs^$Ode(u@u-%p&a24BDSu`kf{zl88rH8}rYaP{wY2rLX-~~Ed9B@X>gV>49%o_AN z`LfI#a}#l8v#W4~64|-qoD3mNE}u}{-fA!_vRnkQQ%#fW;mt#gu%fzU16UGWa0Lwi zSTh%_lR@vLlXliTs*oq&5K8)!1 zc`+4zYuj%eBK0F7fEd*uQ{mTLRxh`SK9BlXIIJC~0Qtx|8da;h)vWmxXb`J)ogAs2 zFNMDZ<}d*!?5bAC$8!ASLK6(|kULMk`%XkPwPu|(Nt80T$7-0bUr&)L-l!i9CPt z)+9Ge0V~4g-G*{6<_!ME{4jT(F|k3i#8*ESno z4@kryT!U%*&F{z8Z%v58*J>d$J(JnPi7KI{x9q}Wt*{%L&4bm~)6|q`X4_6-N5JJo z=&lzq9qJuqK)>zvn#cV{ZlJA?M0skRgi+chzoNHnhHQqKGeSSyxJTNhlf?ZJzaebS zZFo7~VOU&jWLW%$>5C2j>nfXz#>JweU~z=64C5>{1~1)i#l&Wwevg`fJ7Awn8>)LS%(+ zFalBm_Ty8v%a#Po{C6ym$7oUJ_)uvM^|+7TJ)IJnu+0%}1Ao@CMUx7H?r(-65)&04 z4`<}+r5P;aKZ4CWypBkZ${DTgx5uZuZ2G00kY73*T~69`*RTmQ;qGZ@F?Be-Y_Bkk z53^Ugu!pf{b?)7{?|kx^!7r;fYFfg~4@40c8+EqX(|%ZrS?HzioS7Z_-RJ_-gtza zfZeFEJ5%g8xG+CUYF9J%zxqi-Gdic!KxN}oXYkF(M5~QM&~E9d`Y^>yjBXw=CJ@?@4mM#61ixvQc`hORHiHaxNh#p2SehRxMGxNMwuGJR zSW1K(i?(Ho=F+ecNPw(@$_s>?I795dVm`_I?r!|DkYA^W)d;6*(ABFsfEM4l`&cX; z`Opsh_9`3BEIdMJ>;>s62*OD$`DMX#*Ue?;l1;;A-vlH0{R6A3caBBzzt?sM>SAUQ z$b5b>de!I*XWf^@qvDij%ubrMY0PnVqe(L5U5Pc!(gJUv8zYf0_UvfVl}{|1;s~gz zW%xqPvS}J;_4>wxV?}m$&wi^TI&SDd>c8)^C=fHtu?sc{{szjsQ=OH#&pWK=e{?^7 z^%!g^j5}Kp=crMWfmoYOaJx9<;t_#Xq2RW8H4(yR`R1i#y(m_79g(RP7e(hKF(_{q z?dbkK<0zK$V^c7`Y$P!X&Z>NwjT?tCxaoQ?{+iB`aI9G3)!$tz_0Ak088l^mx?DeO zKt21GK$54Zyddj@RwNNK5H2CgCCOZpD+|V3pcO0j$yfF?nty#h!jXXKEW2?S-5_*# z^~UJl$m7tb)%K;H?9Q(uylQsJ`CAyC37Vb_)Vj{szTT>NidJAK2Mc*UX{q~7owG~pwN#|91V|}?48_%@hI)`I-yH?xROLI4gvva#t@))39#T@Eg=RMh zB39`P-8A=x@XDb0LvH>N=vJ)sGL%-TQe$3UGPmfIKiKSeXr*)DKFLXi)R!K|Z{Y~c+};Z2{Z zDJv85h^Sz1$)1s4PwD0E6C?dDWiIijjc`xPu-6dwTT}h^ z8*zjuNuew7D{MQTyMxpPIjYEIsM&nzPFzE3JaQ>x`>-$IVIV4s?H^0nV(31wlDxR!PAFY{F zCWOf@V7I3NKM3H7AbH1+J>Z4>O};u=&_~YY2#wg{V^iq1cev}bojNiH;M<<$9&4R{rilo}Rx$+-8+iSDX{WK^Ol4dM3?&x+DTp90k(}yG}f1haW(ild>sj-{AeC$-i z!|Of2lwMot|0n`oJFE*9<-fkUqZ63tV?%9z(0v8^2I*3}VuP!ywT|Ks4=c#EDkDz0 zRlOeSsb}qj#=JLt7M=^=9B6l0eVw;XSu^y%iB2}Q#_nbg4~E{;Jpw-6t>!iAL=gZD zn^ZCqTLL~;f|-i!l81`!KqoRgROAHdT61xLZ$j|irMf@^of-wKbPzl2Jx39UN&S%|S$A2z^J z{R2DnHS%x?FrK6%lO~V}MVR@lY2u}n+#zn2jwpR8b;1&|;KD%E1Vu$6>m1vMncG1F zc11-_nS3dTQo%vAnW(jp;95}A#nW#!OIQQmiSJ6NK76w|mQmN6M0$aMt@m%X5E)lb z7b>Tar6LEApo_JzGfLcSq&!U{DZ!!od`>0U~Z>MEx(AJ!BHHkG-dEmrwfmSCH+Wtxw1tI~Az-}WSBB`nX5uy?pvG2c)9)2U*5~EL1bpvR)1{e&y9i&9@Y?y> zo5PhcCb3F2=RB`473GfhR<^MgHKvV45##sQ>q#5IvqpWSJmNiVhc+fHxAIZL?r66k zQ?_E@JCbE5jr@n;mA3#~Tm<P8sQ$7v}gGkU>ae>X5FeEvn!!f zZ^HIt$2{IZcS>r>bA|rk2(;v|?ya*;+i_Jnn!_2_YMlLTx+sL?;n72o#zj~eaqzMc z&zS1U*Q4SZA0~tQ=nL!O6)!u?6ADV-4r-C+$t8@JWPNbBc%*=2R1GYI&EX@NDq(YM&+i`4pi zRGwC`|3RYvn^u!U4%igE_d(6T``GErXE+I=j;Y0=)lRKV>t8K>dncEw*dHJ-b)lbX z_mmr@4kR8T?5xe0oC%eiTMk@D-W3*vS3L+W4kVl7-lY8$blwcuQ;_$OAf6Qq-MuSv(85lkzfQzjc*bmA$- z_erH2QXQy-qhJRVkIwo$U+LJR*7YbKL|5Cr1feOf&1!!<8)9{0-Bo|GUT*KKxaO5B zk-zg(KXp;%F&oRAgNfMP;P~Z)k`LW@ua&T%R?*Y%RF(ICRwv}F!#J*iJT4>ne#9ye zLzJ+rUmgv&`Hs9!(B!$sb%l*;3ivIn2;+}v)9ACrTikmxS&;JYCW5^Zm@IZvm+}O0 z@7lSYMQ7`B zwa=iwkJE3|nUwrD1{*<>UV-C^l9=z8Ynze{#i3%Lm8(5cmN#ZvDQaI??0x*zYb|A@ z!sCT4VKwWubsJt)$WUDaOYe%IDkX>8bp_Qqu6ebaf`h>5L2ynwiad^!ve+7BZ-2mQ zq+dQdVntDYo$F&(vo*ADyUkdn($?wq{MjI4#n?LS!M=wx$;(-HpQ~t|c=^_A#J@7; z|Bb`KkS9_C*~o{u4yW`i>!7uSmj;_l@Q`^pBuDDfoZwW_u;d>A z>q>fhWvw-K(G2$ zSmcIJ!lBLj!xhHMWhohy^ z_q}F0t0JZcIi9DC@&X4&>ukHM`ewqZw|7Nh-~`K_!RY3^T1t^&e3}u)lQQOplC$Aj zE%WSwvvodcuCtV$U3{j^HX+@k>|3#D1yxOo`sCpe0h0ImR6L)bRCUp%W*y$h|5F^Q zgPiRg9%YYONpno|PfWI~rqg;u@d;3?v_9Hwp<2l?y|n6*$$M*K+zDH(w;obDmlDfu z%yUu{1iU3?4-xV~KAPN}3HWJpnvLgrb&FHa1Y(SK0Ii}e+Rz!@_zp>`#YNLA2%#=M zXEO2ftVb|VX81F6du{8K-qv9>GstqU9sAR1wVhP@X2{&FR@6!M4tOm>TJW6KjaRTT z#m7eBQxJ;`_{FgmqRfpjh~1_z7-cV&<=X^>vb!r zi)*Z+e9zcCd()A4G%o#-NLf*s??enk$M{CRX|#@pF~RNuVw8nlVImA07t{4M!IdMXVs0thmeQv`d_?W$M~dM zksoiMR54U8ddtJd_W61z`^v42ab4FFzjD2Ndu2jRQF#} z&}<}`@-ZswwU^V!tSdIKYAH*0Xa0H=dEs{jY{ffd-?7z#PX36$D-*#xCFkcFBy;a5L{d2~7tn}>G z*g79?^MO;QS--eef3MP`;$Mar|HViq^&if2W`op<%F6EzjJtrKl~>qwP28vhUM&fk z@O@kh^1kx3=>9tcbrY`Dz*Mpw%kZ0+`SP)XOce&@BE}3eGn}B^J~kQ zkke>SL)8oxRO0dLNG`TjsI?3AyoS7H?W>guv1igq+cGo|Fl}CNO233qw{l1A*78pl zL7t#n!k+bKcAYu!;5S!ah^;eC;r5E|a&oG}MghmIhB@GdLW@hqPoN_^S^+5t`iHM>y$Kmsp(u^B48j zT{mK}7noTAboS{_KF=zxcZ7wHh@_DW;ul(-(j;+>i1`eOW7pm9F#iUMTux^3C0K@v zDpjDe=(MnaTk4PiP8BLQS;m0Sq%}b z+EV5s%@PL-_d5PF(MT0Oy5F+h&~G-O+e;~qo*(_sL%v>qVO+zrxK1O|4PcLc93LF_ z?Mrc_HhnTYgX4J;=PUpq$VNDxPm46l=c%tS=@U8`HFT_KG}Oku!g%t>pqfm&%b92% z%BHqZD2NTkSzS`H#!198lhVVMp6S?By6cvAT%O|TYKJ>~S;90^_S@Epaf_jz68OPw z{S!r<^Hq(DP@K11V+E_y#jQ>dTU}v{5W{?Q{)4bj#dOPE$k%v-th3IqLOsVryUNC~ z9ml_wcOChnFdi0)*&VWQe~W1y^r6xc$2IIeP6swva~3I1n*j`+U}`4nQ9UcYZeP09 zCp_{VGjFqr3LD}zPj+vU0CSZ!y0wOpox8}o)cPDrY|cP^;-2K$t^^D1eaQ!t<&?jI zYQ+ImcS%Igd-W_>B{jZyKG)Kl4(w-MM%=4mj=Za$FS0xnr*#0cB15Rqe;5YOh2PzAiTkMGrrIs7 zwv+Wu({%&}I2prC@*HE#l5G&Q!PAQ`+7=UuyZvT4Fk$ z3y5)t@9b^#Rip1Xf$zvZ#nkJJ`sE2J3>R#g*X?DFP=14ffytK|+I3=?A@UjUNg*IS zrvwiR)R&vzKv~8V3Lgc}(h+XY9q^1XAG{-*^qmy;-d96_j5m}VJ*!%WD;hbv8=`eg zsZWvoRwr8u{YLYOD9l^PMK=P?AMuJ5khmmx{&s`&n$;`vBa6`kvSZY_SB^wd16zk= zKC6TipT_EWS40mbo&r}|-@1A85tdkJQH_308K)U_>j3Hv-$gYq>>hm0kV;c)yrj|f zk<=PaOY3}Gg}`pl`E_AezA7}1^^WD^xU7o4hs|zn8GGgD#i|K2EGrH{wE1;!sdFYQ zvG#VnzClm^#6fB;gr zZ%w^0lhZsjx0A=(No;?*W75}j4IxBu4d{)OC?Q-E(7eNKN{JH=6+N%8MxoF9^QHsdm*-Q#BX$N*g$hL8c!Z$hBeGoR+{9bc6&lR#jE?awR8xY` z2}ATJNN{oyj!EKecr$*8kcOt-`u%1o+)7`R>!xDKHItHQBk(mvT8pm98I{_l>$>?x zpTL5=75wt(Nn`fc$c6Y*Mz}q^0Z%Hl3`qeZu*WY+a=$<7Vd1=B8<(jPl8>w25FqB{ zW(4=*f+Mb~YHPkN(t9v*8O#Ienzr?;S(ni~R9w`=F-)~(T29&B%-m6qnzz-?NS}mL z=wW=bkMB}%hf+U=V;&OJX8Ug+liKZ7fyRs2eedPL$c`%0=X$Yf@wEMfijDinPvtd@ zCf5`1cS*GF{6-f#l6+9-ck+MpEA&Ci+Riw(rv7rKS}}D_TFhDF^t^_l%bza{`_#;>a8tWG_BIX}m55_z z#RZlQQBcZvJ^2kRfLB>WmTD>xCNqIQW1GocPdy1(^W)}wD>$-E4f7cRAnAC61{EwX z54rN8nX&P(X$gs)9lH|A+O76(|D}%m8XrfQ^iJQ;G5#^!;y&pJy z{l3HJ+IwsFXLZ+nOBln0Ox6tz*N6_U|LOH41Ypw5Ht|1m4uM?EH_2<7$BQnf`%LAu z7qWeUCub!vM=xQz{5;dt5&BVw#U7k_s`zi4P38`(gRl(TC!Y;+=+(2 z8)FiBrQ4nv79djkfPO8+k}HHa3r+9nsSyrf)PA8)fxbjHxG_Mx*9j4oNJGOog5OP zGrK`Nnqz@+0)t03DAHUNE&Ka##Rs3pDJLRgPZ?S4FV1ruKh=4us-e)})=Gcp_1UPM z$~Vl$ny+(se6AmPjB?PRaDGIY74l~z`v^G&%$GPx?R(BibgEY{q$S{qF(@v$k ze;PPqv7Dj&dfyL6+<;7{M!){xUfuhk_2o-d#ylo!upr4M!!QoB+)CT#VA1Bv=>ll7 z+DDRQ(zjiX5w>AaQ?__=7UbzxL4A5&!#2UfGHu>E$UFoH|3L9d*VQ@sB%^-jcA7pL z?wl99^VrGZb`#HbxigR#s-gcmCj7@LgeROZ2)%LrGHh>?VTfqQFRa6)habZl{aqt?ZqgSuTx7f}w*W3D*p| z-P|HTy*+>vjNaqoq`7!DbeM&I?VmAu=9r6XbVtr!ucb0F!!`{ zGShWy8kw{}EmhP!(`r(~eEPFdD1nV5PHi^OJRzGg7p>Xw>kp?c?8B$4cW%Y0tm*Av z!!S?mDW1+RU0>!z>d$c|#H#-2?mRljY^It0D0U=tek^Qr4Yl5>hdTve(gB9=WK*JT zWr%BDE2O=WHAQ#6(~xFAPd&(sL|(C!(2rL+BS`(E>#~zUG5zFNNnAVx(Tiq^Z_o5I zoxN!XdzOFM%=iqPhb<}Zxu$=_ViTWNkC5`0yu2nqoq+Pm<)Hgv z=4VkwRUEcu%(CaY)y6;A(TZO`io;Hw>)fu%le^}-09dmH}8;ibP zn5_V7$%=+>;G}^kvivVQ4-WxxXN(pm86u(xzXQqrrE8g`>qNgX<@Kg@MjpTP@E|?{>;r$>@cyOKaaMT*{oF7vY=Uw33w%_dr1_h_D#PF21s zIaJIk2%1Z znV0H#veb@!fueD6$~63#wcW2;Gx<-vKxz!qjc&p0433?}H_akAX`$D%Q^KMK0ZjHxkfuV8Ph;E$&pf z@gW`2&ACdP&_WWbqL#H+2U1x1QN{Cu;}j!FJ~S6+_qWWhxL0)EdFj# zTHhzAR~J+(V&h{YI%_I%s+ zbl3>wn1TJ3ru(%!%Sd7t@JA2t^`QFB$H}t}Szkf4j10(*Te-)6Gz;ElKfo&7nsgx> zNw1$j2uYdSC%uPT6CRqE*_S{@+0%vTE(^Q%AGMgL4VAKL+P&@3th@@0OYJEnn734vOU2_V&8 z^zp4<1HzK&kZt5C5c}fIizWR=;_95FFO56xTMWIn>Zm#b`~~tp5#};d(-BD;K2wR? zjdyD!H%Zg!qiLznI1H3*f88y?J>4gHHu&crGCn41cdsJIng3&CU0u=CMp8+I*Y$3g zyLjCNHmkg*As|aQg%WHC*lLWfQjM5WdfC{doU8BtCa{ z@Sw`-)npn0a{SzHji8Qg-N2gss98HfnupAwX$pXIG&@TIJ_~-=A=RzCSp=IIeW@D> zj~b&?ffPt(^tNx}r;TgtaKVk6>m{IJpUUvC_PR0GY9Q=qbco|VZ-xMBhGy@+rfIaB zI0SD8t7#zOR^J&*N<`A4hsL*(`_ezFEjLQn5sH5GVyint6&!QA7BAYSHy@6ccvm-S zH}ewBTdM#B1ekR+X%I`^Gn|ZxEwb~Sk*r6#RnyFC=v6<|=DW~WAoX(?CIQZdXu76m z-Hs|aN;_|ThIP#IjVH!G2zkh@#)nW7c1N6XA>`ZDgiDmVNxS%##p$2&?3V~wM@m`| zFJ!{**JPI0`^md)8;MEL#P2-liZH;-4CdQ^lo57ihwAdqol+dV05bXN~;U%+Pw@(p39%e{7PNRJR|=1u6ZrOU;1 zd;+uYCpSVXzF`sARL&6BGCq86)17CPs=L4P0M@~%BHnjr6FMs9!@!EO>o|k74 zx)QxCgQTgCcM*G6G_xEj+xr`vU1Tc(c-ZVR{f8kG64@~xTEFZTd916;@IJXs7SpxH zH==UdPAl0h@o~PH{0$&W$HR*1m54T3}MFF zrA*fXc@_^ki{!RiBlb8lG|+9I>m~N^OnsH9!xuZO^~rysWcf$&%k#-qRrMSGS(&>+ zR?jTT8&~FP0_3|NmOV7xocc$Ghpcy|ubL(`HiWg`?q4|K)j~Bj^xj#o+ zRO`qZmkGnlY_k>yjby8eMBSRb5&& z=`EI#0gZoEyFFnaLhGA42s!e^*Nq9oX!p-ifjWY>KNTOKV;_=^o^)^h=V z5tGpiq!0UAgm*x7M7rV{#9jWA?1odDtbbqR3!0Z{FzELiGQT|la?zxswrx^>&f#c! z2;K3x9Z&a+fvOUGdt^RX+wR4Of@-%MgnY|*l1*5O7G}pMWHDu4Jj3$wlYN)0iNK<; z?MQVfM}x=C#MMZZXxqVD9h;g4Z9(6i!_>2BRy}!=?V)QzjJIs9w8avJzR;t#DXoK$ z>cN>OMgFlLg0Tz}-nH-X2^pHlYlYeP#@#tTb^bp2=U8Gso7{QqSW#gW$LMI=1-0-n z#o1S<2gS|(bMDs$&o86}Oon$kMp4tgHO=W?IO2u5Au5mtc|zU9uf;E|qDxBO$&c-z ziY@9r<1Ksjj+j(`_}FGp1fCO*^-U6})6tc}IIj(meme#b){I=xS7ZIeEnw6IFEv8mn~s)zfE5_M{^yyOLr+d{p3Qdc=fI~->?-rA z9*B!{0w;VC$g}#!&zir$(VX7H{pk$ZR?@C z(}fC{Q(YxFUR=7}r$~7#w_n}&AWl%WpdgXwb$ClJughFYXs!Fv#Kp5u)U4JhEy#o9 zo59l)Bc`jvHpaE4_hAzT>6WY?mxfP)Bw!#;l>`~2WHj$^Q(VWo_|sbI$6BHf*0Of`!w-&s9^5~_ z{r~jnuX|(lAE^J!EB^m4R)2C;RDEl)D6n}w z*yrzArNS#usJlJ#nw!uFSL987#ryyI`2TMTdf0gmV6v$V2snFDVOT<-#Ubsltnxo^ zT6W$styXF{26$v7_8dJ#=?GZhjH~be{h$BI0v0b`REIEq`<{OYlJU?Z@o$kF(>`~RWaQ~27Jlx$ns3R_wbpp<4c2VCp|663yf8fh6`VC<_4iUB##?yPT zQ`2&;-+plkSYgBA_<%9bgdvN-GA>E4OaI>Y0*=xo`j4CaQ-M7j`Qh6>6F;n2j!;h? zUtoHA!ZD%H^d5b;$EsM4Goe^3CPcVIZ|mMJWwm+m*MQg0Q{rVccX)lKFe6oPQoddF z-y$qtUBEdsn9r*|3YO6$?$d}jHd%3FlOww0uktqk44Cx%0SDP%u^tNGa#WLQ13}GtD z>;lg7Iv++FZD>Uw?ppLY&$qt^4dz7aN-2u5@Vs}n+LkGf3Ey4V@teEFjRKU3WmVtP zeK+s>_Nh3f2Bf;+`MfX*bhX0kUUSwecz7cD<~mg*|%_IOq#AVE*PH)Vk8S=-XCLiNH z7QR?`_Hi$aK!U(?pvv)Sk<*Sa2Hj{+wBD>hf#ga=cc(%+fFys5yFR(}K*&{=Q(R+j9+D0NrM zm|#`id$tK&>YvRjk5|3$9RDz1!+m zl=`2u|Q5w3YL3Wj-FF$PfjY+SJo7UO>l8C4ZABxP>oR_VTjiLSQYQ>+Fs zqZ7Im>Wt|cam)~5Q3)d7U)fJ3dEW0+Vc2214X{-I#R2=mmx*x^gf?M8!#I_Fy%4wV zG3s9MZchf6wex;WXQ#MM8`}v9`Hz z)s6Af3mBSEFUo6oBP*ZnON?&ZtDwsZ%twGy*cJyT}Yiz6Dw17CZv+M z$JTWI2B=;Cxcf7JA{kJQ$F$5-#{JzgVjq5TRB}_RWwq=3s38t1h*b?^q#pDn5K^~4 zGR+KDie)AoPgX6xp~QB_qmlZ><&8u?xMaeIwCV?!&wpqxu(rJBkX| z8&SGzHOt@`ydiOsC62LF?YDQ|38g?xHS!0^U+a>PMOmwa<^w8e!f(!gtB0FWw;aj% zM?w^p)qA@$vrvT;`OvJ%gKnW}S8xT&P)#7KFZ%J|YkHtzb@zBll{+9{yj0Ss%23YY zzFpL(#<(om+HNNPpRRj0+;RiTuui3tUV}>!A2pMpb=VP6HT{zE^|H=gplwsn(s2QYmsX&f7ch(mKu3&a z_@~V0t>0$$#NL8!3P)a+i1ppuSzBOBvPuwy?-hrI^J{lY1DaV*e0bGls!L317Eox? z$J{$M(0h}Xt8B)}5xzZBJIDs*OYYnFi%!M=4UB`F8ew5+SV_Hhqdc@AN=WccZ};!| z;tq#VAvHhR$T~EE$M<+Q=}#8E+p|`*ONlo3@a#+7xkvB-gn5r_^FB8>%Z?PNGPJ%go_Lk12&1;D;L$QmHr>-Y5DsWW#DZLCX>a6GK{s#$`qnL z=)u|FY+(s+GT0qLcIlrtX!^wlEsWAu&a6-fs>m2@F=qyv##X`4igG*k>H^!Wnruy=({feiyEZ0vcOSb;B zyO9(+(<4KD{}k_dwNxa@Oin+Er^$r&RFjw2zGOpY+Ep1`E&f7R;N}x;3h5kjs_aA39gp9Cx6g#W48+dByD(s zzzOJu5b529=~G?#W%b|l2Pfd$LW!!hy^YTK#Fmr_hO$eRN@`@8b@0}f->?b=)m{Y; z-x<*E@hntK2A8Y*f50>sVto6|eJ66W2&7@lhA*EltKWc|zFB-`&stvj`PqFYK_B-? zM%@Z(geC3vpP$!1yyfIOe?&Rcio)uUXX&}8AmEok9|<&yzo)@_W_{7r7>*YFQOdgT z$VHe6veoz5L*T|_uHhnY0eNpu7$;PU1T_UqlEx6O?-$yl13IVID zucEkQ;&iMiw_1tZ1P$5w!S2$Z4bV;=8~OD!C0y z$%YSMF6FnJ3@4iVlKaF#O0_rCAuIDT+WbZ%HvgYieH_rgeM_|P%K8#RyC(ES8l+W= z%0PU?E&P63x&v*#r3YnfRk4=15=K>3wm;*kkAo{G12L_4V193oi#5Kq@Du=A(S8ht zrSvF_U9%BW<@X<7SO7#pKksqkPi;yhgRedkRSOD|n)bl^A9^CZ4cUgz#P{*8#jl^HMt>I*OKX8>vwjOsf` z_NYk7T~0}mu|WFsqEW?kVmQr-fLdt~mjogRzqt!yb-_x(PNQpm2P7_qT~7@=O`l&* z+Me)jzwf!+5Z`OSfW!ST-ChTx3&&#I24&cq(f3Ew1CbH-bZao1T=u|M$-W(vCK$Z= zvgX^{=z@a_U_MtPE3GGN6LyOc_U#7^=)ejA&vANbVOD(lHw5G#eQJDh zQc~a(d6$oo;JG`G-S7xQOo0ygzKaND_-@@$C=|;Ikl~dEqcDGFq9p;zsoHp zn}~00kJv}ak(J>aeK@t5_P9O}B;(CwFr_tYFmBjFmi{Y>*hjSSUG7;J8Y6cS838DU zg0V;`8;}PvxH+4?xe`jA@2a_>eq(OAG)vp?my`RIPsX|ub@wnm(^;r2fs|fV%G*8r zGxviw-_vE|PF`GQF?v2zRzH!F8NBj*Jox!+A}AmY`-R%DHaE6Ta$7Dv1${Q!DH&m>YKY#mgWLNY~{^36BW&mopwx9!h@m@H#tIcrj7NC21v&cjgN@hE$ zaIpkLcsq3E5?XwJH%|GT$!72YX&m%a9oRZ#Kfa_QMhA!ia?gbU4W~a)cCArD!OB*E z3Ln?5eDVD4EM{{RwRPNqjTubyYR%}2o9bhaTDAa^ECdulbu~PKUQ>b4-V(5W+VLd2 z$qe(yq^IsXpL2nG&Ph^R{}sPLN!n}t{_R<~RHd`3+|-NqOdU2=z>!nsGIQ&>?Lzk- zDv}rjG^mZ!Q1{K%rxb(gUPWC88W#H#*>VS}m+X+3f(N<=in|Y__zSCf2E}2MJ{wsm zud)Wq*=mKq!FXCg%?^zpp^6>><8mwm>G}(Mr=<+?w6Vr|=$3LIJX+|+85!aN9%CVqY&E`(UWFX)-tYDo6``Xm(0<+5-#9CxaITv6F7w5<%+o?6i* zS^a3#H97|GXP#Z+3;-p8c42JXBgtd%@@YvUcU6JVY4e3GV~%nZb4teJ%|D1KEWGi$ zsh(MAk5K;B5Y^Vf%IkkPQU7y0Vt^tv1XX>|QG(P!+R`K0u(B$&@vm}He6CWFvwZI$ zd5YV~ZPA*d)KTV3=wA=PHU~KjxnenppK@ds>3^~JmQitS+1hZZ0|^qri4feXumlSZ z!JUFC+!7pu6WoJCfZ)NMD%>?lf(CcD;O_3L$TD7Ez%*>sxiWN&r=}WP9FWHsSQJIgB5&3+b88Gg6k_x*ZG~eLAe~ z>}qTYoJW#Ka_p=DpVaJqIz-Gk%v5&pFA!@U`O_aP7Cn{_?cZ*J_4PnL)hC}?&+$2! zDc0w9___Y&RQyZF5*3~8>+igwoCJ{JnsN>NFcI| zJt9S4@THgcx`n%Ag5iHGh5aA$Gd{(*K$izFn9(#@V z_xsi4Lx6u3?)XYencrc+5s*XqRH632W?O#Sn3r@wGRo`gvMdHPn!WCBT#K)N15f7v zyyZVD_8%Gh-w~+)Kl<`FgdqTW1+m?&3XN?n^SdlR`t@br#t55^L4m2duseRL>Cd5b z*#B*%|A(KL{x0C?n_RX8IJxb&#;zYS^ULeF-iV%D7+f55o!#caJ3M8dsTEgJsz(0r zI|xwYDA9rZ)oidy>6i&3TjLH#n!f|E?>36Q#-r#4N!8> z6$pOhT(JwmCT?LO&k7`yF$k2 zbT-XWRzs&SJh~4jB_h@IDo^&wU7njw;>AEt@Hz*{#-4_&1W&q{TLmu*B9Ql#Qk8{Z zP9r(lKfup&!ONvX@^?^aFR)swq+O2G7t>BG`Btv43n2KwI=X_aV~f% z^-6^SNf7SnsowwLQU5fEzj7wVRDfq7#{J?#=zotAfwu@Ee$zl8RY`Yt<_McaabjP!dq)9m$!t|2Id`{#usb zQ>DZ}hq4b&^b_4p3b=n4C}B0*pYJwRF@W}Cnpu{{d^aihmhZ+$+Yd}bRpt+-Fg{#g{}>w_Icx38`tH-b!97V>)oMO@5Tj&uq;ER+iy)< z%O`TN%8ke5Z%*q!PDNT~su{-fUthRjRT#g-x`U_H34#HauvE@FAc`8Ua;HyecH2L@ z(LQQCoOPY_6VRe9D4G0DbNIpSDbO#9dUS4F#Z5Q3aON9CV7KnJ_Q_)!MI1qJQAeHF8E^q9(C?E{Gw|Y{RPcZH%W9Lq!*NobdGh$})^KQ-jV!m>J-+-V8btC& zF1CBbkhq==u$?5G4gyWlfqq__0Leoo9w2oMcFx6DAN1PxHGb80af3hSIjJAc5I-&d zU2ywdK*)|Wj5j5+BS z6)3V$mBW7e?Bgn{WwuJYdz5nzrzbXm{Z8fU6=)33et zEiw6}Yn#p3Q1z}M#Nc9Vw(qA|b-lkfae`R=rS%5Sri@96J1c^KMi2LeE1AY>hna_7 zyIcH&+51fVM)CDyp9?Udzg2m9amT1VQ(*dBcVon@)^)9M+?{wz3hN}WN_J9u;&^|J zes^hA@4{jz8?7u?$vY-7Z{?h>NOfjz*O0^dQOnW5M9J8J$tF8&w&>rrp!+*^39h2c z0GWl~Gy`X#gRh3B+eX1_y`laLxk4~8K|XMj-q>LFcZ0y#oAr&OQQ#&6nS17t8_t`< z*)sh(jKH9XZDug8n(#zv3>2&=Qo1|Q8PAxxRgPo8C<#%BVVF2&oEY=ptGvBhnU3RG zoj&G!VtFn%<6?N;lgO1~JIj8WynBA#n>=I(iDc4J-e+7W0O=q-5Lx9t{y9pt)6S?C|hgX9J5R6gy$)GZH&1q6YOqqq+uXIKU7Q4 zIqTWYy{TQFX+{bOyJF3CmoTB14DztP87%rHmoUO|YZmBYaua7dfVZMV){&v7n4X}^_T@PtU4K)0l@A{g4{vPDu=-J{bOEBdq< z#7kLQeJMHas15PeI-p`K6T$T>db74{ z{*CdT!<5O5bKm(v18oIFI67!)@C0J3)_tl(dU(ARLTl0zkyO6EhZc6;b{wy8*-D5i zc<;`iU%j{zN1)uY)!v~?VTRZ6kd3BGIOFXs;;H3XbRL`K58PVkV}Z%CT~8|QwI84; za$)Cl)2pV#(w&9Yu3^hPy5BdYExQb6ruqBK0QXO28POFk)&98trnoVjlliDo3p=^s z{^OS!t*|&2!_>=z<#6q+@eKS^1rQh}Xt#0n>^a-VL=wdJ>vKBWY?*SsF%mxIZ*O$M zlZ(m+v^uG1P?SXAZ0s*jzv1tc10B)b$WUc|P@Pb~o%W=_8}Bb^NxH?T4~??tPLs(` z#9DL2XT)=~j+_Dt-AC{PuB1`OZEh0u&9cqYi+L~Ow{WAuBOKp4?UlRwb2URXV0M3PEa8qEmPOcbZo1B z;#u_uZ;Z-HMvJ>na&gRPfNfh~pLm6Cjqhn*!qJpP6`h4>ALK|P`SYOPoMQt+vSJe# zKaFjJS+gBOFU#tSu@8Rj!XOmvdw2QRu}^RO)eGQne_zdmid*k#y3t)^d^q|t<}`=A zo=$dS_-!Pw^#R+XXZ+fePu31e47xT5%dM7;h8i;qrtCXUI11tw0(C|8ljlaw$7RYI zHOabm%iW?$n66SSHhGLQ@fAwmbNtXmF?g0iEs2XSQk`m6=-$1Kd*2pjPJgUahRnHyP{S*RA5K zbyEn*+%C06o$FGK9N$r5&B|?kM z;+$k=*SCE)vWc-!wSM&>`=w*Z^EMiZ!DxOKUX^54mlO4&##;Z8^v0VsdsdFliyb?X ztg2js!BubJC;S5rHD`k4UNI)4NH0r)-{GpsGl5xF*oF! z7@)V2b@R#C2NVb1qW_4;ZF72>3c53P+(V53dxOOgbybx*wLBiLd}_&9;tuZeHe{RlE(6M z{_wurwihBDo!s|T*6ci^mt(S}XCwlu&f}^`zwBshR6mWvOo(nh$R1|Iz-lE|``FM_u z*4=`e@7p8yi@EZ<6VeNX^)}b{{FWc&e@QOj{P?S%=yr9$@+!>5TpGt+jWWbLek zu{6n+lxI7U1_8K6>QLxU4BYiGNAi%TlR zl=j3?@(?&Jkvm_N;KKLZcRvvuxX@N%s0n6qiin5~1!CO}U;>vidksc!hASGEs|R=t zA|7wG(yLd;Ia^;n2Nx^omD1)J1uaF9q$ES4lA1Kh&#L(pw~Bs!3(hpTV0$0MUVmy8 z0a(Il4u+o##Wsm`7)Tjr@!1xs>D{a77YEgxjUV*Qoiy>3x3bcL?WLGiQ>t8o5m+3`Nh+_*ODisO$Z zJ^J)dj*zFh#VB{)7Kt5H+yc*yNU*K(WiQ|0&`)vmyTYiVN(LSSnV& zFRXk$#u_o0D-z6kVOS-~6YgEIc#Y?T@BJ&y|>fhED z{p+i{ukAgQw`2-{#3yshdi#gO(iV@FMf;wD>5r7n`i#j?M!r93#|=*6jK0yah8#EQ zM%^~>Mp4_+Jd3v+u9jc#pV!lOPF1hjaJaDFw*lKcAFc`>18+~3rO*WIc_b!+AS3f_ zAqnNTzur%N+a&t`O*K@ns3SIVHOiIBk z*=+`gFa;c;SC*qLbXj{O9I#hAi@NzjXWIe46G`LFq2X*S702?~@A1|%+Fh9I!8Hc5aIX5Tmh!q;+g=VA9T`1EK?h z4DoYw$MX}pjbe}!Aa3fp6+*YvWFvW!_gNaY<)N!jFX z`HXmhHYIDhE>X_vH~bp3mt{l{!c{A0rzZ6a^HY=OgPBwn`B3O68ep9SvxHVkJdLJ` zSHYi^6yH*fgvnL~yE6>iWYfQ)2;`&A!lg)mcv?LL%!89^;g3RWUj`1{BH16A3E=}r z?`Y}E=ZUtvV7~r*w=|W3{my-lZbcujN`F~0*8vp%k=U)+i^s``$*hCHOl1RJzo*6T zUdXE1eP8kF#BT~QSBrlhwf``w#&i{I%C#P*+A}uBzW6$aj9vz3;XZ)?>u%?vvPMLT2_<+ODWU^F%J^EzU=z*Ma%0d{9vlF-3&MANp=ymxl`e zRoWTwoauSAFyd=*KeVX(3$hqU)nfMBZwBQqyC|m6D#B=p8a(djHpzUT=~d=BOVP#n z!yPMfattJs_BYAaZ_JUX7Y)$QlW?b>-fi=&DmhKx2}+ZF*%*)*QL0hLik?XtOpt zxRnA-sKvOh7^uiqr&3S()wOD$luKI^6+XS+KkiIIQ3erK9&Cu5XVIthw_w8y{s|nJ zh0!wI7y%kBdl>j(eM}1h_Bi=?B-@UtaA3Ar+zhFY+vawU3$Fa){oB_jvv!41{=e0#vawqed80Q&Gyi%+qqnnRIoa{^ zAVOaL_QoY*^r}W-H17?yUl0y?w=;T}vPzM5WP97E!mHC|>O!L;{`w>390u!g6kJ(*{;jGh1(QWnqfc_v&^X$euf!|FuP9n2iG?iJg0nI?{p+7^ z^Wn(7G_o9SO3=Ab&Uj#(9lPj)2etOjU3E>lXk8l#LIc}%Lct5?_RRvry9tdolFp=x zpyy0s*YCr&y3Q>sg3(b1gg?sXLMNG9M4Dr^GD$1d^W8U9LNHf~SH4$5u1HrWG~nU9 z&$7@VA>*_N9s8toLOjMk>8*}Dqxy73274{XGIft%iAUdC?TO{AdM+utQ}(P{O>)p( z#_czpy-E&97D? zA6hTr!^#jY!0MYR@z%djo18GX!~r75u%$?TRqgugh`@=YNHZ*|{nWJefzMY6V^W=C zQueJgR7cwEL+=}=v4>&S^ns%Atw$lPPKgHwveGc0>PN{43tz~^r@M<2Ehtb*&`uNm z3qLW}+vJo<_B_QNBl?+xnt0x0+sR73DiVKRwG98`*yZRvcZ4Mob5(_?h=_Ak5(vU^ zX1#1#ZoH0Z{=xA1aGod@p*wS4lxGmuCWl4ZgiiNZHaU6BnGc#aq<*-XB%1lO8Zuj9 zE`$fYruUIH_YpMO49DV+D^@|STgGJF&ZM*=LMFZo<)}BS-~=1P7hd=J%|S)Ujh#L3 zvooc2CBE+ydDM25eQAx(FSo+Ux4|#9ol6vRe3k8^7){zES~d$oZ2G!~*1FfkHQX!) z6zW;yy2vVaB*aqfjG6T6uz6g+HlXo^t`OHbAz1kAazg(ePgFOL=U`js&UE-}Haa7C zqnXW~jI<}$j0?v~b&K{OpgRxo3FC!ISyk{U%^5*ALPnqJ5s61^DAof{pTr@X~>`Kr6C)cbK^$z-zT1GD*DjlYGM2-NFx zH?nelFgxpalyFFrG?!iHWV2bAP-zD2xtlx@v+pK%uRe};u{zra5#P_Ryg9siG$o8d z5dJH`Ua|mOc)%vif!_!a67wn1@z~{D(=GSd$mdIJ6D>Z}Du?+Tl<{)p^q!YxWrVVm z#w4e}lWJx@p7FYo)sYqmIQHge3)QedX>k<$o(X+HgD=MHrge(i49ExzwkA<#qzBfs z^{Bc*u|kJa89Rya=g~;BfxHb8QeRJAClsPtn?Q4G=JZbS(G&DA*vppb7g5&1>F^hp zRp|5m-^y;%y^RWgZjAXzn0fB)=+h7yh7f*2W~@#(QCk#U7+W~+o{J;T+~QWVNT`PCKd5l56p2dZ;(zVruyiWy!UP3#i=3nk_EW4C7k>FB@WEd zs{NzxZTF|xf0);A5=5pKpkP%hbX=(!TgMu~iR$?rmhWHJ+!7be*!qQ{hbxEI#Ua!8 zM3m>}iQy*w@(}}ju~GxULgiVCnnlk>NHwsbsEX*8CK6=#KzIC9r3j|uLR--u1gCzI z+*%G4Udkd^$bPs!dC;x88>m;5! zt9{&kdb?aW#m9H{m{?_XPr0^tl)1<;kurq0GoK^KdrC8IYU`!-}!piSk_mD0(6x%8CPE7cxJu$DEKQQ?w8vACPXrEVfBLTzJnhZ zJ{a(#T2Et-eW3Yz-FzPvgi{^ukpT(`vAx3zpf6@b?>QFXwP2pRmh}4Ij4*Iz_K~stLjnvf!RV(?bwe>??**sa$LNFi3B<&5 z=BKlob6SNy57lDKd-J#u>}xIeBI+&KYdp_;^siI+x?kQcxkgrrikt5VNej+&^=hzQ zq&eQYB^O0!<{{oFQi~))0te<`xp46M_aBtyPMh}X_4eLdHzMm16bw4TI>OXz&ge+o zqxBz47U6;kKw|O%4rauVryn&k6kE}t?@RpSz+%6~ZEjgT(Q47hFIB1J#nfjrIvIB! z&AcU>$MZ~u%%@OxW8ZP4JE%Lgo{$pEtSfSXk4sNO&K)7vs)9OT>6OpJ^V`bWeDL#) z$S)h@sZtU~f7k|Eg0{SJ&s!?WkJr#rgv(M*2S3R7M?Nt)H1WQVEzyZemMhh1MAUx& zPMXjW{9OwVN-a7c<+Og~vVdQ3W$=<^H*Cl(FPRccthXd4jrQoDvka!%loUrEV;U-_Oo|huLa3eLD(=fX-xY& z;)6rN_m>1v>NoSlGyFAGwzt^O8M#_XJu~X$&bS_2*(81Xy^N`h!V;8wKcuhriIiqJQilu!mvR@6p};}M9!9d?M{$&-D7VhGAa zL;D`CpxtddV+HFlkz`+`8i;U1iBa)UEEm8IFGS!$Xq9ANrZEI1qNj`Q5ewWYl}SYm zs$xj}WDJ>4l<7uA-Qhs-SOBxXaZFdFDn>)Weh0!D*BUf&}|P zxjyuXrNNmC+luj7d19g5Io+>diRg{PsruTul zTejcWN!A|SY0H3b{=h~D97@_&(S}n4A}KUmtIoF5ubo0>i~M!3(M!p`)S*l451&^D zBJjZp0T6m%JFzOsuxUXk<dx_Q*rMoffLw!^r@Iqj`-s6 zoA$@rJxdOWzx)Fi6;fZIQ|W;A$&(e2$o{t1UOa-|)53z1R6Az5?A`Pn%&Kg+#(Pjl z@3@MRNuDYw(K-r)jM)2pg_c>7;-qug*2xp*Pg#0x--=^PJVfoa8gI}z;$7yIgNa1{ zk&H}qgx>e^MBN(9_FPH6ABqCP`nvTJH083x@-=>n-Qv}y-=jN;u&3Yw*)Q_c18jyF ziU+%kPO%J59(H@|Vc9EOEA{sULHR(9#Z;MTya`IGso2+`f;N*z~bMake zW8*gr9^f-fSY~h7YndCs>x*2nC#Rn{vHOwYu>mQKmOs3{0Y+d*g(7!LZ3uSKy$)xu z1f*tPgiIAD0&&%`94*B*-i}Scr02pXKW>XJpD<3U>iQYyvOfL69oIvV9Qy-GG{Uii z$!T!AbaJNcSZ*Nd+lYW1U-tWzf?i`Wfd24{5F_!M<94A_vW=WpAX1-GAmHy>$%(f| z&3mA`sOQQ>RMsfD=3-1q+D0CE%IYztq@kP^(cL9BHIjPX_;mDYv4V~ z-E71cd<<0TR2!_YX+=6ML|(qk=W5p6+~HAF#6?cQ#7g%Ay=MM`Pi3~DJ4IXOD>qvM z_d$~0-_NDDoHnFB9q=wwlHmhVl8+Ch6y=k`u@R zF4793Sxi#pLK>BV4|>4u;gg%)IDf4EKaUe1TGJ}I(T1=h!J)LUstx`WOs$KHKs0s1;;ZJ?&Z1xSJ@2zmz`ZmXs!^(~`H@fBwPeEn7ACX58)j<2#za zS6=D92dErU_Xyq5;9jjTrkp5pBugu7S^!A0_i9y(%+IUfeV^CG1O_;ZPDQgH6))g_ zu=vFt0B(x$Pl8Qk*w2zaSzso8G&T+}7gA@TW{D}1(#kl7+t1^Pz&SkW?&RqTQc!(a zLxaB!MrdkN$;{)YFcZq{KSlIur+yf_iA1~tf`BM;H*TqD$TFi-jD*kFAK4H8lo`p0 zd$$@MhlV~!EKc(a22P(%hGvDi%8bHqNBw;qaTH7JrCh$+VB~1NfQe+uE(rD#(>|UV zK)d7mJj2;r_X__3t?JqsrkAh09mlhJzbZ+7&=zO#HeoT59TLwS-arLo}&qSZZ64K}x5{=s0SL$bf?0bxvMsaL2eS5!XZhl#ZEImNxFLwq*N{}H#?Qp?JHrwzM@ zPK5>1Muo>Xfcc#P_nJ@!gA|4v3Qi6R3W~6cIR&TVA$t3>x>O9%Q(SCUznDAzqedZd zfhw2CODTM2*!eYdrzcvNJ5Et3yT2d$=$Bjoa@hS?F8t0Vzy~P)o}J{$ECh<_8R*{^ zm3Xsw<<%CzB$PpqUvj;DLrL+=trLY<^v@NR*g%aU0^(hm;*ZN+0#Gh=KL}uvsrKW) zkcW3m1*R@+1WFytZ%kXe{$u(6{eP?}-=QNJDx#=AEsS%Wpkz6A64dsYDK3C3LxX|{ z-*5#|Py)oFc|DdvoxpV8qY(Ma0J?uX^I@CgYi#!%DJ$PcX4 z`ZKjP(|8s3)tk3h72`X_s69(7J10j-mc&AEGP%0%Sc8keL5cP3j1ZX#a)fYC)~0oQ zf;?Vz__b#pSfXFj)PYX>_#a`KCx+QfgUTnzVnOYNVzxzyZk|NN9|e1>jy#R7QlYLp4Eo=Dkj1kjpxljy@ZQmF~f0i!apvh z;FZ1vK>|_!lGiW!=yWI}*XKJ~QQ&4e5yuo==IAtX3ugF35sVy8W>J_r1NA6@W==%j zETd0p1%$p)!$GIf&=~cOKB6J2k7tm9ywKSau1H+kr6xZ`%Ojahnk*&zsZz%vJjYETsuHb|81Yd7o$5-(W(kipKRh&9cg9od z9L-hWlcBtIs*t}`HU@&kyM%`la)A3P6_`>Ngiw7+y`u-&kE$eyg7b@&x1pmD1{YK4 z`8>!?2tVqxMn^^r`TFSn_1s8LTiH<=u;NfDdkYlQDV@x)-RA9U#J+%T; z8h$X+3>U2O*7pxM1-)(KkEM~DPbI#04ITz*$!Lf)yMy=AqXCjr=r50Y>cW<;c4$#Ty>0%kyt{X@!?&6)dut3{NzJL5ZKQ3{C8s!Put)B=Kg}nzeq9_F%iL_Ecv|Y|{6ao#Um-Gu1 zrs)at@}{r|GAb)760Wk>N=?CKqGCR1k5p2vE{G%dMybHVjvHedf$SZg~0GS)gye|ro0gR z!57iYC=omZ^RiUF4QJJ24At*v{ zR`>mmbj0tGp7>C3c+@v8G|}K<*F<;%ICXFVtnz>mYOMv2+7qPK#(6`zz7%I$Nj3@B4Ew`ZNGc^!I?8k?PgaU!L73e^pq|znmo>25>rsu?v zJ1x;PH3;mpCdp;f4}13-e{ST6DOvY@G`4DuS!S`6WB9Lrx4}P@^nLK5N&F6PLm!|- zw*@`?^TAXvKvIIytQv&iRHQ1|?=inAH2&{joo*HDzNcp!2KBwDA&VgGSD zdrQQ@AsNeB!a1MwNR;SK>UhtqMfSU}AayyEg)QX`O7z2t)mml~45Y{z{|TI$8z}af z08F1f9ydZzZi}1AyOTd{DYgShT`-yts{`BJ&r>QWOA)y07Ym`OVX2K=iV&_VsScb< z3Y^N?>o8cfh~=AUC9}bXqM=~W{CiXU=WoA=V2q=}mA~?n2iZ7TLQf%#^HE3xyXYh7 zETJn5Eb`Q#AVp@JCT4C$#|&IhE-N;adf>x-|G)BzC>X{lN{^)l2?%j%gwK5a{8UM@ ze5`^*6{G}Pbs^Gp%Lj7QC#m|-^tMLNAR|3Ig`8v*M9w3!)Iqv0cXC?1^u@m;JUj8_ zUlUNL<5qDO)K$a4$8aIR)>&k_ssyzUj3G6s`kACruXfZcV4M?LFwS>>ZU-54YG*iK z*~58SH2C{8e25Q>ID#3?B^fvPku-5@UZ^oRRrjNmM5~i@ZO?Yh_n=KP$(rm^4CFY4 zJp}|EX$Dug3(DT}(iauPLNe?sx^BfhfWQQ^CUtf5)lZ<*Xi7qytzh*41VsiMU0~iz z%IA>B8{0kN(d=KU$%Si$g#_$WR9X}ZgA6)Ch>n46c-c-WpA#^Zw>2Wb=?>LR%v}&9 zdkvhvK$0u)A^RhL3*?rU z6QII7mLq;x|7C{WfdG1-A{n*v^Ey9tf=>`a1+_plMdi>|<;0~y?^v4BA231c5IC(l z?FS`GCG=`vPY4;s(>poAf)P}JY3yvq@5+`zi9TXkR+LqHu~|stlBkP9FlVg)qE|dn zML%orIH1`#YAd0 zL9Bye&dIpkxd6&4exff7{v4W)l-ReyK=uj=Mza+?B_{Y2LQvlVh*tUyFyBIg1kVYj z-jh@KkOpTf7W;z<^@0ofMb$_U(;&z!+L&4dSlhZdVCtKv6jniXKQ1v!&8u}D$QU>!mDVYgSV?_7td}E?4+?z$K6*JM zs9sT26mu8Wgrx)*p-S@dgzW3QFQ?-dFW7|sxZ`*uD1IpkQo|Jv$hJWc zXzmxY53}FgF+ar%-b0CY`MhQvig#Z z^UwH2(1zw0V27VWj-bR1%)Z#@du`N-xY~?dzCLvGk!BHg0FQJ!wMEV}58$n$;}F0E zL0+hmzsBa2hlWj9>v|cbSGqs$*4N}%%{RdpCpMyhgIh)Rk~s$pt-=s@$!UyZ)+f3~QPk&%hpNgYtC2WcCxgf4J zhO=yG*ISv8j|2OS#|mfQ+Y_rt-E+Hh{_2ebQn8lQhZ9jI9~awXxkR#zAkY$BQS;^s zr$ck~+N}p_vHWh_lO^W15r*bGj`;r-PktwRWqu*EF=gqguozdMx^EJHwy)Y5K^<&F zX?lhGy>^(HgzcX>Len&$E)UJO1==1%9L@#t?8co&k!E)L3TN-n!^%Bw-*OELKj9;z zc*OhR1z}_Bq!rcpCx1_fx??16)oalMfb{~E;*i>fQS{wnxfF&4;Dd61(ya#q9v`Yp z!|T_7if1(?DlaO$=@3rme}MP?3V@v0cJRD!r@HPQW(!QPwTUh-Y{Y^DNR9#=qRk0q zAbO%MQ?9s}jbA*k6v9IH6x76M5ff~^q=RL%^(1qJu;~B99@C;ZbJwapNo8(~m)=4% zjo}=7vj~%fk&QJjoy^tmeQYdpx z(lK4vEz+@s2m(%Bz}&CO6j6}+*&?)EjgCC}ic2H{$GFY?@h}n#1>w1o$80FgYzHJz z)_#U(l)Idg#B+TJeI%aY$J{^uI>XFPvcT$iqr<+S4^L0@lyCY2%crmux13RP33Y zB>y#AbP3NCT#xIJN)8^vXaUMPhn1d4|4?E+u@u=jsTUkqS>~Ow9ziSa20BF>V)}Kz zC5)aB{@)}_3>3?(lT9IdyK47@G~~IQYy#WCB;i=6AmBC-HMX`z?<8#+p(7Q)JRE6% z!=gpNQ(hBI2dKvbFN&%@52>!9g2=GH-t!P^n62eApK5?T zKi#?^VRuZE`xRPz&x=atd#opfjS9`z&!<*I5#))lAn6p9e@LCG`#OqXvJZxyC3FK$ zoD|ZJLYIb=N4>??aA+j^{2l~6l^!IAG7>I)36!pgeSG2DJRd3CA>!18>gPeSjSh4C zlcfgqNxV)$2g_aJVbK?)1awx78yj{m^G#@zWe%j<1Vz%ZOt56$)4>c;k~E5iW#%Lv zhvdKwCnvi^+~=3_eRsx zme8;N43IEsC#kXtJm#S-^B|vJ_T+ns)Z_EG0Y$qVV3geIl3a0EOjD^QX1KY_g`V-v>GU!B3@{n#bAAF z!q&OH%upsPSBZX;#mJFwIKzlE{_s4u*1cy#Nqa28wBT&Fk#?ykyw2&clU-wHdh|l> z$*<>Qnh*G4Iq90P1NE~ofw4gL4QdE{jU1wKB3Zkd?9yGRU%2S_@^V}+YpwD225)nf zv0N=b*fyBmFfgJu$BO(mxwJQtPa4QVlaE!dw>rm+4TSL?1hiiaR@y53noIGxbz^+V zXaD)^t*1Dtn@BOmrL7tYZRKfOv?>z@~1cyn-l@RY@{ThQrn zB@NLT9enEVHo}j0F^cdE@;VHT#Fq`^Nh}Sm7Yw*Cp0^I#buN|gZ@vLPf#ZaSAGF`v z5;1o*PzMvlO!=H}y!!=JFEw*Y%sy7liC}Yzm|0d&ywAdYU4B5cG2!A_2tMlfK59(_ z*AgdmACRgjrnr0C#fp&t%N$`!H3tBZsk4&!$o z&Lt*#kRz+tT5pU_KIUq!KU3qlbl4sBE!1h01J3K`n{zb_<V%73h3Z{uxJ zk6a6zt~bv7=SzAJa*HP9Z`F}iLi8RUZG0$DDw}PXSb4NDQua;d?QlSNhDrDM{^V%) z-o?SPA#=PE_w8a(%G%5QVsA`>f)^s$&d0fI?$gHCR&RB+VrM%Y?ngd2_-8NGA?$ls zkIqPA>w$0{0QuQWS}toC=9-PlH*GoepFcOwi8{IQyNt4(e*rt}pC-Jn@~C>3?3y~P z+3a%37}E-6I6J89bw3DXS*RM9r<0Ch;LVh&I&k~+V7$shp#IqYfiB8d)_u#~>&xRb zLuPh64(jt#;25Z~)U064o7V+(wP|LU$fZXT0J78gi7Exk3ud*zTo-8NiSf$c=b*DK%Zo)C2*Ts-8Ah&jiSl;d^PzP%gLrD^ z4|9c&>IWCHL|hm!3>JVRBw(MX5YeEg)_>>(WT{e7kCJybN8$2;-$xnaO8V{}@(LLs z)EQh{+6s4^%DVf|MA7i3&El6zTr!5XUCL=b$l?%wDECU zf_5t`_m85}#w*ttR|=hx~8FoPgP5N%=Au$-;uQ;vst_8V_@wM(SE>S8O&2(#j>W zo#^(l%o#`%ZjfSCkMJ6v_`Gw*DLbW6uUT-Jpa1pVh`sZ_#K1}%{ozy2ul(0$@v~#S z+X>5&^R-Rk?+0!$=9eRffLwfr5k$G4aIsB3^L?}UMroBy-k5ec1!QEUZhqc!yJg{c zq_J=~8QGn{yk!tn?|UKD?Dsfrg?Y+j_37Tb4S6xc#g7W#BB->6T~2Dq|BRmB#Ujok*QzZqT~Th3FQ%Qak>^{S z_7!(J$PCM|-(Kb2h_vyQM~TL~ZIdHoAdg-)mzrK&!kl-KvH*Nwz#q$ekb4;0L|x^x z;sq&O0Nde2fi=_&-(1y5DYbTuCV1xd9rD}0t`i9UHqU0yx>QjbbS8$opUsO~4}FO8 z`ze1koWGyX;8A7uy5hr}LRAUYN~L8b;i4uvKM9PgMLRKSj2yx84M4o?{LI3>x@|dhW4&S3Peu zY2qEH*}C(K90!s*%amlBmmN;4++Q|T|3AXs0~)S&?f(xU5`u^z2ttAw5sBUj5z*U> z&O`*!doM%ONJ0|56K(X~%OpYcHhLX>v>DxCl>g3o&N)>zB7_kCaY z_xfBdWA6J&kL%$SBuQ}7r37g;(rJqH;nGdm6fyr{`U)groEG;4pH}msYzVaL{dv3< zBsyNRMOB^ex!bA&^*t2qquDf!1svsE+K651jaZQ3rkOpu{s=o7R1uLkPseNg60m&Q zvu(p0&H1XE$ST-eKios^TQaVX?8yikQLJD^X(b7QJjk*!)Y)@Q6jyqq_@xGBoVJ zjz2iw1qDN8?`RO;Rxc0B4-5($g0kuOUfX@>X~+87`usQdqR8yJ8Y$efRGJ6+=puu! zf%DdV;Wr~9N#fgv$p9-9y7%Gx6(EgPL^a{X9^|;^#ci1&vpE8z6J!={^KnMxk+Nf@P>XNikb{(zQZv5-K9&;#kDm9Hblyv(l&&}O4=B=R)wTy#`B0}GZ~Eq?2*WI?$d z0glF_8xBXxhCVh(IQ`Nq(5;PpGLX1W?6y6r5Z~u^G>s8M{*wP_K23JGiR@VFcqiVU zVB-n!1k-BKrW&PtQ-XU^op4U6C?A_96U&X)Z(S?qGWjZFfbpmTI97%!9A{T|~u5-^=8ykq9=E>PDKdDWAW4AnF@OJZbq=|R=*Es~D z7wB98*BV7jsw}c)G&n7V`YLssm5G4cI`n)c_XOj$JbCM5@6fQn@TdB^7#2QK%l8S} zv*bidPCn|k`}G4Q0YuiE_GWsrutS7PDzfkuTf&7cHB+DL0Nk*_qE4Dj&>k&KdWNH- zOd-*Dmd|U~H$Vw<%Udjf0f>grckJYu~^dg8M_dpX3{&oEY@f|#4jDRN)&+2qr zqsza9n4I_Zo3HjONs;aLuSp5JA_Ml7Hvort*)mA@7I3Ryg@F*8`SncB+jjHWuv;^VQx1l9^#<3$$c) z;E2u71?n8ImqFKHkHQv`eG#P>`Y`6g@;=AMt9=st3C)t3BYE3+0l!chp?Ji|_GGmx z`3IiA>G6yv;bS!|^|+2v{#=)05kT!)@5o9{JDpwN4XjVKT#WPVD@4Wv?@0x>h9~6z z;)kry|CFofzT=fB46Sq8&vlF8SD=`6TSso^s~T>8@F)ROvWcL37U87ojpH4*jcPLj zi;SR@-a~_ram8zB2%_^;*FY$bGW2GQ*Wqs)OghXYCt{>%^5ZG4q^;`7XJF&_4R-#G zt*%_3aU%?)WXas40d0EiG{laVru3&HWZISE#_Wv65XxJoO6-7dO2Yi;)#EZPT>eDp z_D}!wLy7$K1?OsONKR+?z7vf`;^tO-JA?Oe8KtL4Y6^gO(L;|)d0OT+yQT2N6-fmdF{Y8UXNPM5i z$2jB{%9q|%L=Q5=Ja@_*ha{qowk8!C+m+d|c%x#=_Gm1`O^;$Uw+3}t_P*s9sb$wP zc`E3Ay6#-H5kD&Xvp&EbGsk`DIh?D?eKF6RX$|4lJog@$mU=fL(vL~s6hgjtpc^81 zR-2^|)n&n)_x8hgq_|!?=}ORTStcoGurK1%} zyIK|f)6?9=bGH}AAMN5&V}D07D|K9mK3T<)o$sQ(7j063);kMapi8j6cZ09KBvIwX zUZF#RU(`d&VUV4#zMJ%+xMmI)5Jp*LT zata($QXUsnFodK}Gp~Y_-|5X%grnx_Nz%fSj+M-%$uj1&adcDlb2_-T1&9bGe0%@% zuJR-HQW~fFR|_$Eo;yl%Q0b;SU*CfY=NbxPCc4%7jeZo+R(mfz=Xn-WqRHW3drRY_ zJ?Q1FaQ;6he_Z&}`)3DDN-(=)InS_ec{RG;g4yw-F3#@3_b1REi~V(m;k0IAaIscm znomhCh4wFuxCi$8hTse(mq>b*aEIfn>a(xwiQQE$|Io4p2P*QXzWp~V3wx7=FM5-$ zXYP(OLM%iW(FxXset7cxD-~0|N?j5b6!`Hx56V$_d&G$af!o%I{5X@ey9W9{66gZO z6@N5ono7koCyR=VM<~JHMmnAL(t{2sq8pUFp1YM?wNy)Iv;P4ea!*+wsZXZJwud<(qsQsHb+evzCO? zt;e!bB_ciwSs}w;MlqD&iM!k6W!fn;d);cdj`(nvQhK}g9UgF-c(uI?+srVYflFJ) z1;i^s(?Q!E@9W*W!oK;WN4Tk1ZzK0=LN!n z;A~e_-wWAaJ2Et%JgrM_JuAa;`G2<o%vVR-uPuB1*uw&Q|ry@bv9xj*jVM#$VkuNI$`+!~Lsw`2>Wq@tzgI|LOHehVIvbNS0G>es} z7Giz98-H9Ul_(O5%u(JPwjJ9leRmezB{h9gC&er*J9Cz(iYPtNp6W{xQmkwDY0Db; zli1mEPBL67o3X?zNX1rAV`s3w*_mEkiAe+v*gT7 zbQsqr``mJ4q&}}D^kvlPAcv4v&DMH}Ux&THE%-(s&n0H86q;<}U^n~NV(501C5H=i zI8QA`HkU>B%rT3teIwjJno!<$~5Mz*_K-wG2}HSr!b zv$YJ_=Vz5F5k^aWd!tVVuc(vI2r*!W>q)c|axF}&8bv=TkLlUGGrq?sM+Se9wyD?I zc9=qUvC^h|wPkkBFSh^U`bqK^UFg za6_zP(hz3?Yql!T9fK|;n#v{he0}-DFMWB{C_f>ua?xV_N}VxbTMb}B;`v%!i~5et z*=&YQZJO)RmT1(u6ERF7iQgu4FuzXH-AhpAO)OV%^0V>O7rNJ(oC17Z5-zoY{0`rq zZ=2w`!T_a5%dXcE0No&c35bg0@mwCZmp+``57NY-$C&tyGB>|WSxO{bWnQN@yU@fA z8e~VuLQku5xFsn=0YRA9vC1mRLvIW`PSMjiT(~umOj|K@`1?(kjziTjBwdX`*=}y* zQ4b&>&q;h=^|V}S;+AesR|+#6^?#R;27r=zqNrbm=LQO!+I5G|5jq@1<73gl;cujo zmgIR)jht~LhZ!goCSFRlGi=(+wL?611|1Au{WT3{SYWqBsLuS9{al_E=0(mgWWMn@ z>1@)~%(W*=GgpN^gfnoqA*}!(?0l4H< zYcOZw1P3k9C}RX@s%a++S}piCd=+p6a#uGU8sF{Wv>sbdEf2t0R{ElopImp4S*>mp zTKavHnhnmW0+hA?WcGQ@M;)bICgVQ^oBx72E!58fku$u$?1+@Rw&#}DbU)uIg3bqg zeSz=Q_FG>U?VP#h295Iud-Xd;4iQN}@UcI9e?v8;4IM|UyhWgxqjky6+AQrP`UPlG z32zJa<)ORP;j4AMI)x3+8g!~escX$*T_^<%7>jIYPB>ndMWgKT?sjWSH_{8RNcg~jpi(yrNtnqaDtH0fs~2y5ZMQs;3s3+FUgON?*(6W) z4ak-QH*`vc_eH)r&jFnQSkGi1Z)*d@68~;ukk$K|Q?sV| z9DIM}r28QBby~7a$4!D*DapSz`iwatipNL=Gi8WK-vj^tOwZn`I-_LAtiO8 zpIEJVyMxmiqh^!efl1A)-t&}7Nil6n=20~ zS=6vd6~iIlFdzB0F@NcOOG*!x47=x3ZO#vrn#2}~IWONmq-O0>SwP08s~=u>v0x_g zc&jemmn4{5wU|rC*`f&8eq~$cl8I!Ru)F+#$iu_ElySr0-VF8a5;lPZ_7@SiS$i&y zU9KKt#b2=`Z)^jdzVtm`C9z4c=O1iv^L{LI9?b{3*5>F^x9kdosZZWy5&M#0 zWrRE>hiNu?6b*8030lqEMPUi3L6tHcn1hSf_j%8^aTQ*dV*Y1Dha2J=P~pdACvPIz zEx=3r)uV7LWyl>%Wu>HCdr$1OWo;> zx?Pa8qfg$Oz&_c9;wP#}BNeGALZE}weJk%cpS;;*t=HMVU;i8q|7vC@Bw>G_fM&X^ z4(>6~&$pGj7uU*qJV!^U$ez6@%BwFhAZH7g8U{?;mY-eO&QVU2RJll@LMhIUkhjK6 zUH=|7=5k@V&6EUxz*t1AA(01#nSiEyh4-gcPf69KM%WrGoT=oLeB0zvN(P(E~vDDX9){!J`-HKG23 zx>23#qdUWbDel{o%8-kA7BSvI3 zARXVNmOlZLy5+A5%4?_C*#?a;kFCvxu5>jj(_mPUf*s$n~ga<(6Nm zkZmeIZqiz@JS2bNPTyCOB}y!2aUK4Uqv_v5`{5Nr-4df%X7N$5Uc!KSI=VYn8M2N! zBSvY4MQ*QGkhXRpQj=}k(CB$zZZ9LYD4X`d|z$r-AXArOv$0jMe6cf1Fr1*l}?nr@R_O4 z{QSZC@aazzthnpi>jqw^RR7dikK2X>FPqip_`{7pAlQvTdFd)B?;JfX+-D7USoPz& z7b&rh^DwVghoU&^QrorZo|t6xCh~QWaMV3H>!x84vVEwUzAz^5Tl?B%Z%?+J8P3MW z*3J!D&7GKQqGyHv%6fGZ0W_kcayf4}JXN1XVEU- zbD2773{kdo|3&QH8?L!j)ps1lIX%@Ui@-?_E?swcY7yN_HWY7<_9NvLV-_+pb=E?= zhs|5&MsupKmrtw?4_GAh)kxIlJEaxtqd2t6?#U_e!rsbG0(wIrZk!Ve1CklERGslyAIXEeg|N%ku^N|g=GosJJ3|RK zYTO~=5fPD83*2@!5+(eJ_{H5C+u2otujZ_`t3J0sPE|B6ZL%AzlkWwzcPhuT&GAcf z#=I39J2TIc{$&YWbU)NFsnZYcw^xnXbg?`SRju*E&U*Y1(((1f!kZ_%!o;*KoNKFiP803nDJu#VMtitVL z@+GQ9HZ(SUzii^e?_S&l^Rl*3kDG%(-BO)0(fr=ayNlQ~ckq}J?@>HBm@ku=FS&h- z_0^lbWo|fharM)gA+7M2HvnOxuJqhR-ev6{!r0QMcw&G{|srstCn#50o!r7_`!Kp-k;OE;SJ5~#VMnmTk>_6@0<0gNG5T& z>7PMiu8ad#8v;0kasbUYsQP-1`}G3ISht!Scj-0C+c3E`V7E@i7AdU5_d$knct4-te$yl2bb-&^zFrrl2PEY$O3KWIw-G>RXOf@yfW3V>V~PJKho=kT-d&6<+4g_Tb4Cs%u@O3!G2xGU^{ znbw?puX}&Gh*v}~Tt!zrYW9F=si)`jhHWVJ4J8CKXJ4FjpyPXMFfz3f{$lqH^1%oD zr+l()GJbf&1;sR~wD&J5Sc(iMee_~C+*}h|S)A{_fOe%&Pm4%u_(?hte7A6{P5R5@qSZy>!-~JM0-FQ&O-rs?FWnQxsl@}9jk@!=1B27@%yWNa%8K0ai+h(jZ=H|3)vD<`QCG+&+qtM zwvy^YO0g~@dAhol`sjA)M=?^yVx>#?eV`sdRKV@jR+PeLDCwEq_oMz?5)X5c5tK_c zAEkFF(yzjX=dY%*%-~Lbc});PPgIEYGurDK#L5M zd~M_Jz6x1YS-|^r!Y6EgbjKEsI660844_t$g2@7#o|S)=9=K`&t62eOcRo1yqNje=?3R3V zrTx&nJ0{l)3d>BVU2Nds6{=;@b}DbNh$=FZ_he9ON%OufeJz|bzX2({kBD_YbBA4= zfz^s02z}T=Thz%>poHx<-Zn#B`nRiKAH7{`OAF@%l^)1n` z0`rW~B&;GHWVu*|Y`UhU7#V=OO`wROS`R{Q4lYyYppg<55Pv3u4GFgpB4pz=no+-xL=$={T9~ z$3wrH%JDQ4#&>*9f7KcqwOpi9gy`hN!UhrrfjJns>QG!w|7zL%8RO1?bScub%4^Wx z7&SaZX}^Mh0R(qmN!;N^cR74!Xu03|iABUw!+Q{d3OW{EsJ5ALZ;-p)PjpA4%P_VC z{|V?O_9uMuE6JO@s7xhY<*ps|%S7}2g*>fJH%b}7 z%`g2<%#${oLkg&66|4vAL~l?k+sdAwx@L)0+h~>%f+o3sFp~8&xNjF0UmW{|@bu?! zy`6V7V)^U}(^yk0>GdFsAN)dD%qSEX%+lXd&@1d3>;byX{O&Dez2kz@X#TTK-vK^J z+FV2sQhpJY{yBNIV60j4Xu!#O5ME#6ND7~7nf-8aTR1|*>0RvoKuyhCjKhc@%*=>S-I+|$FL(T(U07Q z%cWxv+L%Y(NqNMYiapwjAK8kPY5PsypeX{9LR2Dipg7J>>Eb*{spXI{|M*lPV~v>YhKALncZ*JP7AZPqhFfG;E=CS9Gxl|_e!h&p&8|drQ^U&V z{ONALJMNgMZN_gMx(rR=?_p4zn8UVM5Q1w+U5IW0^(REP!Yv830~H%wH|Y=jqD&Ci zK3nuBJh4o3Y8b%y9xqs1`Mb<%bW4%5vjGs;5W$?#(MDQvHCi_zP!m%T( zvwp#Qf_@th_j??|#PO=~JoQHnxy&s0M8#d`uuWOTH<=Ft1c@S=d57lWS8>}nkIwlN z{`~EK+`uE>Ks=V^A-{zbI^}p+T}L^DlqSV(J7jvh$#Bl|0h%8?Ye`wn)Q|YMfiRTj zx2uTZF&tahX;p|9=;VH7x?KjV7uE<+nhx2Q!eiY%x`TpP${NW}x4Yf5WMJtNbxzS< zP*mGe{QWJn8DQ{?dK`D@PBW)R@>@e8f`Xv>be`NqC9SZcDT>qf5*c$6c-2%)zVwP= zAV_k$;AIYtk~2udJkeUjAaFyyr=Sd^5kjgyNr_F1lzfZHOE;u}zYl?L9br!@;-P{x z17x1)=l;oAJ5vyRtta*xmzGUn;l1E$ybb`uZ@k%v_}M94roqa zz9kG-P4@D?Uocu!QdbnHIGtwdFITGbgVfHuN$n>g_>gfG3?Fo-PGflB)_-35OhHhe-V{a_uEgBk08jr&gE% zdQRQ_EvKj0uUf?%bWVTE_OvUQv3fCDZ4O0(y#f*N$JW8duHjog|K8-8kmMY0X}SW* zpCJX)>kxyAvlC1~nq90YQm}!kQla`up-hg0&UFp;VeVibMf1Sd1fX-C%K}KD0gI9# zKjP3CD{6@^K3h8)M%)3KDvxF{L}SOTm5m!+_m00P)o%JA=%7gsgeTPI`>Wfo(fsQU z)U)0;WJ8pG$YH^%b6LGub zj3yvS?*k_+M7phUqnmpeDO?f-RmqD*-caWVa}!uQDs8{yF9P` z#JpeE>y7nFN2t_VxfC8W*4D-Vt))fdpLjxD%1FVdO^6eeSk#jK^M7r*2w9m+JD-!i z@fU?D-eF^hlFC3JKHCNzsg|P&8$Z6lvvk9U%zWp#H}G11rSR?P8SOG$pu0GZgxP@L zaQ%kpWk3CfUy28DLG7IHDA*Nuk4sh#oYfJzUvJ_UHJPKWU^Uwio4<@T6g9dmb`L)3 z^X5OO@k<;t+OCB37-p;548Y7P8QGC|-Ph$5dPy^2xrDNN-f_lbl)L? z&cv~$NyNc@kSqc5`fGwIE=35dRC#J*40FPrOuD2HFUo`Fp z$%T4@-A2203>HAkKAzD-Pg~Ct2VTZ|yB2N_Or!kbUAG43mQY1xd%%3CpSV?Di(_k- zC>P28JlJLZk7LPq{#=V~)apAE@ub`>1RzzFL`CS^(++4r_tw*u9sxCT4*uYD3UoYm zMt9uRRpD4NU}<`9Y4hPiPIStwfMi{%*qoMg_pEn!;m^;#zeC{I^$|HC+lf1x;oTJK z>pZC0lHw`{kH#l2?MUxrOj!`V5S~fEO)Ha`c=wyZ`Ej>&vA3Sr5fmUUrZ{_4xYpZ0 zLU(Tz5H-{T3zD47>iGWP9kl?ZZGAb7k93GFqIkl?ylKD+V6A2Ql4oB_O{`OGIod!g zlczf=rO)2+G+qUtik149n$&^bDwvR$AWFX8Y(kWdj|~=ny#`+m$3=0r{I;_z zt8x>C5*Gtq_Kc5Ya-!?Swc5@x#v6v&Z{*Rqt2j_R?x=OR;g5GeFK!>B(_uxpa33625R%ue=(T^r#n1m> z%diZ^ZNb!A5jjdJvFKHSqRvZ(x+75;(yMD(t=>`jEE8)8#SI_%^VjXh`Jjn&jw!s> zG$#_lPsIP4<*y9`>>8Oj*VlYzG2-remrqX9FTuMf=13WjO!`ky7#kdfq-uyl>3jUJ?KpzgukR2R$j2 zJcmKbjfAn{GUnfbYJVj;uqX|jR9ePdS7XR@MnGjr(ioK;;$?cdbrV5r72eI1Mrt|1 zwY?u!$qX!rj-w41M3asGv~k{a-{9L+@mV{b?U|E8BNyYjLF4^ZDQ<|1cEAD=+&!7{ zQ-j;~=1m?8w~fP`P+1qm@~nP-C3xrN(TBjC zTJw*q$U+6QjIro+a>9n((bI73l~{@_&!Ki*F$|k=-Cjf}pY7U@SCrAO2*JA+wAeoD zvUkT>W)dcba~;++@L`+ujhoN&@aM#ES3Jw=)#m#B)gD5A-|xoHRB9VJF%G?OQ?25u z57@r`z12R$w~;r@HZ-CGbIEw&+;S`pD9&&iVDZYyFkB-Qs)sQ@)DBPzGZ<6ms+=)r+U`lxBEN4~^lW~}}RW(S=^BK4ps|dYr z0&V$mTD)sD(EBZqQ?<6nCoKHe4Gk~dAkmd&2Iuw_@|CJ#wQ``m#zA47WL&HtO?q$KyB8(e<-*sJjf-Ibp=64TwG^R1#@E_m(fr_&j?y%rCqz0C!M zm-_f8B_5fdylfMy@2!0dE#ENlOst${%0Pa`E{s=AsROZ~)S67%1Mi*~Q4p9v{T$HR zi=(~h&@fkVv_d~j}qQHY2aNMR!8jQN9NEJn|Pas7AC14 z%N_Umu3Cv6jznX64#m?CXNid(1)RtM+B+hSuhyO*L@$<7JFXjdgT@wh2B! zbs`Wr?b=j;@x;CF*6;pH2>;Vs{Kt=!1f0N5OQ?`e7@-Woh>=?iB}srZ60bT(a-EWb zu@PEdL*b_feljhyWx({#luhakP|;4z;x#gj^~$<_@X+Z>eCn8s=W!;<@?H-^r{L#g z@mTkl5_=g&V`VMXP((1P27u`h&O_{83n6MuQ;O3&obXwnox5yjqH)NR??E&ak$D`kcWI3L@i`Z7lIAQy#$2<0^RcjwE(UiaR3DrSzL zKr<`-ix=;csw0%Iwsw83he>CTXlHeq<$#IkV)!?Ugo2ynW1Y0K1O;N~G#)^VV`_su z1^0c*OFp0OFP?pT;!z{PZ})yg3In#BZO&-jH6DfMS9U=IK+|Uu$S=d?9oI@Igj^?H z=~uYck47Ohkbzf8%yHORi+huM{q-|sbI*TcXT`ehitXK#h=BRvsY2Qus$RdX3u9~I zo+NU*yYb`&&4g?tE;W--$lsG&+Xg|YJ)%!Neli*C(alwa$&9Z4aR8_vR^uCwPLoq_ z<#~Aa+Gn|Vm^bdKOL3q_MLQtK0TvSHTKQUco1qd2hySq$K6Sc6x4TDAs(?NX$GF zkjbges9H1~yb@~_Z4o)t1ev>oCk1;yDbQH?P#JuMFob(>^{7!rzAt6LVS3gr&lQ6# zcjOJIWc{B_H5*|XL4m;j^Xz)3bH@n~Z|ukU5}6eW4JNU-Q;BA-h-+*W6c$|s{4<7{ zMDPQx2jrTP(k>D2+Ckg-Wv$xY7a9Zw#*OYhknx!{BkNdDNB3CqbkX4v#y-Ary4vk% zT^4>NRy;d1FmgN&O%yC4_Kf?~s2Vx!vt8=$-VTykVfNk@y zIu|&2kpLy>fk7;Bx=^1UF{3a^U+=TKh}PU0p$15)G-bw|1#B0T4yc5KjARtDFu>=#N7Jme`}V)MkC_SndwR`{CUT!HDSMv z>`Vq2B9T@LXXq8_RY8n{_ZZlpLE5RHvIkJlYd;lUaDTIM>~FlC?D9q5k&=FmBFAdS zx~#m%WmU1;3eC9|!X~_a-fpqIy-kBz_NYpa(gTceCw+-V zEwJsCu4={`O}%pHN%B5id(2}fP^&As%J6P;qCU^}qCH+`R9LWad66tt2w*p=X{SXh ziDIoAh@nwkfW*w9Q+k>;2FH^dOW#7>N#Fuc;ib4wy`P?51&=j;z4v`)1H8%AOZG^TQNj?ppAL*)m@)_<`Vf02%V$w4C8>knjNEeN$lS@CCYwhDX z`V2(#l1{cBiXPq>AhiI*uBw>p2AA~NPS$Wg;NUd!+RfAt&wd|m?2Z-xU7(Yl$=FyC zGn}ZuL-A_ero}G|tMf%}+G^f*C*wj&?qq$?m`UvLODSS<-nI7Kg>AkTyCdXbUgr2O z7TDI;p3;V&lVaW@Pos9in_KZxOYOZaEw5cXNhT#9Nhi^FeVF=sNe8TRkFe38?7*EZFlR?$9}|2y;GTtcDnCH*puds z?w%AkoXvv~#{h>?Z*?q2cu-6y?BhMrMbn!fXRXOkH z3-9E6^bu&N(S7N1t z9c956%sQGOc?Sl7p0i@7B@e9QEOtJa=nR`pE?RLU1V4Bg8GAw&C(^MoXdXY(s1Yf; z`i{G|{4^^nRpY~O=i@ezOb+@Ta!V(#BCf>dc(ZB0|LdE?_T`Um(5|GY@ePY8;6PAf zY`XYOS`VAoh^o2J5di0uCibE1%H4fP;I3JXZ{kNgeNVRaEjz8M)xNeWGe5Bz_s41q zzM6h#&Qx3$jZzHL8_A@_fkEfo+gwWaduY{uI>H-I5J650CO2pUCMYWPo|=E8xgI zx(wtIG;v zg{apt_Fl|a>~}dBe_3l4u6Q-cJ)swPICckz`Fc1WK8-OSOOJ+2(4kkz za7}+_@o`kaV|Q_n_J_q~0&aWJM^BtWHOE<0?I%4Y1Xsda2kSRjE3<+OLDs|%et?~I)KZc~U-MnI*gtfY* zg3c~M8$HuP3e1LIGgDBLUf-XwvGGsQ8bxyNj-SOJRm@i>c)>hf~y-<@zMeaBwVu53a@E_<>+W|=FkUSc!z zibDGADgLP?GY}4P?{FyAW2a6_Tb(Ji-$vFqyYaX)rv5nqu-y9bSBc?BRhg%)MER~N zl77;eJ*WP%a+>Q_qLAN&IvH#-u|>ReSh9aFqyM_d0@-Lf$uttxx!uC0_VsgVzI7`q z=!Yft-&C1uyc*3|r!zS0c+x6vOB~wJ%eAUDGgSu(%<#UTue}k@LS;p`(^MF%&q^ z8X}T95Hovbwep?Ce+Cp5`{)S`Hza1UJ>o=CRU-MM`Stiq@<6}+zH5a_!yh=Ac{`YJ z=>fQPv0h83KaExP2M~I4rR$Vc8y2sA$YgS*2lZV$HyK11uyPjry0uX$B#h7PYJGok z1J-9&p&BGlDb3ftAwKvt^_i#>m21JAxck-@sQU$|(c{t{a#R2=e^28*tYjoF2-HT6 zlNxQ<H|76Yo4^a8nnR`NgohpNmMK6gGRLvKx1_-o$f?WC|-ZX&a%m&JWgY&?gUYz7i z&G@-6=M!`C_jAjo9CgERCzrgwLf(ORJ>u$==(cr2i*moGQ2#?|F5?35j}6r$pu3#E z>}qq}paHqg*M9qfdx4&Jt}|sQ@k8<|g1{NbFJLv1Zg0jnvfxuF;0BD0yG;D>yn{~q z?0jtk@@aHneB!BN7r|-uo*7}8w890=BDpp zQ0wyO_#D6~P04gy>U;BrqPGS}_|fdt(Ztib-1@4pBhf@Yw@`?_V%SKLE$G8Za?6Q( z(9BqFb7dhE#f&`r%~*8!7A7esoSIFhu71~sTr?@W7VTmv55ONX=dd*A%K4-&XFHFY zQzHcKng?_aulIL|@V_hSz&6_J41gD|EmjNCOjKt&lqT0-FH@eJ%)R}B5S&rL@>TqW zxdV6iPK?Rb!0UL$JHGZ|kg7bu+i{oGZ18t#CR@R}+sTJX=#vC{|7b#9!Ue`eq)NqC)BL%i@)Fb zf4vGMqJ0Fw#25Jwr-Sn=Dk_RH&nOa;Q%*#{s8!e1>--TOu4pQxPO$}uK z0jMpr7$-MBBNbPoqpewPkJ@buNX8y^cdf$w?Kl?IEUeu8u|Gajj`@pLPUOyHJSpST zj~H!}D$m55j8aqRhYY!5MK7EXrCpj2n7>^ke{v)WjLUiWUIqv~S*`0BbrU64xPUHJ zLbF^8uf_IW7Ac||)B-?MX(Hp{|NB0aStQLi0){NH(C9Mf2k0EoKXd-1z+NEZ=ej-h z+@QK?lD>ggqwy^&Qr|XxhlIud;Z-cGGwW9jf&POy%WD6OlshH(iNMn2)Z1Tr6gO znb-3Zq(PMd8bNn<{U4U#6>%V(1b!jdid(2>;bop8Zfz-Rcbt)mff1)?d<)gSf0zn3e7R=^0_`_pfpt}s^=7f?** zUJKTV=d%&@DXOowuYStd7bzEZrVAWy?H@`1d9q#C*k$7r41hV`fv&vJf5UKQ`lcGTF!RKZCr#p69FAz(Wf$dGq*!`p?K0Jl4L@V|i7>_Iu)riXLYY#tQRp{jV z?*~$_sqE0rzaQ3ry9y+_b6+Mlfbz5Q%YRsh`*Xy%AIRiHEQG+XYqaCJBRBsq5qn8U z1mAP$_}9j`C3Bwv(0>Mn;PpGnq~Ixj0ubc2?0>a9|GuC5vBbWFU@Mc>Bd$mwR4QnM zVr6>W!BE3HeRGzxUhWv^u%$s^&h+i7h5!G@*;~g&*=_CPfM9@#ih!gbQbQ@J2UUd)5O_E$H~dba81u^SvucqxqYdS(2Lk$;ur|Fqe`5FHQ45~1Kg2=Kb5(Ejr!l`Bte1ckI@-F zFA@~vxZqt-0$Y5D15tZ*@3`Xjn)d0rRGY<}c33ooKAe;^fhd)uQJq=ttx}v+I|SCJ zh6*nQY5Ii?-9m2W3Zm3`Vm{v5DXa0J=j-O?-yM~8xNR3!dvtg=!{-V){+=^D4)k@g zQabPQ-)U3L*&`*4@_Xf$u>E}LUQIxQ0v^l8{HPnh82Ms*84=d}5I z+34tZ-K5IUJ- zTJt##aau{Jp+wG#4oAbJp1?UTpR^~9fpND8|st@Z_WFyPS}G`y!tUj6yYaZ=&pO}cefSiPCR_{!5yuQx)+h9$1d?l-k0hyw>FuFwCE8UtXx3vi{T~Ktk%hU*jKtPhK7@ z1P;---6Y}NuuMZLds5o-}-ir~py)GSs+`M}JT3r42?*Z@M zTLsQ@NlMEFTdgwm?}f$0uo>z{%9b?6%ukr))37#C81$(IhbJZVE?D@r^p0+GXZuT;5phg1+-m83fV6La>q#v;Qo~m7(%<2_sqwJa1p4}w|&~5 zSf}cbvKs~wJI?X1zbOH;NDXeIIc3b}ze<3Cy?;7Gd?Yk5V(|KUx!7Zi_V-Q71=~s2 zwffWOXj~HK!KPjK_2HAmiPHlwxebKPj`UchpdDa(qR}CjPMw_?c&-qd~-Jq=deu24h2HT;=>0vq_5*+i>T{C*6q zJ6D0y(LN~={rx2HC;-~8v`-D4G(YzQ!k%)+B9p#?x)L|g&qca7Pw(C0v%8j6=)ryv z|K@o#*nqoW4X#e9ygU*5p?T-$2Z|MepFjVSzY_@$1{ozs6L1%hIoP40n;FOHd8j)W z8qtS0JD(WG?ahCnxh|oO*3*y(r|)_Um(d_Ur(>D z#ClHm@L*p_?saMv#-mnx>{NxdFP8mBU;e59M4QEW=46$F;ymz70j(+6cQ+Q${Nu|B zKj{cz;7NI^Kb{EG1ql0uxUbI1YgI*bo>u^#rz@ETPY<2%E0hL%U}CM6um6Zi4Q28v zB|!rhy`k>jjjYF}wFj&Lu3FUUiJnv%?PWtd2rX@ORjz-#56mFiT4~npWeN@0KhIkU zn8yn65CSAr;ZEPl)feFZdB+u)f>vdKoH^U9t)imxjG*5@IVP`KvG2Q3CXw%X`@fx z+;QB8%mVOCRc$6R-8a6=M23fThej)|-oV8rOO&#cisb;#pocAn37zMg7_I}LgO4VY2&i^k3 zKu4MGradRFH1*{t)QBoYVm@7jWW5!`Y? zQwFjZ(pi0v=k;0H4Fi#VLG7Pu{((nFyLo4G&F4H!27+!ztA52 zLF^Uf6RpzM;Lm^u%R&}%Q-DZLj?OyE69dtmk2>=p9s;+gR2u1&I0M_bz%8*py-Z`_ zGHAK*=uULMkVDXubE%6a-6~zq#X}{rhKeykoU+2K$(v$Rzu(;o+!P`~X@?ViONINN zsf?QWp@n9Hd=R;$D!jNiOM&3+XL8Ow5G9R6%Ey-pY)s4hGw+&qoAu^RIQEv=zsuO4 z$LlSzj;uWZ)GEXr8ShFD@jIe^@m+c-5uWxAI*bYu0q|@gAij8{I>(CqpE3jdXi%A( zYNy$E{=!cqsLSUT}W}@DTDQ<{pX>3${V$y4`u0XxS~Kl*Tuxl-|X((%5k!C?-aq7tqzw zrCh*Hqv`L(Um*vT-OrdzAeUrlI128e_F8Vw36~`$CEZ}X{W}4{hz-=#)2)%|KbPWv zVv_rcvFcN1ubJD@8+@mNP4K?UhkZ6T+zE5nf%CJs`>6dm%*T; zcFRzCp53p8l}R5sD2Lq0Snh1qYxrK5JPVJuYzd7tH-gYfg)9p-su1u(t$|*t=U`K_+BMrfY?8w(4d_8q zGYaBQ=4R+Ga_j6oG>F}-O3{B)4ai_2htB(%oE_S}!N_+?8zprE!+@>1CiMDu;O@={ z+y@^H#=#RUsU+J7J7_>Xe+fPF6_Wc`hNv)+H^17(@>K$gI)uA2DUV{|A47aLbT&C@GYDvYfu$2o1QiZRhqwgjUyDU3H%_;8Q;nUJeHMQL!k<6(%G zvN}VO3{E1#oGqVM+&TtOe>A@~WS6ml)@uVLRGIYaeJh?q-N~JCJNVb<^EH?`O$Skf zq-TGaEe|x-Sy(iYZ6G-bh~jp@*pr$lDV=us0hM4}PH|rf)R|K%oJ$%WHAUWy9CCCm zl!*`+RJB!(Ya5fMa`{kL{v`Jqhx4r6)OC%XO4rJQr5+J9MM0<3A%sKtVR^MWy7Ws$ zDfIOtEA#&aOh)osgz|-U39Pe$TbqvskMGO9;Vyw4#0ItYztEbozqTrIF$47l3l^KP zFN5X>860lPgmb-A|LW{*3B8X6Bj+&*Qp)VVmtt?;nNC%`yuZ=UR{SfuOEy(9T?Vi< zA2su>S{XknpPx5r)m}P#iHg2*FRy)8+yl-T>#WMb$r(Y$K2d8 zUA=u8_ujA9V|1*nO(mPZ2vbx=c6)ur{OlyyOkd=d*HiqK4A7K2HQ|k<@`*+r_x$`& zxthz)3|h;swL1ch=3Yv6WfY_fG-Va$QH;iP&Aa6JeuUx`?oZBbI2|gr%;{3`&B9vhidom0NTtPW2F*s)S$(i7_09wijlur@EBx1!yK%HW2Ay3-3HoDcsPifD;{f@OSYXCTFT~Fja z$@N70SZ|`y^W&oUNJEPM<9Pr*nIg;1S_PZ!)^td)@%IeU;POapjqKrNRfa7t04izl zxoheBUp&rD2sYR!q@Bh;Z9}hf%BWDtW>^Q(OKcx zeF(UZ{;~LI3VDyT#&9Z z6X5Qf-BfzX|B|J$*n0}*RT7rmE-LcvoQ}%zo32egUT8Zgj{$ZI=ku8SX}iS;b5F#R zcivqPD=usrv@n^F%Cj4dN`0ycj$@b%|H@~%vk&LluXzTMaDzOtn?X!uH;m9!XG(WT z$=MFL82@Mxwwex*adL=g*I(Z?_wl1Ol5_tTO|Z8q(X!U&S&(XTNu?)=mg+d{m4$c3 zJPNS!2S#%N{nFfvA>+C2sBMMAIvK-@&Lm4m!~T+_VVk1@<@ZXESJ>-+dFzz4!ue}i zXpswPpO7b=`!NCyj@tF48Rh~2+=K$e7Ywa#13Z(KydKEUSyr^nL^DOqQ zeRW6nooVmAM*T(uZQw@Wo_R}u5;UN<<}&EML>gz*SrTp1lf%R^A|KCKng9nSKfR5N zH0|~9STURn^5vTcMl;}+7E9Gl!6U-+FAA>~!|OFwW%pX7I*|-_Spg$N=wMuNrl&Zp zovqDtcV{y+`4O2T1+gr+-1p46@q~AR9?DeFub&hjpI*6~+2i|r0BK-ZCB8jBwLB+E z7Z8Gp6mq^10ADI&|42m%!JqAB4p`_<9}0Hd#ShsDQ@`c!>+}igjKlwl8WRbQRMvaz zKjDkcs+i><QytPI<VMXIF021&W7m z4C!T_!Xy~E4Y;2rLOEiMc;X>l6##|S!3yrGqn5)<>v_x+vFbf3lr?p+o``HAiwdRykP z!D_Fg`2iv+F%}!HEg_PGwL}t2$A_L9+6imw?-|6x<0@WJQW(0;qS>Hv=WYZ7&e6R= z2j$p2+f>hpX)D06&}-DGp4SjsO{tL!CC#6d$W%@Ft{2u7#*?XLS8#ziE@GpR#onRK zD!u&d$H~gAs1S(t>)Kx%^?}zrG_qyPWCF zxhc=|2+%NNbA4%nA_WiS&6aJalO{erqpY|fl`g-~UnFPSFjHu((rxwgLao}|Mp#p1 z(Ra!PKK=zi;e)&3yi=sHKJxy;cOJ(?3bydcq|5noR<9xi_Fj~d8@NpWpaGs$DIuzD zxohP9zO&a#d%fx(t~N#KZ?1MyUVbyyZymHk8_(K6%~OSa151)Tu4HYcW(6E(#JP5n z;c}t#?xo@iLus^=#-hT-`&6s7XY`W1p(`9oG1r<|+7?oKDc{1lAu>^VY9lB-e5SlX zj#w8+N?$PINaM6Wkw;kVD6O&HCk&WDIc5YCNhLMbWw4CD)M2qJo!w zv#-3eWH}K9m)Pw;WoYacD|$AVb>xX!&Va5m{}<2jH~K2NC*sSC>P(kEzl3vrmdW8< z>Vv}WebwSLMeow_Jg;>T9$~xXI02qX$?(djlHXBeu!yaW=atnXp1AUcQ_`VqVe!>s zUIP9+=Xtn>0i9Fg5R;(3bjf+7y}O<_Z2Ka?R_9K3QWz=m3&6T@?sGK%F^X|+ZEiww zy}p$4h&-^3E^7$$`kk0B0Q=}(MIzCM(K($fS2sX1sYc{g&?fJae9uxV=+0P;^gFc( z$)y;Lm3GmdT5#IRFcoBVbQ0@x5g8*L2xYDUukX^*(s;WReJ?usm);G9c~$Q{GF2@K zP%|re41qB&nHP1K+huaD#cW=7Sv-U0d6DWb)1e7a;Fx5d<{>!n6RIdD*xNg4e&2g4 zlFvE0F}AXY_Byv|y`n|UOv*MzUi(GbyXHe!;hSwYr}zeat)6`8Dk{uDnu{7uEqd#r zeING`;IY5j&H0^9`rj$Qe}wg?IJF_b!W1E9-~ltrZ!wY4WNg`Y#3--yo0pCQNxgzk zLFuxkt&sZwCk>YNDunTIRlYW6x7GD;3;Zsq<|GYx#`9*K18^@YmLTre;*cDSszXG0!kU5ixU&%g8`K!3EcSO zDFDV-0Em6xO+O(!N{I)|f^AXQC;Gg9a*7<>SA-==8Am3#!4$q*wTC6>OI*YiJS13p zEtTNXamAw(EL~C`;griM)?Y&1JrU$ubixJJRa8*(@ZO5CsW&kS6H-J;FUQi8oJ;#@ z`TS~*!JPVmn~(CJbpBuQ{gw~3?Of{BiTf|2kDj{~416nHhll~ZQ>;QAD=;6$vFx_q zzwHM!5S@g&Y9o7c;u~Zlwl4$SCE&VroS6PU$TvvS?FryzVWS-(AOoPJhT!rKB0n+1 z4N|Z(=oIWe?c~{`u#(d4vrk`=$VtFE<9u@T~^yO_ISV~{@BxHK^6KYaF79wg=s_jV(S zxqMbCUNENGlq&9{(FdSW6^K2L(fK$@S}OP1 zx5Ov<$#8o}H7ub%hgm*+R$*pR4z(@EtO$i*3JztJbsG2T z)427BS5W+F`;?0&4aQ3*&oF=Q>Iwe|dI%^pk}K53_(vh(Pf4&H0)qHiI43;xd$_N_ ze&8lo3mrXo`Fj`;ai`pumrs%K^Vi(L7jHtRLXK6V6s;PrRRjMt9Qg09(|=@ip#$i8 zRiyYA&%dhS@dr?J*_+1gD9Qn<5{OPi4!oy5Ui81Bf829)_~6TLa9k%&LreVn*u>;1 z4@yA5`y|)z7Ly(?DLNDWPZ8;ab$tLvhHLr|?|4by$b$!8Kjk`=seBU{Zn*AR)X`aQ z_i-Yi!(}a@{HO8pdcg$g`Uxjoj%M`c3>f&!<;$P2j|cESQ_}x7?DK%#1%D#Lb?hmC z1RpR{38HGJJ;x{o-XNORQhbCG5(?;*+Id>cddh=A=#{uC1TzDz3&2?2695AO-XZ6< zdWxBFgMI=US%pZTJeJDWXnZw+ke$XXfL=kDx__SgJaar!F)-4)Em$$bX(LqxBef7x zUOY04?l-|+z!UePe&-4QDr(?^n*hLxFo_=>h<4(v{6ol3 z@#3fr(c--DaiZpE^BMWjTVv1?eky=-fG-Bxw~`%8L=}4AXRkgwMJu4xY(Pl9ebX7a zdGt*QHuRFN3lx)|wxlXxh8)5gi$~li_nV*y3xBvAb;O4GH@Wh z@E-rq1%~s3=j^V*`)htN_+EO2mB0u&4@r26Q~K;ou6wq|<7-ziOW)w<*!uK1ihp6- z7$PUWoP-OByO~NY!DzT--#i~4-8*l_Q%9e;R~y#YXlS`nv|Z6;z2F=joNHsM8L0c_ z9!FwMsyxSf8-=H*=#c103FF7_AtVu@qzdx#j0vFOk0!~rYZCGIrY5GOH8o@QN^f>= zEDfZ22wx&OHX8E$*vSXC`zwB|lko;bMN!n%HHS84$N>Hp$6=!ux#(o}+s2D^T!%i5 zuHoU~lXAGb=iahfN~vah?+4S097?_2bAARYPMXo7hKF|I1-`@WnhzUj$G*)`Fup?( zT(fxl-|_Vylg0gj+5-dbYj?x`%F#cKnHxnL7U+ORLoY9_IBi@Ne5|D|X!7&IuaMhlT*+O4ouzphnyw08@ z4G9QENTc!_jYsq}cQO!^BgM*m%g&!PjyTl|EGl{6KCwuW2+MwyX_DwW;&=|T%Wr@R z6ERl_9z#fo8kl171=5q08Kji1VSQPKfgY$ylEL&YAAByunW&8o6|rE2Yra!@N3bOy z2xbXU2+KWLK5Mah|Z zMK*yX4Ln?2-M#`t&?}6L|0)gg8r0a3@c+-iU~!4d9iZbk9WSr)Y*(iA8y~IkL@>CZ z75P6hrU%?fI5GFmDT9Lq7}+83dz@{{)e+wYL6z=MnZ3={B}zVteElW`=W7c_Xs1DS znSS-^v4EJM<%P9*^(54B@1vFPTZVx`$G4aJR-#BYjgk(k+nR=N!5F3fVdaD{MjU z?q`-G5lnpyCSlakU-$0B$O-Z&j>j|QS|?8GRZQE3K5iJibwPw6U6dC*+#1;=eN0r! z0~3OWabqI~?4zD-Tq;7)9-nU5AhiLJTa}-0NuXV_C=tZb|3- zW|;C(1pF6Um8kaFl$(ScT$pM~#w?da9{I}$gd-5K2Ou^NQI1PZm2la5=~ZyM0fI8> z%qy#I1$=8{JXj2)t>inuGeCdSrKgm*pD+-z_lri_Gq=`2j}|JEego32$M?}PdY*@} z+UUIAO80O*|B?$e9?1b)WwRDFXp^X*YTBc~GxP~DpDWJWYp^8vNJ7se(SLXEUH16k zrcig#cBb!SCjxxrd_x^KZ9b1lTiKcxCCsO729n%SEExgyqS$Mb#h0$aHG z14TMYT5p125yy3jp82|zn7~|p7D3s2+jgWJcF-ym4CV(IU~*g(6MpaCU$iCVlZzEn zl)bmWQkn56^3g=`TmS7%b&$PZ0RA4Ff5^x4XZuLwCn-I6Y4>qDe+h0It?+Ve&A*#3%~31T z&>iTB9IK#BSIP{fD)-BC{9)u#O)$q)&0cxeObz!6G;R_U9+1ULtl1|XU`jpjZifkR zmc0!|guFRUst5!Po;&Q}O=bUJv101WkBmz_u3Goze^BMkBuBo<+Tk=GV&^dKqG*kS zo0(+|qgFSf$NgRwNr9sMK1X?~pLX;Qyi|8yFkVS+(A~2;qt|jAG*t>qZi?u`fCtz3 z8jqBImwtfZt_wsbXh!}-fu_F98~|F{EpR>T>~UIZL^O?o;j?e9950r)+de&}EuPA{qeu3UE1Jv7LScA%!(lFRxsI~PKWIY@<;&lw z<+{%bI`0Gn5`=E$K_lmm1N!TC% z97OuB(kI`5lPnW{)3_^x>2W+LQ1HmZpNWuB%j3F}QN~4Z8e~~b=Ol&DJ)Edg%r`i^ z#lQGNWwG4Rgz1U&a6wMa_tz=S0r!NP3ZuCN*1wJsNW7aQzeOptt0A;!WIr`XuxDdl zaq#N7t8EB(#z!5rrz|UrB1bk(6&iO(ytFV$&204e;Ad~YooCbuF>Jf#%uF^jFx!!) z7-OiyKuOKa%$)QRS>>3pWNJ96PKt?4NVvI5HHFySe_{TrLX47=zjUv%+DxYTJas?> zK!c8`=bnE-n4`&$TtGu3F`N4JzPHTJKMvOx8F$NqgOWy?62@M0X^-Ct6^*(cIG?dnsuzTvp?{o~la zn~KL-{P8`@mLOXHyIhOc>u?XZbOOsZYWg{JYFNT~7R0v=W;j}Z@eG&wt_f^m+}m3g zNxZ+mQ|FaqJ^W}}lU```RpW$qrOVSR-AYe2^uWO*uIFqizoq4}U3kc!vgCcxOxc(2O=0zP^I5+_$<*w2NPBb8 z1Huqh*Zpp}+N3b8iR=gK zl|tg*bKbSAmL^~AYK1#cxvWWoCU)ocU4F4ynN@qmFh`n|NR}C?ZH$Qc*9mS4M&%5_ z)h#^EKu`0_3Wj)tY%wTdBef5DW|pz zwco+zg%6kw7uw5}71*82r=s~KWVvV{wo$I5Nh@_JT0Q-DKAPn$eM|=zt3*34$Jb5_ z?FJuaP4C`WL`6P|gOK%D=uF#(neA>DEmf@Nt#RJ}y1h!WrI$+r>_`5Wj2?@{D^Tik zfNE`Xbbm4I(=n~nyIucX9ASL18{7p|};(R`?LWv)&iciO^ zRJulZT_#t2)lrVS!Lb_Rw-NWC%A@Ji{*(qML+cg{Jiso1E`Z%f!dd*E!(E`>Yi#Jx>U z>a-zxptI3uX***(`_=}p1aRhIRK78+6L%!5rNs_i-vF|kyO zrua5Z;b6(aO#=eb=QaIR@58iX`M2kmbbkck?G;}vU#4h)){n zsPPOY7P3NESb{c%w= z?9=W_j5O{Xg|&>9>%=YmngNFfYXt^|lpY}^96?hktnJ}k=l!2OpP!h37IYdP&5BX#^zVpSL#zGXlesQ0rnlv2pK-mk z_^gVvr6Kd9Sy6oUn7<&T;M>#rU9PypGz+mqMfL6<+Xv^U3gd6Fb|3=i%LVS}s;VqW z&d)8nI%wTneeV)qJnL(gl0s8br{!uq*Wt95IciGS4*DP&tRDt1vsR`rIPG|l(u?#PXlE7owtV4`=Zexj6TAK z^M!-uB&QJ_cqVGZbz!H%*fifrHJrO7q@~|-AlX-B&agSetwhFamiP@})A-?z^v(wP z^Vk&aNM0>hn#>ki;;wLRN57~JTQ}zzFR3BB^?PYrm6}ykS`ORrmFChLJv$9-#qtg} z?4ReNT=#M%R+^A-Gw%3j_%ipitNjDNy$kC>*4`+Wd)5Et+u2n5^1Gk|gb}IvhmeM6 zB5LeHyqc;-L#a<(HMXZK5r^OKM?Sqk*t8J^TOpDk*3NbskEiO$ZfK2tO`!^8MfEhA zYpN{0%_`$EYNXsKF3}stYZ0Qcp6&QGb*1b{&N6TD;*OeW-~ro!!z#B;A$vEy1}3s+ zlee|YX|cFl)Ae21+KTaplB?X>CY>Gj8Cck*Qs~Z_5X+MVEq1kyY>J*Si9?~sZ<@_N z}~P@UBJBFuQ%7 zR^^F!kxe_oe(gu*pqSsMTQfSt4!eTIPFvh4-z@AzW-P?U8;!b|q0-uVKYptX?+a&5 z+K3n%8XCd|H~D_J)(AN+(I~6)z#@1wTG*Lqo{hw5MOHTRhLEk}MstTfJ_- zxE*F1sb*fGv=+XYnz4E7?vyr3EW_cPUzd zO_K1{_5t}=T}-4M^CeHdu%GnTpIZ#Bt=r6%yt7&ykVN%3S?2##@Jff+2z@dzN4sKb zF0k0@Cgc-xVq-#EV*VXQJBGzNDr}maTY$a1ni+)YX_r0^iNzJO5 zqz_-4CExgEl)zKxS5@_3reycPCAfzu{S_v%XxQ$KA>(4t*lt}}tZS~0uj?M>uIui> zXLLZP3Id@dMDUltnw;Yg;;?Y)DdO5Pn|&IE>llMxy?U^k4aIG`$1be3va&KhOjK;s z7tL>-`gtbI^f|tKvFWbW>r0fV5XVId#Tm8D;$Gt)&nwR)sEsGl0UADiugw@;0J@XJR5ga>9p0U&tUqAvx z3deOSi_AWaqHQ(qYKld@p~2fMnPl;KBTXPlj^=VwJFc}LEtr^$iDif`q3}qZJ*9$z z;f_n3YK@6}YA2-})27oLRXisEf&ljcmwr}#cw%(>Mi-dg#p`xvRnW(hgwKD(xjO+k zbm7Er9emOL+|?6OdGkfQ+BLIoLvs7ECfofsFxQzg)_x_gy71U#gTnJCw=Cb3f7-4| z7fFAa$sPY$a07C0nvmbGRCxOHqQxM0^#jUx_?ys>ThU{%bakvM~ z-}o3J+5;@T>ch00P1DUknI%%>99Forj~p&sj$2Xr1brF}6341j=9q;4UN!mOV&Hxa z#|RD@DF|3EY3Q)FhkG=uP0=8Mcgn@g>#RG~zWZHdB2Su4<`?T)MEOBY|AEa*{)HY< zhX_Q-Kp;zo<;;X~9Y~ivjhwYHDtDlqFG1L4X=PXR)?_6OFXq<9hJw3Tx+}YhqW$hB zgqaK*s`Z+z^5l(ru_npN`eoj@JMH9Jfgp`rVK86=5ePx}MzueO^(?_kD?@DE&u`MN zIxWW5mFo`%H-9y3%nV6eSe7F?Yu=aK2bldmn|UTdr9C-5a{@9ac%gawZS7)kCSL)& zA@af;Fl}I=@X30#cA_1gRT-4{j3~X{9N-pPvmKzsPL0Agz($5b6VUBcP(>O>kG*t1 zm?~P&!Sa)n?ioagvX+~|Jo?j0jPoaxbaizjVjU);IXDJT>6)(DH}^REYL*Py6D9(G zRSo(KiuRMFC!Aa{0G}d@p{l^kDp#rKEy;$MkCLzpbbfkCySo7{ytwojv@-OdTeO=< zy1?^dd@(p$Ija#Na*4l>U=v(A2j#jr;isz|eWz%UZY40lwuo~TxMQi^nfP$a@XwatWUpOKCozlE8mK)&(k}scNg?q>lff0 zecbDm&vPJ%35k7$hm8yYC=6M*xqVy;|KGCpCk-cYQ=S==1FIC9^)uWIKII4f?S3|AvuegHYyiC_vmW)(JNn z!mbtP4{EN+cd%jr(vHs==^JZsVRPEIdoxns?m-U-jK)4T_ zGk@=;a7j2LMcv{TPEha|j@^KO$5hW}|16)xbXpvLU2RJIrulL$xyo&vDg4ke|J_*E z8)e^tkgg2{z6Q) zL;G%8APocIwma~YZEgcSm3ya+Ho7d;4oTtrZdR`hI3fcXt zO%R^=L@1jtx;tO)y(YMQw>MA2C>~{1&aku0q?l4iY9QvJS*O$t7+|vYvoi(@QRuKR zhMQRs=ZsS@gDbN~^9CxkW2D`Csobc)W;c)pS_lpk^coLSxfGq*7*@8j&akVk8g>aA z5*IDn;ve1mII(AW&NJd_9PY~(9#90jZlyPbOMi0a9Qajq=R2lB`3MNEp@vtg74uh` zDfMx4j}*%`H`&8>*-$~7C3yG zrgkmm1a%(zEVfYwSdd!Ec7}p_Ic@Fu0gJi2_8Z$_>YT+Jv&`co9vhoW)(C11RtbNQ z`O!r!m)_;_3OzTKu;~C3bCW7!>gfD1@N#&tsO}QK$&%TE{k9L0#YQnn!`ckzg7YqG ze=kw7IxYA0+so?Y)a@J^_=e+eq2ddSH-a6PTzi&mMz=-ApRDqeTr`+I zAAJw)L|69WUQKs4gHW66Kt9DTlb^=c^E6tLhEt8Q&fh>dx zxM!sXqQJR+ZPZ?=ENb@05YhHjP!*qXcNQX8?w%q#(KaluOx*_p`-ipB_bgFP+nv0i z<}uf8{An7Pid7K})n8rxOLY^~*}wXyqilywmGf8Hh!dDOocEiqZ8v2wUULM?4myhJ zS;+fOqulwtGmDJaK`aaby}`q@n(ASM^g=fxB91jn%TQ@95QGfVenqbcsqHMS?Ibw}^tk;0YFY-$Kr+>NHQbcvYTY~9r1UENhElBL|9 z%XWRBEogd;y(4J?gjnup+>s0*>o8l+(0Kk24*$&;_=yK{ot+mLHpA{&PJ#}%3*$qj zHBw_WzCZD9G2(lr+VthV8?fyDfX&*jRR#*n#fx5#S9ZwFQ@FOw25s)7-^UN5f8=vc z)5;C3f8Qi%%a0Boy{qo1QZ4<6YcSO@M={^VnX}f*cxgMpT+*kQCvrx7dwcsJ9|C%e zt%9bBX%>?zQ*@CLTDJRzwBw)8Y^*MMkO)T*A=z#-(-tq_dRXUni&MC~QRka~mB{?^ zo0_{+tz@m^&&kzle@@-yUJ}m-FS6L|%u2sa(!a5FeqNaIbYD5RGItESVQr_Qg5mqf zeS@uUbU3L6+6g&v!V)7t2lCI=OEOTAGrrZl8t0?>!V?Nd3nyX-fAUmVsKYk0a+A`s zQ>jwC)aaQ?#%rWo6mB_zu#N$7s?3MwG8u<;-%tJnS&HKK#sfSOH?MdT<4t4pPoo@p z2L-x_>2T+sCuKccZ)?cz{R}TdBv^4n7F>Jc1(RI%9lnUa&Wd%_4jOPA7I}F_?95Iq zBqhq?)x~nVPfh?TP{Sew157)r1Hak_>@D`*ru3`f8w(yxJ7*yWrixcxLK$K{P-mBI z=;!8IO(an^pokEp}UM>*puTPsXvfUHuPfbxhu1XX(COBYKW;{uvM*lTmO7+76 zhIPhd6EEX}ykvjMoM5XrxIj!R>Psgp+%eVoTtP@TQhK1}|dsK;_1`S?Ip5#?&NTPdG{&6}%3_gw7G zDf@aJ8yjU>`En#{7Jw$QWC@@1h=m&0hYKsjK-`E?cnoH_vFY>nWbP)6-Q9>Z4#F|a zsDI5~>kcuoSf!Cwwl~fG1Oj7*UXSdTXX@(e0;A?lO0nRmm_g7fH=}!JQ(XTA4)Qxvk?%r(SJb;~ z=!8;0o06t$IWE-~_{Rj-&JV;pQ|~J4;i>dJf>xBKHz1RLTAuyY?>2ISKF2|VY`-N; z^o}+Xc)*g1KPK=MWsiwP%H{R4ytnv^cD_YmFl8-A60{pcMXRPI*TsaBl~B+1Wk zkbSGA)yzlylD|fxad|jCIH`?!iuy$7HJl+OScp=;v#E_re3OwffN-^M^Go1J&ye2G zb&xhfImi0sdupw3mFt8ai{Bpw|Ihyo5skCLgtR_7Fv$axQz@7^Mhw;~FEEkdh^iEb zvd2HTCJk1xf5L(XW{FLRmOZNC=lKECMPYT6V^oXZUKd@_M-N#?U&r2FvU~b zy>&i`Q^$m8gx6~^^uK?1rk;M(`&GnyI*mEw@emH0A8owD4yE_^+k zIy*itp|6yztEUIrfpQ_E>v3U2O3oQjL^7|Z_Fo0`_ycM{8Ag6$xpvHjhS~!ZL5TZT z{O88~CydL7V=5>R(?1=o{w6fk0YT7Q41`yrj95MP$Fd(Gem}Fua8hyc z@MN6hFUW_>6Ja7lei$Cf0rU~c@)?*fxfF1S0cqCHWHihWwcK9Gr7&D2$Jq}WF3_V) zQ3vg}ZO4Z+-`Fns&LBR;_SI5qGFuw3B}}-a8HX-YEClCVAUbsk9^r6+oaZC9dY8y) zoTNtHcWF4OYtpqc`8%**7;qQO3KornSUPPSq|r{~mx3cs8KXBe4+Add1v*{DZb#C# zzmB>&%19pAHYc$t*+Qlc6xWaURo1DmPJq^fhVewn7o@|pZ|}420jbLpN}@qx<@;)B zySV=rwYQ60M~-})7~Urgcs{-FEq;c6aOp6=be_yp2q$L)_D8NPjqAAbdVL&`DS13^ z!C|h>I3JVm5cSE{vkiNN$tL;(nKBb$p<9~RwUFF9_@_w|V9(wH_s~4A@2`-neEJ?c zb>7xb)TTk`k>Zs&q|y>^@G-MZ0b2oIUQf?3pdOFQ9wbkx>r4GK+#wYDxG4XMf*0ha zma)o`ZV;cZM5h^=C+^RHeo`iz&7>R#fu>qbK8m8EWI4FmP=wY~rFhlIT4I;IS4SR< z{5u>eaHFrQjjn#*qt|DcrR+yjZ)*6|HXoV1{3#kz0?Rzm!` zXeY!LjJh6A-ro8P>mC5Y31{ug$H-U+y$wYuGKlBp=iTBg@QmG;7TF_8MZ>BV75&|$ zmu8mt-H@t>JhzX#)c$p4ktitWh?M@QcY?CvP@GraT45X>@lZ_8g;5qi{jn3ViX*Zbpi@dY*Lo;v87o z8Q2w4_U98H)JLSMm0M{C#B@{wtJNRQ?I|cn{(o0UEKG>+{qSnGgUhZs5R%Zmz%&Ur zsnTl^M5!yQt4TR=5-TgKiPYIpr3`hwtkopFRsFoj>BN2SL2>f;4j8$AzVR;f`_IZy zDOnp7m)R4oJd39mJqZ+(B_^^_#v>lI)j15x0C&ll^!3}k)MjD_cetIyt*$v6 zvzHoD{HAL=X|(y}VuJHen8N9{NtGIus@d+_9b$I|I`%t(cE8 zDfNu)ax7*b^yP4MokqDhJol={W433O?iCi6iN}-o^pF|4!2kl?o32$odZ`Kf`wF`Q zK`sw>5gkDer+U$5SWKWNB+d;J{ra+!2ag{0ic;g!g3e3|;lSo~Id7PN{^@Fw?8e=b zb+g>YNuLX{gM(=^c?O^n+@=bHP9NBh)jE+e$Ew!?#5covJnV9LGJHtQK|X~PS-aUeOEZmv*tLYqG_xCKK+Q_R5^FNkGCQkMI3gSt= zda^GDsx#4088@l!P!4Yw0>g^VHQ6DO_dM!E+gXp#z=lFyG+#*dN6d#@cs$Xck1ro? zy0@~5C-bBpJGBuB!x7cDMq+VR%%u14&)Dr$o8muLF3gkLR4Q&WoF45g&ELc^e4(lN zw!16RF46Q;758!rItekstR%6B>hCJiCQDs+0WX?Ds~YxZ2Oek0lu;30ekB2 znQqDa!pckR=^(C&LiU%EXbd^=xF8%UqUk%aMXeiw1QwiHwn^5Ds?r*2wq0S98gs)q zL#{6T?aIQ3d0g0fNlk%iJ#rstvE;Sk~7LNzpEH$3OV+5s6Uj?%TJFW+k8Cvt73uH+ee0f_2>S4&?z4W z+EF=`KCei*_&UX;tE7 zh#0V{arMCebg{YUm?k`L`_YDL-=||}w`G0SLoZo7igtjVLng}R<~x!|R-7>QO-mwJ&SNs`vAkiOQe{6>!dH%U+eUyPd-qY*pv{T zT(m*vlca}iV2i=N4#&00)9W$zmHoHRq zkFf8KYieuORuGgX77zsy6-5C7=~9CtpeVgb2k9jsy*Ck1Kv1N&(0d3q)DRHqO-g8? zcL+sF5+DS=t>-=W-tXR{=fC`t?7hm&nl)?9%=0*HwZQ9rxuvq_$5!)F>b{pJq*|>q zcvMU!BbMb#Gk0m=d?TX4O#H_zm--)*X!T15JmLOR!NE_JOp~RE2B-udb5v2r_?E5& zrPrhK1jIEg*LFvi#&(Y0K4Hq?5LouE+lemLTns8&cgv`CjsaLm%#dHOj>-lJ>~A=g z$4Ky*uWB$^CZqP+`dzP=gODfOHJnZxELbR{Aq6#Rw*^cdzso4JA=#Wm*bIV*7;eTN=AIUJ710!Mh+!@vDrE%|6yHU`WAY7 zq#GM=AY3#wPNadk^phVNHRqYpmJZP6*RufT}M9A&zFa} zEONjiBXR;booqtRlLK(QrPAm_xjPTdwn#^2w^WJ4e#bShVz~(;#i6DBtX9<3c%&c73^pfR*-Td$dR#gdRC}NnS4E z<5XEaRAW;z1L|(>Gs_3618xFQx{rmrpbQd$}H(VtEE53<+? z+P8s1w%sjk29WPPkRgK_d;CB^#I7LRpF(-jV>(ziXTdDtwhVU>od{Z#@G*x%BH_)K z;Ius|C1O73%dwj=2Ix=Gz;T6-<|+L`(s%WA3bll^80er;G<#L^np;NBgxDUH+SWJ~ z*ot4vLgx$&e3nOG@o?1Mg_V^|NwgKfWnGLr*adH20n!BlNMy34EN|vSr6_|!t)yk* znuLA15ID=1SSG>K!78tTd{~ANntDNU*L%_?iR|IdUPkc!fK-P8!;1-%lK?( zT&8Q?=yPL~L7l@J58+E3{v3RumB6>->9%Cw5(n7-*CHoXo;FY`m7MST%OOl@MyI9Sl(AZ$K`=Y@Mo_F-zA8;>R z>Fv8sH}d~n+MeefF#03fZZcP{B>95IB9aHS`T+p7RU9L{9w3kEc9BQ#Tb=6+lOBUi zg{m?755PDPF}ZuS?ZG*G-IVHNI#zQUIWN0wQJh)IT6Oz;SsjH9CHn)D>Zqju0=M|h&^sB!W_K?;xN5?ELtg~bs3bs%z>#r@mhy7qfU9{|L*tqn973V&A-BCjs4#$- zd5+WiAtG;ZzoCCXg}edAEESBnUPqjZ8GoAv`r4;39{q2c{NMGZYU~d^Vyp&pI)Ke( zy&KT!K;gVZ@v>L`^2<=;+m|f{?3u8BLf;pnUch^EKGvtH&1vKT(XI0FXziEsXw&%F z37n76O|t+20s3pxk{x>Jn7oPsg6dFjvt*y^`=j^6WYVflSDG9VsgfqKJ_=~Na+eh< zla2XGY%6ty%9IT=zU>uMPb8 z;x_fUpS8Gb5IS8FAbx;LLYb|x_c*Oi`*jdt2xGJzg6KL>>a-kv7&BzK9;4MIXO93U zO=7#xSfM=UqiVDCl>9l&I2bj(0!Cxv<$WJ-lSmamu*Ci|rj$6%3sHrLA-@RzkUHJrxk?mFbQ`5B*QD?p9Z+{_;@nDeqp z?gr)NC_%VuYHCzR)*r~cFNi&k%GxjE2adT4y=~so*C-xXfxPS+phG{Rd@ZcDh!?(8 z=|gO`0Nz5bT%mrrC$|8n!q^Gm&1*uw|A>b7JA#eSW0!WD#lIEepJ=?H4dnI125o+8y z>1>dwnU*N#6sz|gukI(gA!avk*j87K{Twn!uZ1boSURbh@|gTsHnR*_96iqM*qp={ z4#V!b?x-OXAFu`|n}kKOd^e21Ks=4OU5jRjE3>SN&BD`VGWdocMHI@F=QZOnwOpLa zFR?AT?qg{5_@~conceC4c$^o=Qf-wxhh<1qKMNV$?*t;+$QJ65-1-YKcFW5W z!iVe1X&qkil0t9X4F}eo0_92|b*@f8M&gDTJ+1QU)ncDF^(&RaRVzMgT7$mvc1-p* zZ)FczV!3>RkWii3f^Rdu4P=BRd37vk#tY%7mrXXHwpI`BwR;*Mc zX1@10OrY7z>@c~peBDChP9vRF(MARlfvW{WxFVB#J~CwRu_OTDg&PL(^010tv5>>~ zWls~E6p@J#(*@g9qmz~QlDbSak}aU5<_!{9rytb7kC@PTQOtnD$MVmqAEq{2Gh#qM zUx@L|w;K0swvy_^XaTu3yREyMtTeaH48%6_z{B)Dj6tgbzmE_j4}$!Zo|Y0jfYLq;q$N*|jRFm%?fb=3uP zxnM?UgazFEc#dC~zf5`ERkb=HlPF}v!QZ```XJQJr3nQi64gF1YN2Z8;G) z;5e`8J1tl^+`gbB3E%aY{jd$MNBa_<;iWytG45MQ!MFVgiwrgudoZLa@d}rj*RH6r zE#fn%xUPC}fOCO3f`Fc8@m{=pIZYnm3)=vKpys`Tij9PDPMc5nv_VXYjse+?7Wp^_ zNKvuho~^$^w(H=ruUp+(G;@C;z&5urkMf#jXCB1yf-(!`Y96XDd@T35-8Zs)24bA# z&L4)0+#4(A6_zO+rbbAESt{&r#1>kuXiflrsZWI<`BUzv0;B(h6Fj^J@i<>x11 z$vr_<3G6{jMLv5B>d2}JEF8kzK4n8%#}~uy7&$VvDWYRb%Z!e|P&%7#l`Qt_YT5QN zZVq@HT^N&x?Yef5s;BoZu^qjHD*Q+rjrdH+AH03K09?h(>9`Wtk&S^EjjA&A^(gdF zsymr?f4bF{Y6L;zo6dGDR!u|?=xrhvH9d~E?}5>*ijNG)^&Ly6mHa^DH(bKIBOk=L zp*E_XSNY)JSh-DjNRdtgCwLql<0N-pn3I(Tj`y{2DlMnb{CHJtd{dk8!3f4)@(-zO(~ZlWdVYS5&U{--DYfDD~NtXQ(B8b&naeMVWE1{aqwgZ z)QzRJkYr~^-jHE>I=aMDF;y`J%Nt){nskE_tI(5)JJ1|OLesD-AHiykp%=5(H3|W8 z(Gw-5$(enMd=vyx8FT1@9SFmtTj%^!N9iqw5Te!zC}t380Snc?ny_MfIas_RJrS0sq}hI4lIz~ zUwVY7$Y8ef?U6)JTr^M5qb83t7#IR`ewC5plhuJ=S6tUvTgp{N9-Pa1*+?p%s zTL@ns6=8m}Z_KwIymBQ{SkL=IJ$}swzF}ft&&C8!Y&eCAJ(Krji%b~x;^riT>UrB> zq_cwPf!sp##H8HXI=kxPxLjXO=`h*2bqbC6>Z4l5m}85o({S27&E$a>y2X8w7!4@G#K#=Wf=;~B41UWzC|!IU$A+0S+>m3 zOZJii_vk{e(4%acZV+H+&)aHd?6e6rkCsH|SDBzA#&4*V%9oPQBEIOwBUL#G7rZMaI9YrpTW=CzxDM8HuzFI% zW=^OB@~#iCEDZ-adOlM@INuQjK8mSZ{^beu6?fZ~TN=e>XvLxu@}#)JvNC;oxg@3T z&_&06sfD5AmK@7nnI#G0;TI*dz4x5N!^d&wzhoY!+7gbjK-J!EUZ&aDv>%$VTYR0H zkT|0{&!%9yS)}ba8N@(H&$wtJ*CBb9#TIQ9Z!`4cGfu~Ey@Fup7)qfH9`(F@;I;}f z#~`7m$9=n5)3-vcT+%Q^tHIf>N~1Ul{3oj72Gz2%^2JJv)Gu;&$Y!_`sQ0?( zXJ=4F+ym{s5OE{Tki;F7sctq9H#U(S!vNR$H6`|-@}QY2+;Pc##OKT8$+x(K$J^i4 z9mn#TR~9Kv`Hl=TTWLm#5<czAE z@n9ROU1_soWig6Y3#N{32<&szz=_Wjwul<-6*HXl+!#BK@=Ld!;P($3GIxZ4fIL_rGJ+UiRxSmycF2 zWeQ%E?R;p=?iHVITQf``I(r$~3vzfF+f8(;Y&!Hi-FZaMUShJkjIf!x@w(TJT9@wN zqTMq6Axv?3DRMrJysixqf%~AV@Mm^Bsk@XzLqDP~X*%C5sF>H9L+fPU&~WsZpO;_q zo8nM0-~4>)OYo=ell57$DCbIcu0ea?1aQD$@S&4R!764%QZ#3JI%4T#=EmL|Frsdy zFQYwFv;Wcvt7!4Cl^>7PA~<`*jIfcRe;b?rR$%(&fo~$SLmjwE(D1PJfKRli?}flb zvNKf5?5(8*?gLU@WxbrI7H56gm9mO?*w6pv@&0A>-crbB+?M2tYHIDtX)izAkFG5I z^Ls(TBF?$`ckmz{J(r_v#KrJ1?sF(VBlx?zLvNmFl-Y>B>E3+g_~A&Zho&9k^*e;5 z#W(tl*^HTVG}&6{E69oQbK)g=6c*Zd^@!YQ# z&t7>MR%tWbZiP7iWt!nZ#fBkd2RZ~b?6boz8$dM0cel@$J?@Hye>~pb+~ryLs)kq= zoHQc!I4+MQ*4l#zdfaPnwFnS){Z>YyGg+iyp=MY3R&J;B<;L+0pR;37LPL{v&Dz8+ zaIl-IFq=>Hd?LD0or!2T&Insfc@7)J+?)0oERw3U$}{w^8wXfKJoZ;~X~^U+Z+;+8 zouHx#dH?nV)KYma0tUrSnSWY8>nAX}&^mmmEQa7W6I#!r#|`_ClOHBUZWOFpn>7vvs@w%1P8Xa; zM9QyX4NW!8*IZsclEM;>3>UwVdX645PB?Hrb$Q6?JPC%s@9OS6|8df$Erkf=fhblQ zV?Ih_J)P!`&nBGeC(%9L3}@-Ss%=i6e{rYtorUdK;k1GfdP_#@Ygy1zn^8Fe670X{ z?uVoH@^#4|hXtcC0p^v3CIqj?w{Z?yYAsesZa^dd=r&4%( zs!o>5`xY|P5F?XY*J+e#&SMpv%gwRY+D5jm`aUTy3B$U)FSPLETc4zD<1pOU83BF| zLacTG5T?BSqVwW8%4qiX`H)is!mdTeca^TtM?U=496;8MZ@YdhBdlJrEzHsAT zVxZ5eq!ehC@)=GSIG+qhgT+Bo*^`0~7lMK_c<+Lqnl_YFjOb(=+RCO{aI^Ztev`rtVtaYt7g__qW&_YM4l`gL#OvA$Ig%*pkU9ghMxFq_F^P&Uj0-n($t;?6zygo5d4s4tW znVbPou43vM4imAJm~>8lmnky~EwjGO%7QU|h__`|tG*LL9KT|c?%H7|V4AIamV9|& z(3amF@bKs`uEYIoQn*Pv-Qx%#%CN973LGGa6Gg$OJ_EcM-c|&=zJIzvWYD7B3)a9^ z?ibGu>PcP=nSD#k=z+Feo$4yD#l216fm6I&-5&DVYHtM#Q3!F3xDdz{I#H0`bLu%# zL1&yuSOWXENrM6y@~{R9+nysMDV0gYc4`4stulf<(Ux_q96hy0J9y8*UB2xHn^{Q2 z#3=4_-`)(rbIIs(Z5*8)!&NmNm-CyCKWl9q-W8K0+_91Q8*21_r_KEp`IM5O918vs zeF!8)wNGaZwVem*4U&KhsKR#Pq@_;sck57wXJwo(EWfm;pU$57eE(^-$=WN|ymp2x zZUPt&9{PX>DO-F_Nqd24CQ1cF(CJcY#m0Puq9{|+BNJs zqK`sVs@j_nk@ttOBQ?7VS)>S!3g;l`3%mL$_;dA5a`!jg;GOmjw{bKYa)U?Tl?LE< zv(boLmL#^r>-P8f7kBZ~Zqm{24NJWaW%hkHR0s5&(*op}SwXTS>RUaB{j|zH#8nH& zk&HrRvPhr^`7$39H%!r+?bW&=1{Y*!R>;}*F@{KsB~jOcxTUkCc^(D= z(eEVZVkv+_+>f+6Z;WI%QkS4JAL277Ff{BNf4_U-t>UaI%)>UtD-{%7^F7yNajEl2 z36@E`U8q7vKGI-!efJ`>oxNn0zJA4vwbKRPIU~DU6gfm+eb8!w7`|p;{AXGJojRYT zk_La58y$X1gVE2SlUE%`Xe1A-f1?6q6R^xZQ5TvpZMcACNxpc_z$3`_JqKSn^9Ugn zB~;S)o##1`SD>E$aC}g*Pk`OkeK+h(T_}p2@-|GS4S=eVF?g9)>bBa7<9vG=h@c^X z>tnd;G?kKw0-N8CRo>iDq3kor7bVJ=)sIy4tJt&VNeK5_g-%NAoYTI?K|&W9-Z8#e zP~n>=SY;TeI?O{VTsnL!&;@~}%cfd2r%*ms5klzQNt4{-*}RWJ;4kZD@!)Nt&#f52 z{O_kwg_j{;n0RW2AR)o+u4sG1u?!!tI6c)Xwg3-;!1;C99Di$?H=6 z4wa8*&Q;Mo&3;*BnIbHkraRDOiOlNB`*S@*-l>3bx>Qw3hBW!7V?cmLSpzt^NEBU} zq@z+^wNY}R=O9uF912=yT!<0c(Xn!GC6B(1KYXBX-We2I5mN_u!G#ptrh_x?mTI*S zp6XhrAcG(^Q@mv)8Wl3@8hi9D!_kY!X!a>e^^_{k1`>@jkGMtcj>GN_g%L`1Q0Hoh z2dDDtu&vg#gKk;dl|nDVqSiuzQ(qO3#~15E)g$C(SDCR4B0SZxt1!;%dyID3#@PEE zJ|9cR6sI4e0B>ow&UIHS-*eH1=a~zka-{3sSr$0h@NkWPEKMd%8TnNBOKR$U;Trlp z*=Y`mxgsfSSh18#W0UJS8d`nEu^T)pHD1G{wIrx&vGon+%g$s4`g$=Ebt46w$`U7I zZSeKXs;SRiz2aR4hF*B)GJD#sn)C<nhnGHj!elO*< zoCLAnDSNtRmOihTS9cq6@HGtXyW%p^dGX$L8`xxI8c_qd3?$NSm=zWe(B~O=ju|NJ z|B%p3b2Lh}DU$M(e)L@Oj0ssFq_ouKGvTR|lRg5KnbGIGq5lEl_7QB{O{wyk77Thx z?@}Kw)FH_p_SB zK7c#Y8b=F~M;e5nYn+9fuIkgXqfA>K(G?s2&Juw0eUywR}X>gBckEq6mRuvih;m972P$jYI4Td3RR;| zZuk)C^L3G_Q{yHsn;h4i_e!Jc__W|-zG5P7-{=P_4#)v7W8cY{xF?>5KUrwAN0!U5 z^d_*60m0VdB^R8-z44vNx~+Rv;z#}nS5R<@q?Dw`vc4B#CX2z$W>?Scfg${*;%fhk zD<`GxSM+__9*v!pJo8^m-d%(~^S7RpV|j+@8K?>}3?a9jU7jNCMLoWGl%N%Rt?r^c z6Ylx&)KdCHqq*v)DuE7@`%!@uHes`BDA#F1h?W%3=HqQDx>_`9Q7t03y!7$nAlE8* zJ^ne9+TYl;|C}}WNhko|`s!RCE8lSMNfM58T_Sk9(b3Vh{|D%nQNZ#hvzTjiQPBe} zuBI7{U#P30VMY6-Z&Wa30Q_b?0HL^WHriHY?m`T12TfiKPVik`^J~uMLTraoy0Ajp z0jXJD*MiQ!3w}e-Yk}ql(w%c^{FvP9xu_bhAXP#c1VyB>15!z8K@Za3*$p}mXp<5f z2f5;C;}{@U?a>f%%QWiiLh5@b9Vrg(_6cThwLL9Q$pU^Q3@Tr5v@3moDEZUYU zGTuMN_rNd}$kb2sbe-ym$Oj#smwb^}HLe^1kh7Kty@rbu+B1)@_#FBsJK~J^Aw7$^ z*Z3DVlk7eN;f`&>rL-OPYN@m#lBSzV91xG~8yBv#`XYQO+kDqNxTJk1&pa{a(8_yU z@C?%aD!m~`eoLQeBm3kvfV*+=E3tmtM5}bb70BxIH1QN%%3WoI;#;>d^40Hgoawhv z|19Uf6Va^b_YW~JaIpUmbsg<%4`c$U%Lk%6&bFL5@*Z%gAHEw1$y=}QW`J@}WSO|1 z)R)bSR5y7Xj5Lu?(Y+?o#!(#8Zdhog9r`A6q0_%{9UT>0)#O>7F3=wI{iH_w{CZ-j zj29N&QRW-Av_l-3Zci|8VU}2#YjKZdV$kqfxBZ2hQNT4g z5V@35yHt!`^lv_2DOh`ZG>NCd6b2F8^279ue{<#9l>lP82@w&3&(Z{%SeVR1i7Sy4 zXWJ+Y2o(2iaz2t4N|Uux;v7bvH>-)Ju5OKw&u&ECel93Zf9)$q$F`_(AtSI2!66w^ z-Sao3?{D%s^G=L)8dB&JV8IqjA436)h<&%NW4PMa9da2a( zGL{NdQ_jpj0N>}Y-#(hnjQm)~7-I+)ecBd@8|I@?R`_rRsC-T@pO)dt@Ojc=Rd+D_ zE^u$f7A`VKpD>JyD_f!c(XJxJY&kr%s`4>2ji$o>408?cYkCF%GA$h_P0C%X9D(sm%6NzIGZ01a>@_H-I@OJP@eKx3$Ey%SVTq1jOTXTFXzof8g=)x72}q_*$gtl08o5cp!3F7f)F$#m>_YtwT!&DVVG06j%53OQ(A)N8}Ob1$e>yeEbN?5tS~zuN*JSwPX;xmfR5XygehdWLIM( zH_4a)fnD01gn(kkx-6x16h`b37TnwXq8q<|IYEJEgHtuX&{ZPzrk( z4cj2q0wStM4MyoeCa;!Gr5&@52z!6Hqt;UA+_YaD;0AVhVqiR6LbmKhi9oT#X^hT2FOtvU6Ze~ zAS;m1TzYJE;ThgS`H0=)^qn{r`61b^%RO?Sug#oNGN2)%WPe6H{PR6>P);S3Mn-0B zk8X7<(xOnFA(fKaq%DlO>wLmo`DOzGEJvq&R?ZgX^}Jn*wy*$r^I!O z9&>`b0)X=0GDr$6S~l$HC>k0T-DX}eVOpuMe)Smf0wlv|<1xc)ckbl+ z#xlbJgHA4|a!dz76R32+V>owikGyj+?@k7y+ryv1a3Cf^o@c(u4Qr3n zF*ey6F=p~3D-dotfqzYHZba!C6_P6y;Hivo=c1(>4eQx2m~&WFn?An9vrKn1^zr;U zp6U$bsH{;M!F!u*Nf!OCvx4KHY=zAZkQo!^V_+hf7wnh zzo$`NZQOpM{w{YwwpZ$OKr{e-VG#Ii$uGT`mYb}>0>xLp8UePzY?vK^4~~w<$19xh zo3>QaN&>>AU*1Ej6f!QON(H0@{brv4Q25yc*3DN2Jm>FlE}k(6JD>7(ey+Qb^RTCA zqI{*VrR?~yC##1o2}ldOA5;DIl*Vf&>kOdGIpc~R>iTKW)odR2!&1#0hF7YOo`vvC zu^lRFS@iYKz4pnNkLTP4jr1Ln%^IQ^E?jFy)iGqlMBv@1RS^Sy)4cDyog`Q6*JsLW z{$kVmUBPJHt6!kXuYZ9mzn%^p7xx5Ej4$;6P<6Nh>!p&e(Lws$bYJMy`_###h3wr! zE>%ochS^|RskjB{p}XXfQ*t`FpX>%C$;g7rzS;^3xlQ%KGmD>~(tKNrpDb!Z2F}85 z>VgF9hTfmjSO9bOSWV+}37pCZk&U_m=WH<7&+_xIDO&^U4!C)X$vl&Mm}a|99$7C{W5Iuk|^vIFq5*3O9AMwDesjf%V~{@8ZIRsjY3${pL2= z63RV#n*Q_aXXnx{Kcl`Y<;j=Nzni+;Jt0=rJCWeESwTQ}^Wl?okNTV%EY5%+N0NQ3 zUawbul*4cy9ry9`oJ;zW zQonS=$$7t33D%8!oG)a4=1g8|ccwEdDc#i-KQ+gI%+6g$#9ia;)FnOpv572JICe80 zCBb)GBp@{P+RDq$&dTeSTz11m;_Ik_D$umfBgFLl)B*9l;6DxhKa-Jmngl3qI8VTD zZB^|=-F-12rGX@+x%u!^z-eG&CiT9v9~5@JoqvmqqEowWI6>D}(6<4dc4BDx5>~8T zkAB*>|5mUyztrI9vRk^SdmgLpXffb8T;a$C3j z@ITv!CnUYqbLS%iSCez)h)nYJ5fmV)1LO7gBm^(bIPN{NUv*vT*k^z_5l$d{>jXZSY~LVKbp-cf!r8Nzd!R#qn{$)Oe5_?v1PZtE2aELwuR9v<_uq6B?8OQN555BlAu~Syj)R{%!o_xk}BKC+bdUzVK62LU6vQXq2+XrQ}Ym7PZYHk1Fxz z@m;5*u95v*t}!c)hGL%JoK~!N74BVb@Gg(#)_6JRf!C5Gb>VdC4H8zJn+>&?{SGy` zJw~nwDU&nS1UJu?6Wkte<=lQM)5<1iYO+}2BUmo~=GRw8tDAX`a*d3#k0-DL#vRYM z;xkg;a`>>|dbhli|6sHL*|io+NlMY%mp(b4FHEh`k|vy|E-8jARP)f%se0m68#28cV6gvleJ{^g5C?hgoP(B@V`@e2Y3fqCNDO6#w4GuTc*5o3QX8WY=ZgJ|w8iq}roabPOfTGsEo#?kJEgo-r#t;Uq zG?uSG?})G$s|=xa^B|dXj6~{Th2N{4lz(G9{mOae7BuI%eY)#Q_Voe}qqkN>RyJS) zbvI2>gOg$nbyA!4JL{Xn6Y&E!T4FrR5Gs`xocjcknN?$nUwLbPr)5FMvu!Ul7c4=_fxUOq(nDK30omfFkaelT_bT>w6|4OmRB-0;u&OkL z^zXLHU$VMNO2XA~{^jrGBPd-4|>%vPP3@8i$MY(qoSOlhIbXUmHd zxlJzo>|Xe*fX~-^*$s5J{7A#lgUPB>RTVrND=9jH`_YA}4!#YZ_{WvJWO2{C=p#AT zxbjEwRt_l*ZEFA>)<1X}|50@#TdD<8^=+ZS5~atl^Jhw)rN=5OZ^w7Wgtn^RP^FV9 z;LEZE*F4o!*@(KRNb%EnOO>D7BM&;HWulK*NzuBk@i1>Ke!>eEm5*xM8-@zy%%}nx z0eTUC6kGeNn-t0}Y<{3ICI$IGIYcg*M2l9jVA_yaahjz=e#R$t6cwA3r;Q6kog7V3YJYY8chg`=8ITHWJ0qL^Dw40%lZ6WsZ8{^j0t?+=KA(;9kTD_L z(7BSgh6szwNJznzr*#)+{t}1)q;W?2F;QEiaKb)5&*(MM#LG2h%})<+O<>e|GxoAs zZM)M)zX~Kr{Ih;21OUE!ebbb`GNb95gu+(Cf&h;yoo8p2rsVw_y3p77iMi6}y3@^r z&&{0VV^yR-L|yw!6pigy?o(dZc(vyLM4GJS5Tf<)QH|Znd>w-pSkIx-)OJ8w9B%tG zs17=%u2*>YNaBy(5Qvikt|F(r?Z4fpVa2BA@ZHUo(IE!KQJ!Up+$glh7tL);#2i92 z-8+sPT67MkY-!1BzS%OQGyc>h>U=35UPu5}WwEkyP|&a@%9x5J{TH!uqg zw%`0y9UY*j6$ImdrvyKD?Ep3aS~D%wZ7S($=UIQxBuYP^gc*D$FGyYH} zjy|3ngIgIdg2nz?SDCVD!QuTgZ=bdVoz=-iZp)y&6hoKkK3*M~zh5kzcZm(alKlPp z100@1fETfDljh+fsXRh~{Y8h>H2^_GTL~N7>2z2(AcfIj0p+DO@z^WJ@dL12BxhvP zrHI;TzV@}pCCUf4&+3-LJj}FKt?s9)2^CBec$k&-U=<@G|8q+J?^29G- zSbYFc8Ui%Jo6Y8zT@3UTs4Oy54pR857r#+pqizanAo{t55KfDx z<--asI&cUq5**JS9MlAhHrT*4x;ochz0d#kw9)7pYpNS&%nu4G4aU|y8AF%jJ~Bp| zJM=t`dH8F7|L<)5^-TcVrKOyr=8jCxuximCu-NgzP{Q@t~AmPAJ;VtFa0%& z`bOn@u9LqF$bl~&8PsF2FuFBX|uW&5M+`#p;!@SO5uR_MIS!6#J*C(-IBYQ@j` z-5O+73NQaPwMNxs=p?-y&h?D^Z(R4@7GFuwe~egWqC3)RrYw9XFtw#=Pd zd2>q>Gf~9CogNL^9c)3wcL0X%XQxfsAC5j$Mcr2?4OH81I9oUMpl9gMGrmV@3c#ER z8>Yr~o`rPQsX{q=i1JGqoY=srzdDrmZs*;~fnP4BO{ zv*ZW}Cs7wE-+84j`9pmwMzLTZne)}4+cBfyN1^w>x++j5btNEEl2w`BEx9uRFTyXJ zx3u+OGkYoQ8bC7e>n;Dd;2PuU+8;^9@N-1UEJ`ab>eoD{$CY-v(H!3Nn|!SG@bj-n z!?^=wgF+9(CFz|t8+@Dm!yj=P-picp{Ilc)NN6aP7mqpzRb>Klb~Y!z?bSgxGfF>- zvg_Dqa%TWcr-0_&zi^ekDb1HviHwv3R%0a9L^N}Fb>OM3t{M1;UY`muzij!O$wGI8^2jcqnJD1SMD}Xph8q^5&HZ(ouJj*ITyFr@q=j^DjDCrk>Nz0Kf8KI~V6@hMwKfM1m3F|YX)~sgP z@74u8cafwT*|(Z6=Y(>yM+(uCqzY+8cC3-O>u)O!|)8H_~{laQSDy!r23ScN7AtZe!Id z0{jDY?MWH31pe4z(o0v>04{)KB6&3VH~t?@En>@a#ENEK6D^w0OMAUqkTP#?SXW)I1~WD^-wKF{A#UZ+^F@ z$-)}rfn!D+-_WgsLsIojd|XH8FYRf3MSmfgu~2E)=T95rIpglLd5*Lmd2iK$iFcU( zYY@&<=M+9}E?Z##BrR)tOMuLb{aGf71`w4W=>4nJl?xZ*8JYV!IR4}SnsR-wI9>3h z{XsL(YEW6kUyrt5xsb>>*4MW7Cl#R%0$?OQI3kQWP8VDPU=n}+*XSJu(BG1?uSNdU z-(YP3eK+##!}y0Wr!-j7YJauT_z-xM=5l@4pDq!uk^xsyf|6M}Kf5dVmQnVXdN4k? z3HVktu_{Gzw3q)_2W-9}2GN56R#9_jdGcM9>M@~@0N7#RPd-%VUSc;g z|Li!}0*{tCbZg~bN$aG2^E;*c{{__e{^EtS&V7}0%4XCB*MHls|IyB@lbaQ%d@!LY0qc?gsFXDx5R9|^atiPEJJ(%4K z;y-JU6~OQ7y&A^!N`FvPm?j$q+wWuv9&B<=v$7`^X>WLS< z`WKFIkxE>4*IW5d7Z`to%@2^MyUZj2OsD@c3~GP~Sflkwn=Ef?56kqm(oG_9dyOMb z>|~$ytCoS6;$rVDJNh)n*FVC!fxE7YS$zM}%kOj~Vs5syw6^si#E1vgl_0A@3xO7& z$e|=UK-W7=FQzeursT@odu6RZy(^`0Xe!$VG1n}NczM7iIYvUR(Ze}g{^6pbX@5onx;u1Vb)mey}<8Q{WO#B8K;6;Oa z$H)6KVTw@jn?Tu*L#I&3q|CERl}XL@nK|!FmKAKiPex9akpTP3nD)P%an4bHl(KTS zK7QM>8bpN-$_rl7jy90-FHq0w-36NMBkZA!n@zmd^jcu1ze2o14+6 zdG3Ffm<63!fE5Zw`D(UC>Wjo4!Erdb<``tPa0>p&;s%4FXoHtmy^`;2ZHf6Ls}-Sb zijY;}tl}f)0v>}4dlQpv20S^nu3t_)+9wl)x@4Wdl*X8^)cTj1|GoAY-8n}WoHf_0 zR`Ww$PghP(t{UHq{u)3^7|f`=>de@un7bl14pm+45B6Gxv% z?s@#(sUGg`Upo)XOoD44`&;L==tus3V866bHcZNIHlMIr!@rJ3-)N15+ zG1&)1l8aal4c8JVajf#*5i#MDs&wuTFSx*;t3n)}RgEI@(GxKJHg* z#u#|WKJuQcF2Gu^=G~K`H@vr>Sap0K(fy&zJcO2rx@=uzD&2NYSuk45;U8>ZUaj?u zzp()Rr|MqKCaDb0Wm6Ove_-JHdbGww*WGBIxH`%G%3Cj92;n(p932(jZbqeScJzvz zDNSAoLaE;Y$`u9z`?Fz+G+oOIv@8dk<0W>35ut7kY~*=!pymn+4OZ7QQGAid>;?=} zI7f^X(xg(3i73SD`4<>G-u=_2{nJ4OZhEd-x)(s9T!{3E`f66xc9#dCLrK{U<4abBx8#GA+^L>6ttGCGG93jx> zC2RbK4Yww$9K4FziISoeAjG_aMF{e^U1RlN^&ZQ$sa^Q)!2G}|)R9R}5X{d>q5sHz z=POkNEssaj^8@B4gX30~=#L$O^-E^CK^78~1jB0Hb!-c4l5X=QiFP)m8dqI>b*FQU z6@WR+68)b;{4bZ`zdt-2Cv!ZV=gtyHqtsGkFv~z6yaYT~y88@Jq2SyGA7bl|h!lK)^;31a!L<0i`HSTB4{Z zEtG^RL_k1#?_C8HDKG>mx?Q(5`EP zPpk}=IX{4HN_1!#GUzPLowtB&7x*OX9FVTD9^Ot~C4Dl>uMOEH&~H_FIMlYV1hx5& z2N&3SE;oIs_8IFtT~%ejk+=unX`jv5Lvl0i-{5OZCnu6K%%&YHA$u_dRxuPcU0D7> z7o6v0=M?lSbjD(*{10%X_rWm0)<2SgtTynv9wJ;zxK0V`^xPi-trV zKy5aR1Q!-VVvE*TleRngP$$gWWMv`6i>&^+OP&5zBD~84Vdz@;7ds{$5^1=gn+v&9 zviPb&_;b%tFdI(3QOIwX9v|Ppee9gdeZlgZ+Dt&>C~0z2(>S(trgE~Zs1U%a z+sw3?R+2ws%I}-~PJAW&-4*z7>Ktr(oo>+VuU zglkwN@B#mnF7}rR10a{lnn@>Ww3a>|R1XhBwxzOwfW0007(2WOuc+5Oq@Lj2U9q^{ zgJQMM9%%#L4XNC&TC^v-D(kO=XDb;+x%(}oFFUdK=Q{g)bd~$ZCjwhm=jrG-J-KpQ zYR3KcEkQqUgrQ@SkTSlZAgi^^xG~GV$*ne7p^DYWm`Nm~uEgB{COY_@y_e&u-I7XZ z{v-70L*PA~sLrB;%eB4Le@t+N>2V4f^>KaMT3_R;l@T%&|Ayv+7M}K5<4V^mmLyMy zE`D;3RE?}&T^k9pw(orfXzgP#mL;4=@kr%apViCNw+DbYJi))4OnAn_zFT5H7O_|r ziA<1SG7AtW4z?ZG2$GraJ33!#Z%|^nR(pE>aTJl%c!Mv5<9*X8(7i$LIH~Du{k^gL zKyGdeK@oFX@lH3F>LtQ?kha_pZBe4rIUm)yJ3Z;(`vyVp?gv?`4mtQVDZK#fIt_w2 z{19L0?|H+DXAc5Z`Q6e?MtWys!=7cNdO6FbS^WTJR9V+ICAbd`m`PO|Tg^9mgd3Ab)R@>Oly*YdhOnv+=%^56X2RnvUp z*oyDQaJ8Jzw}q_RZR|ip%P;NnO%e%LK$m>QwmZ}oaq&l7#I;b)XE-0GmtRZT_jE;h z0We)QhMWNrq*zWR-orz;V)hf@I7KfAA2Mn&$T<(@T=9)e-u2iA5)HHqJ<5kh?KYY#^iMfNkyRH4P z-Mu}hemDW|##OC(n8}OdGlF?l>#XPyijUGC10viINF^VsdLcuwYywq9Dp+hrUtnfA zCu8FK?O4yFN+L7s8hhe}*N}@9lbMsOb83iQNV_R`WatSP6`h}~acTow3S1&N_Y6ib zBdT!a>wOm~0H}tZ_$fS8b_93!`Fl;&G#m2*J*`dzjRHw??#skmPxm z=|N%gPJUC3n$GU%@Zyf(f|^@-KPtkLu*F!*W#oF(>!bpFWTztm-_IqHGFi&om8y2o zu>l)XwfJ7d*k?f^uypsMAEP>xcB?EkaZ{xODX=@vKKqb9tVq%)8U)G17TF|1@B;}1 z(q{sbdcs;DZ-_#I;fZW)k<*yIL5(V}x7&TyDg%9etGHK77+&P|XqX_gedz(-Vea9z zx5)QTK@4SDYp|P9bgBoc4eEHRTsBuNk9At;NV$`DBXZ1$!|lU z4gEjDZ?@Jq$Nd&t`54u4^-&RJJM$Ou?A2uu8xYY}OxjLH%@J1Tc!!Tvy`0_43UOr5 zDB(GS6f1MTjp(&H#NdRLY3I<^wp_RsOu7ho?Z$pC&nvPD%_j2o6ce@LI zbNcnl8T#|@@+U*8eLK?Liud_8F~bpWLZ#(5H>w%jvqz$fxWSz&S?v2#qtU1ai{t5M z)gD@QDDj+|AZ;pTJ@IINzy3bVcB;V4P~{}FWWN4D4Z$_?eYx8B{*zZMoOJW<-z=Fb<$JW% zpwc29*=SFT72VPuI!+}~_3GfD>p;K5w-387x|h2^W+^2QyUcU(j0Q+7j-fT}1F-q| zmrqK6J+eCr(FvMa82XXNGAMP?-t0`*e&jgTf6W>U6E#ce*Jt4&9FlRLW6?Sn$#Sf| z7$;$QC=A%`JuDp;DKYFXEIqXPhZc{NU4;Vfo_$@et?k&gLon4i`DByo`se&0*}CL> z0tC5_vc97@k_flx;6U>=@(%M<`L8Ja$kj0d7s#V+1*TN1Wea5M{%yCn0z8s%3rN*! zoq{WWPop|mkb+7I6)^=IfYYp$=+Qd|j7JH}$^vg=*5D>QK8;l{ZV9%_3VeVGkCEuH}=xZa9q`*zfLb&h!*&FtE88 z7US=%n>F{2>Nn5?dI2p#V7>4L2|8UyhnB0e&R@qJd8j1{je3MFdohF_g_M%unW9+I zz@~|m!0yZ0ORTk;qGC9fp&MJh&)e0#q;X)CyuGU!v-JlYedLhxf3hmTmr!CVh;}1`wBQJEGTwGuZoSLxoL8~I zN-R|#htyi+w^tnoE!i1iOo<&TR7?xNjrJa-SdqhdfCmtL9AqxK65hP+G(=Sr(p=4m-e3FxBk3CfO7L* zT3-jc;H-e+udeXF-EL?kCG%a)0QA|z-}{rKKp^ZV#=tn5{{!)wzZdauC;LzS@xK!} z`@iudvdW1c!vuft8U;X;_o^AWsU#~|=ohC5Zr#(*y;=v_=j~0u@LQLCKhQqnG>F?& z_0&%_060TdAcL};iu)x~=-+h)^f(wj@BK?Z;NK(++653f@wsI8G3qvgvbcllTim~P zG5+!BBuik_V%Iy${~09kPhPecLt>`lz5Mm)_5wUXxA7W~hC2dH`@KOS{o zA6UUu-&H$m*^<8=M=Mah=btR)pS(;g6DaF0c`r$78Ka+%3!sS_`Mt&MjnxM9220*b zE-KjIUyp+ZG%ft&i2hw<{^@^F6+8vS6+{k)AN#EnKLs6kr}D(V_9`$Hcz#y>iVOAB z;FzD^1;knA|1EJA?^yV7X2YIQlJu=RXQ?}+_U#^SRhP+~5kkq5t?@^G#UN)eaz@Ij zqj{H)<1ZH9FU3^k9Hn~elj$t^oQVfvfR|kQ4Gw{e-f~?cqJ*yFB4653zxN+>0keWr z5SE7`Zgx!ib9ZNZC80FRl0Up)U8z|a-o4K8J5r~53Y_0wmMg=fF-ZS6Luf0XZbx>k zr2kxD5uLjiQDNw&bNeQD1+%pA42??in=6Ac=nue8aw%gU53< zH+Yx%r01vjocs6(!A7R1>h@vwzhiwsgZoesc8G ztn#4j-pvOeifjjJDmRAXgv_QpQ;a8?-<&bl>lUfm7b^gb8t}9-S;khTD6@w&zC0)X zeQDOx9=6-yf$WW`;B@#w9}v$`ya?VWoJ{Q=d~jft-JVJ|-q~Ke@kKZ9-fgMT$7e$O z;}4&wkg;&{L*6yE?t^cJ$&FuNHo6`H2S6fb#;*K~oT1++y>Zj4#?ma~Ew&_1j`H8z z#aey}kKnR}+G`10{U1Dnc$m4%opMV$cqs@+tcei`5c^w+t-KO)&#GGO|D3%Bx`*Z{ z3jO9{=wAh+0Z=fC&M|y!Rg%~`Rbtn*7h_lIYDlRl;|Lu>J4MPDGvYuYS&bz+KHi!q zdI2OmS7O?j+ICk~tja>xxrsGo;)h6UPMOaA^y=XSd?vqU-2?ecx|1aGC#!p6QxJOe zb3{Z$j@w*+jz4+V<=tUKDJt47F!i9itE+2JoOUMj5^?r2FT1|Je(?9LhMA#FVqDiu zLg8rG>2kZ2xGw@wS5hgXHM6>_n@h0pP9GVr-}>18SQ6(_V z@DZTC)m3vu1X0lmU?sQwq`QCe(*B9n`RmfP2&r3pSb_0r##_tdKPHd)WFMY z-WuOG`)IxzdKd5kU#KQ^CZO%~#VcsB`PwcEKH}HokgT$!^R+iY0|r}L7V>(;moHi3 zY@9&D)o8h}{AYFX-;_V429Gn*%Gz4_gwx7s1l%Itv0nGRBkbYv`+()90}HTnRT8@+ zqdsngmxO1tT-fpD0EwTa5MDN(jf`V8v!>{frDH6NGQ30F^JRXfy)MKvDau09k#=ZV zS4*i0!0>rLeXKUo*1I-UhKIg*2P?y^FDCU9^^Brwvp|vMHTB%t_$$sepyG2yXA0!9 zOMBMG-F^s2(%>Chtn8bIJU^u3+<^LyA8v6!ruB~F&HJj?pe-kpq={Q!YCYK#*sdvW zk$2tXi}>zr4-3`+`(c)#$ScWLF;(e*yuZFMdaZ6L#&CIMajM?d%y&)fpgJzu;wM-6 z7vK2V=oEWEXw(6BtT8exIW;|yYe?RA-6eMq*M7Ta)^7TY}mvY@Mv>hLGBk$Riu zI&KxdD_M)-)un$7iC*ZrVmkk7F%%|?Ht`UUOdY$cxY<^{HIiek?46Z14{}yz^sK*l z{m-A?(BETC)c;G}Tr$w91S5EMx8;>H?&!rA-e296XTKaQvk${baVZnztO z^_{G8sAJF06e#iBiEeiU^cBNPG8L;2+dePIt^rz6khQSEu_BxPBWm9Lc{$5Ld?DQ+ zgOdWVJN#lL%rK!l%+{W?{ItgSSVPJr1-}^av34yX28ZJ}SJ;AAkWOB&#cWObi~ZXI z7lrM2?Y!daSSU0$9M$ElF^1t5;jb)RPFW?b&G_pl=L0c(h#JskR$o)xXxTu%34Wir z73^I5WKviuWMQ~Sk~C6Hy4vyeC92|2*}1mX+XK=vWi>Iov(;T=H_*JtgnTAnF3*v7 zv%V9#*o~w+AJY2O zv=oLC8x^>MZh)|Y)E;{U>N-u#I%vS#d%|dKqmAiuL~N`Qa<>l|MC_5(P2DXMt`Jd) z9j=Un+YM_WeYK_5A|sR=h8^d2@Mz?YVPC~$)f~O?^qZBg^*BEl?@imhd;}Zs?`_&c zc8(c*+W9k3@y(IQ3l<=Gkf!&x8*Eu!&q`+b#4v;V(2&cJdw1}rRb{cy&e^xNcQypK zcc)!rf+8Mrn>h>lk-KU{8{Df+SIg{2j@ps%ws@HQ`mD%g?}_PN;v#GU`OYWt~ypb~T~hZ93J>EL~&s;>rsd}j2~ zZz6J>2A7pNhaVYs^hD7C!WKT0yxZxb0{oZFQR^~fn~wDKgJN0v3o;g0`+X)|xoTil zPKF*s>@N+|Qe796)`noamu$**o_AW}OY$R_+B|2rEWIzz@C&M^fZ4JPVdm7%wEb?N zIX&#gO+euzU&84c1z>MtJ~CSa@X>|1;$JFtQo`|$(q>`xrcrOXwf~99FOcmFhfg(c zKuLdb8oU3uY5bI#b7#>AX@ihM2$gA?NO144#LqIupy#-{0(Odw;c z&+rDpF$OES^W_FUhraG~`ihXWIK5&*e8f(zZCvff?k@J7=hFAHygoOjtfprRb|goX zu4(H;hh#LJ!?m9RgViXz~y={v{@)sHn)t-+0jqv|+(NJ`?eI4cA!QDmC1q*Mzc^E0igjC_h@>}eegI|Rl zx>O~DI9?r1#11uoo~01I^D}gB2VmpO>NT`#1?By&-skGk@8FlnDmVAttRq*x#Z-e7 zcg6PQHbyNARRJqu*}f`I_s#kdlKm8cAYhXWycCKsb?CNceiTo zc_HQ@0;2JU8eAXZb5ACPW`B8_-IBiM{I#uWSpm3Israc5u%yWc2)V*Cl@ zM|NZ#J46)93IS}kOPd|10)gL^sb6_+=xh; zXT0KTPzzi(PA6VEIFm8r6}7Mne*F9)^*Y+1)7Vb>Ncrviy48NZ{U;x4J7%y1dhLxp z2X&pXEe_csZiKvyL2;ae2@KPw@qDP7n76cNp?Lh1m@Gbz^d~L0D(9vyiUxPk`&6{T ze{;?La~Nf+Pr(fBi!>iAd045CIS&oAh^qz=cEh=9qc0lNb||(0ZWBuK&u{*{t5AHNFs2$Bjts z?A`xII~aVPB?iTvVCEqJx`e-fZ@vZ0>Ns*z(z?4@WO}i7hFPM{x?o|5tH^FBx~fRn z=7siI@v3nWLF@Pay{k!W z^Sv`%ymWeuVpjpe$6-g9ojnxt!VtsEBYT|3XYp;0>10I4#is;Sl!V+#=jIN4PHlaV zqvJ+eHz3d6?|qig8)$X+E1(mtT>51-+Rv{O(cf1OkVN^{^E8MJYf_m4oZEO~e#m$- zE5UfA$`{}MR$=EkUr#f7=6lkqMTPyzEE|*BqF+4uN(tTI}dyL>?DnS-Lvno+38lo&~nIXUD=JQnXQR9NE?rJuAk# zM{Ddw&w9AB(SQy|B4-wOQTg`rj4)#ev&*6R{c$$kAOVDLL3%sB94Z|6Wo`e@+a-pE zYVF00Cadm&Pp6Y!^lYu|MFYv}(jmI0g6`z)-~1R~>_r^XC_D!lP2cV}aS+(DQ$-HN z6r}7l1{jk_Q!CZXGdgl2VS*fTF-CbNMjpchC@C*Cn-uDcrlotxcK;m>LQJVfOY{Qn zjSrs;tZuCJyHxQWToUWcCywrEn`m)Q1XAc0uG2YwHI+8qi_jyp@tjy3WbaR!bbCuU zaA{tilB42@xFeR2dj9J|{=Z!9`Ug-Dw~y8;Eo&}W?7I4bR99zb7d!F5#_c>U(Q{EO znkkb@4F?ax#^=umW9&9RW*U!WvM_3nt9wYKr~m*8I<4jhi6>zgIT%^JAfV zz(#TgVE_ERl_o1d1FT$R`O^RV&xY<_tUQSV5->p#zq!(m(;zI7PJD^@Jt1hP0UNnL zNq|~`&|l&SDk+nwR#N`EvvWTHc$<6FqkeCtcU=I46CN>nFX~@x#eeY>#Gt@oro|}z z-b(-H;x1xE2cMbu%b_jK{>`HeKP=_hCmMb}&Qp~Z+kBh#_ts4z*^C4N&gJDS%x{${ z($a+=eGT}dH=|k$<}rPNN&y00lUW?UBYuBXx&3dca{Rv$tNok5Kt&<{KQEg7|AjcM zJ+$jBm%mfBC1X64Wl-}mi&FXf)-JGCzdqz8I+0B%-djW0WAjDX4F7Lf2M&H<8%{vz z|0?}mnBRIvDg9-N<9-NVkefeq4bF5-`?*jWTl`5a|H96hj|T1ak~*IGLw;o~+KL=Z&#CF6S>e?vok zP^a*pGU8nWtSC&oWkg)f+J+51i;XQyh;%tYf2pK9TExElea>=8AHIflrFNRpq8lMR z)0ka3o}w26&!(kALguQu)PIM=@S&X%yv!z%YRxb2hZF$x1(=<=BfDHJIA61Htp> z!SfS0rqgSK8`kepo`3PL(%v*mMKLJt?XR?im5lS+rz7u>ZLFdKye=dmu7Uph&cZSp`AMsfA@AJz69ebC<7 zsX6dye^`?Mv~Z_&4j+?UiXCB%h!Yc%#ji|;=%Jel?z0X|QaNML&5nGsWF<*svV|#< zJUbR*&A&ARD#7?q{@2s~uMSn9{12edy$yuB!|Nh`q`hEfz*(*yeo%g93(mi5*!f1i zAg6Arf&5lHr6tI|_hr&$*NC-q#^j>;ujXo#x5=bWB9mcPO1qA%0i5_9Pe>irm&We1 zVuGpuRf>`0+)%Xmp`O^a&B(^fo~nw{SSdVovI2PC-{u5bPuc_s^!W(5oF&H(f1tsI z2uq7!KuOB^P*~z+sxksu{;D7q^8?PeiLU& zoy&*CaVL_5VFH|&HPt}0)ATZjnOd}?Uj6|J_`|lgmP`Mrvd!FiaFbadxb5vOQGCqu z(5O%77sqka3zd0JcxeO3MiVQ3G>WlP0Aff~_n6bk&enBo8F8(yu`e+ilZ1m#FDoJI zZjVrRR$r3r;KC(@ns$j?BJ!qZ{GYu=Fw_JNG z9o;pMhvX90KIYfpvdg7yA%u!j{1VF7$LnOzy2H_Tp{NykUn8k)dc~B6AV}8EmyzI> zo(;KF2cJw(I#H-}f*O;x<=ityXdRKq#zUZWjiDMNA_h>YumnZ@0IZno+T4s}u=|}d zEWuFHAb?Qp?`r6=*&m`6iS}QyH12<4Ilc7J@IWo%_Wd-Gb}_ro5(iABcLQ4LeDE7> zKNB;*9&7|?YQRpOjPY%KveN294$WEgWE?Zzej;PMLum77EgC76>w&Mz8BaVS3F!sV zVpSmn$L%)1g-`bewHb1>l0JmK^9;(~eQNDL9Esx6XR*G>dAS!9)qZSxLv3ZIdZ*GC zzgFyfTGOoOeDe_QM{({&YQ?$seepS#%HEr`-Rm{V+HySiJp|bF6Dn%53scUD)e4f< zWpnsQ-$zlYexi3>@NFpGYsv?g5MI@4ZV$a|)}jmSmw1Jl`6{+IMJ(svi+y%k8Odg5 zF151>=62J32zqa|9#iLDzDxz>TWN>+_&~hY0 z%RC6}GuJrnNLnH)`|(QL$rY80lu=9AjX?)p5uAARu$(1$fV{TuFtV`#1C?ksGzcHx zk#Yak+JbCNsMS~$SFI}Vj&FbUYMpZJ^n&a~xz^DT8U$Nt>GzVQfAj*dqN2<`=pN-r z$ER(EadJQAyuXv-Zx5_KTPBFB_PV!vj6|{OthP?Za|}Cvd}2HaiuukWH&u0uEfwn= zOY1*^Lb^d53e+!TnhHW)DL1rhq=Sp6zuMNn*Rd_aVL->eZDF?H+k<_L>C3GuTW+?! ztbXfxD0IWh?tLSv$rt$w$|f&}pAu62cKNCgiUzPkC`!eJ9lN<*m1$iZoLOwg#F&_W zO2tr0T=J}ot4k2C{EFfhcZShsI{W+bt93cu8?9tNzrn7mB}LK)cR6%c4?cS&z}?Zz`)a%4(@rIGlWVQk-9I?@``NKFiiB@*E=a` zX}V~-uA9UTHT*>QG6S$7+T!eG_=pRy7C9t9is_Do){bs2o`I1%q z4sU%I-`AK#gK@HUL|-(@_Q7eR%2}MpPLpKbiuI0d%T(pv1^WKuu=nFMUCTZ&o+UUx zwD4oXjN*n~dBXk8ClP3*KtW(c}d8F)rq5S*H8 zP^PVl*=Rln9$=MQY91EHqAPCxI?GuiaN-&~lOC25D5D=>6@l<$`@&Ob;}VxRdwN21YcqP@|Ix3?4B6~?X*rfmTj%EI=F7JCqxlzF7EcJmp=GB@Xq{JUvfCD zKAYV(@xG|9E8y^!zCT)6ycaajn|EJ0_b^{czweUYhW&9wLi%X(0Z1tMe95uF`wVIa)m3SuQ~#^$@n1Y>kroD*M~iSTPzP%}#y5xu32Jc_aBTgH@Un&i zPF@&ERE3h-EI%e@N}o9e{wZ< z0^*?(E|t@se-O^|USL0FxO6MQ13$=~KLNHwWp$tcIhLg-MMz{?Xla#XR!?~;j9hi9 z@N6;YTSExxo;5eH>%QP*9btdg$hqCf z&LywnEcULpzGN3t6AJl6a)0F;ZnOhjpU&Q7VAWZT*U)_GXj}a12#2)C{q6z-l%428 z{R&$&IZoWGwd=B1bN88GlJTwM3aWK9h^?bOjCRO_&T|7I%~AV_>qGWqZ|8Vg>um*~ z;-nV*(&q)9maMjFoKJ4A{L{Jw>!B#_wuh{WnL%C!5##)}CXphi`kqyKNGzdm@Zh z)~wpc-`etq+K&*0WONRxhi_ZK2lF+2UDGCN)D{Mp?J68v8TG2c_D|RBsrD18;@$Rr zucVXq0_Pu*iL3&?w07U!%uSGN-j|p~MK;^B_DSn|2vlY$9e9`OLaOiwW$;&?GV_Y2 z-Z;~Z!`-m8HN4=v`mK>La_2Et9G~Vg7I8FbdwyqO^y7#;JkMyRNj!O@rZRu*2rB$B zQKA|$0K+AB?+)l|$Qin(&GkMPUuvr)pD#TOU+5k|@nHG@jeZ0ghE#gQr4&eab9(kVSK)R6l^2+nRQqZ;E-iWAO z;e-F87YE4kwA>H+e=2uMQCo51-l`pQk3+r-b2d$t7O__*V$uGV z+v4KlOTz>9pCZpFesbw@jojVC7C|87&3@29);B1OwDoT!ppmO@ETc7%G7t)zymeO# zn8MT{sUH`aGe3DRrZZpOeZqNZn0o;|^xCyl&lJa~-MHS>uwnt>T^L?Ba*MwPe>zvF zyBhDkozc|g?e7nfC$~-Z6`o*!E!xdfpnVNy#KJ2G_na>8X%JX~m`6TQ=}$paxn{G`L7|k)tW=>y`Q7QwDSV`I57)wb zC9QPB3aeEkOqCNZrvVbq$KsvmnBTdy>WdZ*dfT)Io_5vqb^2H1!PYz08y8!W0aL(g zJKLAcij*aqr4d6dcK(>qb&cqBOq2nZ(~9#cwS_!|I;NG@(_)K}{%8G2j_;ea=EiSG z#G+{sXP$NQsLg@F7n1`eWT1OvEgpKBl#clgZ))U^>Fkn}DnzGRY#{sIc9&VTXqNYj z7A_HxMo-=CeT%QIVZNRUFI{Y9WW{Q(T_}XfpddS*q>Wb=$tB;7qL%e+dOOixctD-;|Y?QZDYp zbei{7g}oi}1&WT;q|cS4KmVF&VqQadq*=S)6X}Z#k)$=4 zL(h|uOF?m(r>s_slh0gi>@h8x*N_|96jzEP?2M89!j7OK!cH)JA-leLtE{COE330& zs!9^Exej-oKQ1>hrLmbvqWRiRln=8218ce5cQYrRrZDSa8@<0fY6b|f+%To$3_!h) z0TE9rjS0bULca7MeNXVR_(Eh79%!d!X4-;+nQ@X4SWN%yp#P@>$cWFL+Ak#sEAm$# zSMyes(cr#27N%*t2DJ~JsrDAD@+8LD7+I6d)?QmKy%CU5q{W7Ia8k<`_UAyyXb`bh zTBil@X%eKPaj!wk&12^?uiyXxYG@emGob7^)5Tk8&Tw(Qe0`&_UWbM8Uc3*}6DbsQ@lysdJhx_3H{T=2a+bKV)pBlzjkjzw#Y7I3&H;sy4| z=5-~DlEU#R-mdc$&3a!VWHAQ0dob`-w z?vpJ*3=8ax)yia2$9?@;&+lGwvRH1#(K=PM&bL@M%l>5k)~JS|Az-4{c|lY|a?do> zS8}mLz@|g?umYSNmehI z#P1&idBH2y!QJ~YfZA+2+Z)?!-<~h}Jt5mE(XgwQDc(P|#G%0~*?E$H!2)+uKg~8V zGd=TZEU)#uG6Po^?7SH69B6-m!wmiGwEVB7vH#hJ;*mp8Uiv^&7T^ zwqLuC3uvSqM&RxHVNq#TjO<-&@N}%1fv;H__8L^+B2EWk7_|?L)$+jRAaVQ`N7x~j z0an>DZjVJ>lMU8Ayi{2Og%Zl@&nn-ML(Gq#qaqjpH3(D!S?%!)gWy`mDq*i7jGkc6 z?L%t@U=L%lf^d|Qf9O_PW4K0?_Lwprvx-(X69`JtypNUMmzGz(7KQd}B4|x-344%d zJ$45yIT2mu~u2*Y;1%s!+2p6lQ@L*aNKz@y6~Oc&!Q# zp!K}c^boLJD^1(pS!(D@X(WG+UJ$fS1h7h^Kf#RHWN!A$KDYk}j6T3Ay$9aNw9z0O zt?HVz>c)JkwARvmZeIGmdhK;ez4l66I;hv44s@hQE&2FfjMIMc-@>2+ z87Q`f(k}Nh2LG>8;s03D50?Z^X}(|qDi`9fGEvJ={Sfk`2b7NjCE??TtfZ)3JPO{y z3aU$+PUwKwsMk`1RepRMCW)dmKu6vy4}Wi`p!)#4<5bTIUh~y~`c(uk5ukJlz6^St zv?c}r99=@?&(yC{B+7B$-$(K5TmOIXQ4pI9P~T_#@!Co5Q)e8+T0vL`rkBqto|sI>kRyC;2Y(NMZUlMzw)QZMeuAhUn%xl^q5H}o-J zD*Hgyk82XYY~jbm_GDrCU90P1nVHtOFc}co zS6yCv9LU&wG7e-AFNoWtw8O!qIC;T{X7A4tGDhgf*{H)wgc1l1j2f$c??IIa09b!N zuX;63b`P9yWLI-=^=mtS3GtQW&;hjnNRXn;7@?{cOT+wbH@p-GqM zkp63C{IZA&1qO{ZkN_NgyO2gsDqN@$)TzaL=YB{*v92I2(Vk{M-F@{3W z;q?e*2`UQI+_b=M##bR|uQoAfl@aG)&DTngv1?Tqxj~Ivic`y~wQT_5{eV$uT*x6? z^VO!rVXtqpj)QE<@bz;qISd1=jzYDZ^a8Au3JR!_MbB_ygpkBU+jjPj8$um{NSQ7d0+*k`v9gFmu(Lt2v9TVL;X0?9fThCCWdc1 zet$gGUl?~72lo*kFFu+i(DT{2x{wxoHnKu8M6bZ-F?(CDL+n9yU-H*StQaqqp0q`q zHHqYg>tQDbMAFt!G1exTL#amlu(fUkeEC_pXodXw6j`*#(`pB;C%(kwqB2Q5SIz*4dL=y<~%cHS1Gav=P8VX}&5XRMMvVu;w zIparj?~j}q`vfFKM}9lCk&A5ub8WzHZN z-9meY)5EzIxQ>zis#0$kk2Y>iU_--oW=^JG(Bi(VGQvO1qtDedc==p#g;>={bEQlj zuiFfp^#vsNmkW2uyw$MkjHfdP*qcmPix{(bxfguz7@W)-9|6g@K{XgP7pR>f(Bz;1 zQ-^oz8`CV$?Ut z)7r2Nz4&pe9w`QgC5os>{?gbLi$hM5f&p^fV2EP&{vR zX7nw(zMG{z76y#q)by{$;QaW`RNYhAi|`T8?Hi~!=5I!cI@sDTZIH_yZ`qMvrTcpX zhpIldI7tCJMw{#NxO*?gigEf)3SZu%kHpPI>_j$@;PE3()vOB}E-aX4A< zv1V!RvuJJ$S&oMSp}d?6%sN{=+WP%RBgc8tlbJE)kkz9YA0eZ2daRYP*9y_Wz zc6X!{ZP6^Le{#WI^z>G^YpclDWJDehW_q{MYBt*lUO#0}7)J^y|R9b9KtRHWO`B*LcX zC4)vG7$m)a;WI6kH3l2Ow_g=?0;HR?ho(bps!3yyuW=B<_LP~S?K~Y+Y<#Ca-}beb>A<(7O@Gf3sz&u|Z8)*rk2 zX^`zgceKQ@k@D%`<>V_8YUMs~AChM+Du)K4(e!g7+b@Ff`zSi@(*XSi#EXGVU$;#f zgclQKGbCiA<~zV!-FK0Zz4z9FPh;+N4z70^6y|={96*r9&mpH#ZbH*#1WazWv>w6Z=^x7}ROfAC&Ek81K3!k>C8A^+tFlq^;~%iK^bl~J2l5g`)Ty&}Uu`~w^vORL-CySC zSv7l|5fW{XA)Uw}=Ie4or=)*|A9o;sFGl|{mW!Gfyh;B9wbsy)J}jOxHo3D6 zGD&RQ@+K-zZ)T*YKke@?)7_r>_!3uLdKh6{qcvU6eFXsW{>}N7@0?xxpZ4BG9dR6~ zZs_I>Bl@hZC+4bGV>e0ZWm5B_8cQ(-iVdRPE>COS37m4?E=>ZOnI#If-*6U@t%vhl z;K(P0-lsR~_+!GGZpt_ivmA$wyUd7|6@5LVtdEuYzUn38JunyhHIenz5&dREA$Jei4KY80%AAv-iJkq7wBe%_>D}_yO2s+G=+4NAycXFED*E}}m zYfmc-^aqQ|Cw~Pvk)6XsGh`jG z|9Y0~O}0RJw7g~z7M}LQ2!DI({i^kc>og~4`VN+@mRnnIXp)lBKyGkIMN~h{uFgc( z*jJTeM-#jWf<`H=uqyRqyngyz)iQ4PNV=$8f$+X}+_YG>+-Yj9n)k*Y^O#GSOineo zIS3Qy`zqf?@g9a#%>x8f<$^G3y-rU&#*^(w9~mI6*1B9)X%KW3)3furYh}lf1IwWU z4WI1z!Y+71yvJ5^n`_1%YNjxn$rQ^_TWRxeLxIU~>>6R*~iv5P}#TD90)FK6Sm z9?A={3W)89MM6FvgR@^!Rc6O3T~ybtvTyD!^H?wJ_aMLQr|*wK-STBKNRo~|sm_XI zjV5@1hnVtNU#U9&Ro{4tusJ$Y=CShd$w)HE@7NG~QtbK2r_>_gyGr{gNWZ=3W9*VH zC8YY{-MTR7r+^*~l+MR1-j<--S-vy*2(QnTKPL55haFa0JJ0O;EfRp!+kg|&_uaX- z;U)@uN!_SjO>ztnXemuQ9JL7d_J|vsJP#Eg{v)PR8z2>g(eJ=XHbCv3k117|K4l;T z(K%UOcT@v`kx!w+y&@F0tb@R2rSdf^6*W`<3#4#xZZ}a{YtJnVfh<0$RUf1^1@~eS zy%+p*yUfUqKfq~(cgEo_tEelCFnV>>L_Guhvrt_3$g?dfUN_YH=zSrexK0OQyjEu| z`>NJguQjxQzWkFh;II*@skw37SOEVxMRgrl-@v z=LoKEsP)Axa14}0`tsk5YI}JKEmln3&=7cUA(;AZKzZr)07(|p#iyvceBMKm#v@^& zu{CSmHaJ9rNyLfry1bS32&U+Gx#-wp*lAhZ6=|Iw9TZmJ&cdoz3YvlC926H@EMttM z#nP+BQ}uiH9()C0%_!^dIV0eBPb;t%x)y2}Xko5LU4sWzTS5@2*o${mdJK%-rB&s@ z5vNZ@MHAAoSxpbLa3DX?n@xBXy#Rn|sQ4u38Po6YV;EZSs;Wc8ci z*cMx0ZJqKVI33YYXyIl%e!h%)x@~W&Ed?GLv7Z4r=e4nGaDEkWyW7JK%lp*7Glp&+ck@g%-# z<)At%`bCYFWqO-xIIQO@FS~*2gnN+>Qg7e_6yZB=IH&{uL7MPXK?2%Fo3X*-@^e9hEX!ETWCsh>~F;MSEuwh zV){3D{fjKmPaeUb&hYl1lSh7!Ne}={*~`WyVv!Qu>N*Jc^A~%L2#UR?K?L1pqMEIt zD1;Aw zrcdhF!_A`gE=3!9rOkT#%uH+~dhgbGY`?KkHocIy_#k&SPq}XS%SEm)7b@?qa2ryI zlLOuOMa-LDdwlz-_=hi=23J;nr@RHy06~&v?L3wr?q8AhoH=VckvPN|Z>@ZQMRwC6 zj6?JiBP`{aevFV|f9I;-a;eK_8k~l|lqiqaW^Q8*(rg_0X&Rk)801^s{J+0kJH>ef z^9-u0sv7Uuz2(?2vS7E)EVEExI9oZH)sd!!HXpd-z0=~jixRS1-@bZa_SnF#+l+a3 z`M-(8zxctz6l(e#WOs*C+fe9}Gvgg~NQqoGjOuwydsDmPo2q-NoqbSl8Y0_*XN~9PF9U>qi z9YkpfiOL{Km4O85h(-)0^dcouY0@zmVh9i*0wN)yClHd{mznRb_51F(uJio?!ymwc z_j%5F_Sxs`eP)*9T|fUWooJjBey{udtjci=$M}%UE(L`3snjrm$zuz9TJIMNev@Q14x_jLd)y$K}k>98&o|Ex^4C+cu|au)^fQTForP z5_m8R(*38U7k;q3rs#q{zq8WBy()fK zzYBo_w2j`Ln`q*@^+K`N!BB$fgwlasd+u9)?_mdq1nj}K$aFlk-d7si>!77BiYk^dOYyd%$ zvk$33gWXS#c58Y-$;s=ng^4E-#p>1cjc+|#b7Le72K3+I&IeQkcF9H`?s)`o zcM3gNE?4)l@0C@-sXbBHBi+qO8;T9>qi~iClnh0OX9V9;kQ9Bsq+IM2DUG3RINbHkwe7vu?3!K#$}^ zjvq!!omLSp*###+U)9&wf35Cd_ZjgFcG88G2=2H^v^Ti9f~OQ!J?K=TA%IA1?358- zT$_fqICF-j1EiZuK+uW*U?>{y-4eAdV3)qg6QHFlS?s#bmE& zbD^*4;|M;lHGu-7-X?Cct91}QTZcbtVZ6eHG=PwYe)TDCx*1|%HO|rG<~Z)LfnsM{ zv(L5dl=Vv=Ih_q>j>Fy7XW$3br&pV%M|ZUqj0zO_)LMHTu4j#nRYqj zIIxsKyX|7X5>w0d$gm^;E9_E=&)59FJQGIX{U zUf=PSCBJb&4&}x_;GvWqc;B~7px!Q#a7L^WvrF z%so-fx%mde3Pz9ih(@Ab#Kz+7)~nJ^_r3PkuRmc1=7dirItIvCH(IYNAm~v+!@m@G zw8zL*!8WESju<>P@3U(R$VxOTRV|)&{bin}g>g{qC2L!k2Yyb7j!EinuTwQC7J8>Q zACtDrp6zg{OE(%=6_+a+7M-dhe*4r628t`Yhi`2x>N%}Yj7H=@|zP=a>_7G=v$-sd8gzjFsf(pt=P=%aZSYZpZy zICD{`?#Gss({a2>c6k_{n?3cQ7i5uOrXw^9QSMpc@L2YZPV4@-XCL;-2()!jh_cB`N~z%IRzFblAH^_3LotBD(DY#f85m_tuwi)ED*P}VqSQKEcc ze=>E!T;E@o$Et+SI54u~)C6EBEj0~p!BX#2w2j=?y6Z(rDNALS9xC(UP2cjD9OUy& z$8k-oh9@CM0upn36hcRD3IpoN5?cRVe*Ztm|M!s(rC)%HSsb5Q+(NG4ueZDxx%14} zc-baOr$0y8Qc_9n3N&>$m}{u2$w_(szySV$Y(gi!5%#IrVVdq1&w>W7xMNlR?_w<-npU8 zT^QDQj;^@RSfgght+Kf98zMC(P0IQHc-RV=Qt6Ld@9);^vv%k#(H-p7_mk!^s~s20 zmiZk@%@egWwoQgf{rr+gT4K3-`<;t9Zp{acz(;Y5KP)DLuZ7^&Zw`^lWW`Mr!YDm(&#zMa7I(h<$jl-eAV~=_(3(kTWbQ7$8FJ=>kFD-wa&1UNAz3z7&0wjLbZA%$G z0o~hfQOBZ_X7TUx_n*it4SUfQ8h-7^Lp~>Qu6E?jIToGWsAH}-$7FIz#<`#_wMy&F zTj7}tKMIL{TZQd+6$MQ-Vc!qDj2?4UI9j+k|K;J0bk1XKJ>@8`igE3;8Ekn|`G49G(Mor3x3G77DZqFK8uifjUg7ifG3| zF*}_fcu74sz3(+smmM-vQ07EaO1~{S=gXs&fL(K!x9cx_(`3MsjFX)$x`yOKnZIK5 zzEGz(U^ws34{Tuyr*7RGHsUWYeZ9Q|lNPUJGZOU-w5fH3Sc~&Ft*j(``1b}>@&@WI zkwJY;NBkRSYKmcn8PzOxigM2^Er1x8y=T18O?P(Hu{7bGXqT9IuZ@C>>73Pz@A-QK zhxk+3O0zi_cQAM(8}Y*)JB}C7Jd(FvXjO$yT=#F~6?EEX`qkg`>S$6YY{2ATZwptJ zHT&*3@8j}a%K0G-Rhd55r5^1>I=j|nIm7iyair)~t?C_43xZbm;uh$_FkYYiTvccb zg%YdAY3xQ>l)?04F1xbN(+on!AIv}PKlvf=zM3kpWd zRICF?5~)v{D}$f9{eb&&S4+ffiE{+Twb>|PySP!|L6#}!u3VmXiD!6p^*MoI=;*nN z*Hp3tW-!Y4v1LvRk#y_bFIU()0bX@orH2lt39!f+qNBgu!KGgP(9PQ+Zp787Szk${ z&RCE8);iB}WNUrqg3gWv=WbV2t)`Mpfu?0i%w`+hG(7{S(ja ziZ1_lAkM=qM`rQHhT!2kmM0VQ2a7OGP(h$&q>5Cu2qxiZTpK!PkTzyZHI&^|6dMdi zzw%d6(c{ED>T2~a!pjX<&|igl<KPDTzOMf>Fu-$4}v zI8pn;E70N2%lC=YJ8`<-#^}=OXu<&M^`LzK0$m1(&j%wCWwey>gsHY`t6myEygaicYUx3tA*}ITtaz8EA5no~G70)8Yq{hp z+4j#S3MA`Fr{3xlSB@K?yH0ED{@?2IzjFG()A!GX1`@c3*MM?IRG7OKdxjC;G{jFa z^VwRsdJtKXIJ|$A-f&0s;Z2-sq?a)ABt};zaOKSqKhhadVr*zH`407 z`yWu#|2k64$O+DfV?cvuuWpebG<%fOqa&sar6`Z8M0dqPhn^TLT&pC;d@)KFbMh)F z_7UyN=CxbJHCumcIKHVRk8Ko<`l*+1zqtrx1qWv}8E5hO`_`@5^k%;JE9b0PhJ z;I@D}&%7r0o+k|gE;1=g6$593iEAqu?3+_|<%8-v9f`6rxuywia|j_{+}`qpyjtb* zpFz~)C}pivJF%o^CZKwK06G&skPu$!71%VFW2>W_vEn|MI`JgN4)NL7IQkw$w;-rY z*;%F3H#M<#*lpnJ+p<5#j_pymEBuz)YcT_4*mZ_|LCcS#l40il$-Y$%4IigBou$~R z3ejNZZI`uCR0c8Ag+^(rxoN#C!q~ zDVT3EcfL8vEv_W=E*@MtZAHdgH=XvI3_b}nFQxYOIBgm&9I+GqL#q}$DQD~A*TlTX zD6^7Lif&>xuwQaH5*BETysvjLaBdB30*E*oGF?n%hj9IvwQL2m2OYhUiydWOi_2cS z4gu3W;bC{8rZ#R0WX&&I6hrL7AC$QDNBetHRWuh1|7;d%2J9%{(+oM^zf~p zbx3#LxV#NB?*mdFIDiCfBva^g}<3pyDMl z!tj}hp>Re|ts75%cDp)!t~{7o4+cgBF21UWl1J8>Gz!`rlQCx+Q1f%x(~}q9medTZ zB}N zn+w%G{NuXELa!b#^}7z+AfZ7U?xf&S&&oLM_I}%v7HzdHGvGAzdHr(Vw25-7Eo;!X z{e&8`oMv9m^Cx!UQ~Qnra(f3Kyp(4S(oG^1Z;Tc^D=u@3^r~Nsb@#%3OflC}WHkuK zPw?KnA9ji+&Y<>^FdqX>?MSNu0z#)|1WEBF9*XbUm%+V8F4i7pQmE*^;=pVe4=sRH zWV)t9dceU9#`VKN*OoFupbET-n-=&@Fs5O&aM-@Uo3Cep0SB`$XqyH_; z)on9H$-Vr!-sb%|rRRl~h61*dqR9RF`!ffMiW}X!b=^xt_*nx(2auD%h^RkF-;`ab z=m$*9k+*Y36e1%y{`0*7bqj;K(~Wy7gSSh)FvcIgZ*L8SqK6QIHR-6hCCBzpTEb%I=FkG2nB*k*RqDWeoIyva(M8_p%! z6JtP)n!U!tiMrVwUIpX2D%=JDkO9Oc|HkFTq6NCp2qbQ}VHd@tqu73D25v+Gr!QBQSTt+PY`gkYv<_Oy4RbvvFy)XH}i3;a=+U zxrnltid)qCCYk5p-O{2^P^oZgwa+-RFd;lI%A=g>C`8zB7$1%GNeJysllSq))%lbX z^?HQ^t@gFnIIq4Y@$S_www~|Tg7TSCWM;O-cy@|~p?=YP3WlN2&Ki)V-^*{$MXrZu z-5a7}3$IOb((kr^Y+alueb~j4CGyQ8HQwTot+(vzSNr*>KGLgKdvK(Qdw-l3xUF%C zOMTvjvse1io8bg?=$!w+V}IIaVK%a1Y$4QHl7Fzm z@$QGMROA|fI^O~@BU;0En|x65=9EEbdkIC7l$qVtfLRrWtgHl$|DNX2J_&3hGyv;( zP4-d%TFD>I1bG>Lsq%9SJbyQ9pyi2R{#BBD+(%+{750Y}P81sKc*f}kzIJLvM@R52 zOI`dXx>hP+v078<@fm+ezo#k^>%!bZgPN zVW2MlT;f>!=kSLZ!BN2qSAx1A%tqZQ=Eg~yQaVF>^*E2~#^2B?tWdf?o_|GDCUmK{ z^FVtON>I*31Ls1^l|dT&Hf0w*65M^Zs~cP6=wInBWquvZmb|Qt(p~TWiWo>R^&^>! zPQ9KScTusfcJRVJq8_*>CUbBfq$yLhM9m`W>JX4CfP4Ooz1oWsKebIJJ5(D|YVDY$A*K~izelx&*_T|~H zLsSD&`?GeCq^y6L|4dz73WlxE?SHjraz}2bIrhDSC?4y#Qmx(j*f$~fOoJ}#mBEqP zC39M<5q!?39qxY6pyo33a8W72^tHzcXimmn1GE2Z3;ri>_E%(m@833H`qUfHfBj;iwNY^L0{O;6 zWf9*RdQcK1Z|3icz64gI{;PnID@?pBUJ9!Zcw^MWSO<97WoH65&r-DRwJKDvo>AkY zWT&R#Oha_dO)!#-uQyN!t&b={kC>vLcGkk#^?G-*A7B=(7QVX+W1Eu<)bu%L@(WMT(?*GJUAjc46BavL!E55Z17IykN^eIFuf5L`v z+tJ}XdpOuU&PDT!dY`RtO5uUyyo24>X)6?$U-xty!)jngF@XN_)cz1^uJB+auQz$5 zfSZgtdZX*tH>yp|yLQrTL`jlS#xomZ4FSD)X&#nMp@*F=I%$JQ1dubu1+EyPq7rU9 z40-B3V74ji`w?Y=TeOQv^U9hS)V)A<=mRL3wz<$@`934gr4aVixS@bwcDJBhRE1n$|8p$EB;-|H6lI|l8g z{}f&9Khkfs<4yE_C|n#kDKl;Wu(U9J3p77s5hrXB>{3X^VV~b9tUCu(PNuPGE+HOH z0?I{d5SY_xAB-bR4y42hzM7g7$F{@fR;shbRcrRgV4>qKiYo*JnK4 zbLk++d9w8_#Z*M*>K5=dcQPu7vsIMi;w zzI}!v&qSo1j{)N6f@?g%l*q1NOU0V6lr*P)FD<94SLLRmT4?Ysc=1IX)DOQ1|0|)@?b+ORifW&tNyW03Ruk!9gWjx zD>#W-9G@-{?bn5n~0?ciBe^SLJ{#>b=eZswzsi%M+Ir(qt0A7#C%S&TI@b5_sMAFq4m_DW32sRkd`v=AB|=EZIb@!P-OXINY0 zm0IIimdf5QT!(x5YpInJ_>TwfO3FR15#7bFfMW8Nn*;;t;Ebp!5N?{|(iV^Nt zxl%gOABBPy?nC2ID=YK5d1V{JE$ga45w|eBq<*J)u6}7>IZzXvQ#j93-tmXIa@e_Q z)%x!rgSv0VwAJW;QRh>vfpuj$r#@k}*|qxhqtjZB#i>{uWPRs6O;&VY(Nb~>3CzzH zm1e7|Sm^ms7gKSOqVe)Ts{o7gF-u5RF61v1TjhK9&1BXy|H&h#O7YRET)ubdRsb|k z2_FH9*JBq}I*Up@$w9Gyh>wPvY{K*fjkfs1vQhYV$j9E7aUTG#y$@3dmdra*gB3N{ z%E!+93Kt;Wv=)OkD> zbljrR{UwR~9vcZ2HYIFda38t$LtP5|Ip(fh9cjpZ$xIZA-Dh}TsLPKJo*?i*{u);b z^Q&oU`sdynKu2$V`vhVD^kBjVj-eg$Jk8>0ZGw)AvG#CS5wi~PE3D^IJ#*W~c%WF$ zDDTLhJ#>ik}&v$X&xkAOXNz&Oyes^uGkP{apeW5oDk; zp>B>5tK`9~#z|0DyBDy+9G?UbNP8yvMP;vH85Tic$vPWn04raD1D(3lIjjG)A$`s% zuj$EK7Tnd2i41QxXmfAJODy#bR`w8n9mhQ*X6!qhm!W&T3;*T_8E7BL(4~}TUSIga zjQ02h**#S-N-}rczwghI*rURsharsSk2`}ik~4r>GE$FtcZ zuPA#pZ>(}VyuTLYwx+=Z>P4(njKl_&S!t4{maPPj$DH#8RyO0y3}8c74}LTaXj}-1 zSM8qlG|p6=%3^q$J)z3bHAP;G!clj}^$77*J4OtG`?6`8jY}-}LZ;vBXn! z94697$3y8T|{hb@H zAD@^v=XR?PX$+^(FD1rm7~m&y`{8*y8p@D)Ih zp;etb%}9#zAQy#D!+Ce2{7}TDQQgU^%1WGkIQL@tq*SK)oL4>Q=SUkcb9-??x#G+> zV+)fcmZ2LOYE%3*^8DiaBxAvCpf!68FxnC!`-%aBkTMav8BYNZhAV*%finvqArE%R z-?JXnR8Zk)NgW4{yd_upD{f)`b<#QWSrNHp8zY zr1y&TnkTg_lH5w#X*8a$kzVdJeaHzEvx`SubXk*zZf-)2YUR1Izs7m0=@*_ z4TCr6yTjoO%Ho>aKPX@T1>k#_lt$iq*W9`vdYig>X|C{GwZ@5*>mJCL{~v#_*|we5 zW_}%}KdmYL`vzXHe*aLpbLO9n8vf4&?Z3bJe<(Nq{UHB-ke|2F|Ggpq-jIK9$iJ`5 n|4j}3`|SP?3g&|K*mmc;J#XbzJI`+cey;y+eg%K&*5m&I2p9sV literal 0 HcmV?d00001 diff --git a/docs/management/images/tags/create-tag.png b/docs/management/images/tags/create-tag.png new file mode 100644 index 0000000000000000000000000000000000000000..a88e754457b9f6c9b1598b9c33b5cd5248b0591b GIT binary patch literal 87931 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�KqsD*Q+T)|R@^>&{&Skslbh!+$bsSjskh7XG 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 HJ2C$OLiJ^u literal 0 HcmV?d00001 diff --git a/docs/management/images/tags/manage-assignments-flyout.png b/docs/management/images/tags/manage-assignments-flyout.png new file mode 100644 index 0000000000000000000000000000000000000000..a4e0b7a49d96a7501aec48a5c14d1062f4eba057 GIT binary patch literal 213896 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

$6Cvw^zY#ApMMT? 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

+ } + body={ + +

+ +

+
+ } + /> + ); + } + + render() { + if (!this.state.datatable) { + return DataViewComponent.renderNoData(); + } + + return ( + + ); + } +} + +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export default DataViewComponent; diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx new file mode 100644 index 000000000000..d8b96da36628 --- /dev/null +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx @@ -0,0 +1,47 @@ +/* + * 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, { lazy } from 'react'; +import { IUiSettingsClient } from 'kibana/public'; +import { UiActionsStart } from '../../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { DatatableColumn } from '../../../../../expressions/common/expression_types/specs'; + +const DataViewComponent = lazy(() => import('./data_view')); + +export const getDataViewComponentWrapper = ( + getStartServices: () => { + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + uiSettings: IUiSettingsClient; + isFilterable: (column: DatatableColumn) => boolean; + } +) => { + return (props: any) => { + return ( + + ); + }; +}; diff --git a/src/plugins/inspector/public/views/data/components/download_options.tsx b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx similarity index 77% rename from src/plugins/inspector/public/views/data/components/download_options.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx index cedb72309163..f849f598e9c6 100644 --- a/src/plugins/inspector/public/views/data/components/download_options.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx @@ -24,8 +24,8 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { DataViewColumn, DataViewRow } from '../types'; - -import { exportAsCsv } from '../lib/export_csv'; +import { exportAsCsv } from './export_csv'; +import { FieldFormatsStart } from '../../../field_formats'; interface DataDownloadOptionsState { isPopoverOpen: boolean; @@ -38,6 +38,7 @@ interface DataDownloadOptionsProps { csvSeparator: string; quoteValues: boolean; isFormatted?: boolean; + fieldFormats: FieldFormatsStart; } class DataDownloadOptions extends Component { @@ -45,9 +46,9 @@ class DataDownloadOptions extends Component { + exportCsv = (isFormatted: boolean = true) => { let filename = this.props.title; if (!filename || filename.length === 0) { - filename = i18n.translate('inspector.data.downloadOptionsUnsavedFilename', { + filename = i18n.translate('data.inspector.table.downloadOptionsUnsavedFilename', { defaultMessage: 'unsaved', }); } @@ -79,38 +80,24 @@ class DataDownloadOptions extends Component { - this.exportCsv({ - valueFormatter: (item: any) => item.formatted, - }); + this.exportCsv(true); }; exportFormattedAsRawCsv = () => { - this.exportCsv({ - valueFormatter: (item: any) => item.raw, - }); + this.exportCsv(false); }; - renderUnformattedDownload() { - return ( - - - - ); - } - renderFormattedDownloads() { const button = ( @@ -121,14 +108,14 @@ class DataDownloadOptions extends Component } toolTipPosition="left" > , @@ -137,13 +124,13 @@ class DataDownloadOptions extends Component } toolTipPosition="left" > - + , ]; @@ -162,9 +149,7 @@ class DataDownloadOptions extends Component escape(col.name, quoteValues)); + const formatters = columns.map((column) => { + return fieldFormats.deserialize(column.originalColumn().meta.params); + }); + // Convert the array of row objects to an array of row arrays - const orderedFieldNames = columns.map((col) => col.field); const csvRows = rows.map((row) => { - return orderedFieldNames.map((field) => - escape(valueFormatter ? valueFormatter(row[field]) : row[field], quoteValues) - ); + return columns.map((column, i) => { + return escape( + isFormatted ? formatters[i].convert(row[column.field]) : row[column.field], + quoteValues + ); + }); }); return ( @@ -69,14 +77,18 @@ export function exportAsCsv({ filename, columns, rows, - valueFormatter, + isFormatted, csvSeparator, quoteValues, + fieldFormats, }: any) { const type = 'text/plain;charset=utf-8'; - const csv = new Blob([buildCsv(columns, rows, csvSeparator, quoteValues, valueFormatter)], { - type, - }); + const csv = new Blob( + [buildCsv(columns, rows, csvSeparator, quoteValues, isFormatted, fieldFormats)], + { + type, + } + ); saveAs(csv, filename); } diff --git a/src/plugins/inspector/public/views/data/index.ts b/src/plugins/data/public/utils/table_inspector_view/index.ts similarity index 51% rename from src/plugins/inspector/public/views/data/index.ts rename to src/plugins/data/public/utils/table_inspector_view/index.ts index d201ad89022b..3769298af05f 100644 --- a/src/plugins/inspector/public/views/data/index.ts +++ b/src/plugins/data/public/utils/table_inspector_view/index.ts @@ -16,24 +16,31 @@ * specific language governing permissions and limitations * under the License. */ -import { lazy } from 'react'; import { i18n } from '@kbn/i18n'; +import { IUiSettingsClient } from 'kibana/public'; +import { Adapters, InspectorViewDescription } from '../../../../inspector/public'; +import { getDataViewComponentWrapper } from './components/data_view_wrapper'; +import { UiActionsStart } from '../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../field_formats'; +import { DatatableColumn } from '../../../../expressions/common/expression_types/specs'; -import { InspectorViewDescription } from '../../types'; -import { Adapters } from '../../../common'; - -const DataViewComponent = lazy(() => import('./components/data_view')); - -export const getDataViewDescription = (): InspectorViewDescription => ({ - title: i18n.translate('inspector.data.dataTitle', { +export const getTableViewDescription = ( + getStartServices: () => { + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + isFilterable: (column: DatatableColumn) => boolean; + uiSettings: IUiSettingsClient; + } +): InspectorViewDescription => ({ + title: i18n.translate('data.inspector.table.dataTitle', { defaultMessage: 'Data', }), order: 10, - help: i18n.translate('inspector.data.dataDescriptionTooltip', { + help: i18n.translate('data.inspector.table..dataDescriptionTooltip', { defaultMessage: 'View the data behind the visualization', }), shouldShow(adapters: Adapters) { - return Boolean(adapters.data); + return Boolean(adapters.tables); }, - component: DataViewComponent, + component: getDataViewComponentWrapper(getStartServices), }); diff --git a/src/plugins/inspector/public/views/data/types.ts b/src/plugins/data/public/utils/table_inspector_view/types.ts similarity index 70% rename from src/plugins/inspector/public/views/data/types.ts rename to src/plugins/data/public/utils/table_inspector_view/types.ts index 31de9eb3a152..dc85c3c2e313 100644 --- a/src/plugins/inspector/public/views/data/types.ts +++ b/src/plugins/data/public/utils/table_inspector_view/types.ts @@ -17,15 +17,20 @@ * under the License. */ -import { TabularDataRow } from '../../../common/adapters'; +import { Datatable, DatatableColumn, DatatableRow } from '../../../../expressions/common'; -type DataViewColumnRender = (value: string, _item: TabularDataRow) => string; +type DataViewColumnRender = (value: string, _item: DatatableRow) => string; export interface DataViewColumn { + originalColumn: () => DatatableColumn; name: string; field: string; - sortable: (item: TabularDataRow) => string | number; + sortable: (item: DatatableRow) => string | number; render: DataViewColumnRender; } -export type DataViewRow = TabularDataRow; +export type DataViewRow = DatatableRow; + +export interface TableInspectorAdapter { + [key: string]: Datatable; +} diff --git a/src/plugins/data/server/search/aggs/aggs_service.ts b/src/plugins/data/server/search/aggs/aggs_service.ts index c23f748b1eeb..ae1cf3054ec3 100644 --- a/src/plugins/data/server/search/aggs/aggs_service.ts +++ b/src/plugins/data/server/search/aggs/aggs_service.ts @@ -86,6 +86,7 @@ export class AggsService { const { calculateAutoTimeExpression, getDateMetaByDatatableColumn, + datatableUtilities, types, } = this.aggsCommonService.start({ getConfig, @@ -130,7 +131,8 @@ export class AggsService { return { calculateAutoTimeExpression, getDateMetaByDatatableColumn, - createAggConfigs: (indexPattern, configStates = [], schemas) => { + datatableUtilities, + createAggConfigs: (indexPattern, configStates = []) => { return new AggConfigs(indexPattern, configStates, { typesRegistry }); }, types: typesRegistry, diff --git a/src/plugins/data/server/search/aggs/mocks.ts b/src/plugins/data/server/search/aggs/mocks.ts index 7b7f3d3c4065..66a6aa2c7d80 100644 --- a/src/plugins/data/server/search/aggs/mocks.ts +++ b/src/plugins/data/server/search/aggs/mocks.ts @@ -70,6 +70,11 @@ export const searchAggsSetupMock = (): AggsSetup => ({ const commonStartMock = (): AggsCommonStart => ({ calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), getDateMetaByDatatableColumn: jest.fn(), + datatableUtilities: { + getIndexPattern: jest.fn(), + getAggConfig: jest.fn(), + isFilterable: jest.fn(), + }, createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx index 338eb4877a50..00429c8df0cb 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_exportable_embeddable.tsx @@ -23,18 +23,21 @@ export class ContactCardExportableEmbeddable extends ContactCardEmbeddable { public getInspectorAdapters = () => { return { tables: { - layer1: { - type: 'datatable', - columns: [ - { id: 'firstName', name: 'First Name' }, - { id: 'originalLastName', name: 'Last Name' }, - ], - rows: [ - { - firstName: this.getInput().firstName, - orignialLastName: this.getInput().lastName, - }, - ], + allowCsvExport: true, + tables: { + layer1: { + type: 'datatable', + columns: [ + { id: 'firstName', name: 'First Name' }, + { id: 'originalLastName', name: 'Last Name' }, + ], + rows: [ + { + firstName: this.getInput().firstName, + orignialLastName: this.getInput().lastName, + }, + ], + }, }, }, }; diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md index 60b694d628b7..03818fccda0b 100644 --- a/src/plugins/embeddable/public/public.api.md +++ b/src/plugins/embeddable/public/public.api.md @@ -109,10 +109,6 @@ export const ACTION_EDIT_PANEL = "editPanel"; export interface Adapters { // (undocumented) [key: string]: any; - // Warning: (ae-forgotten-export) The symbol "DataAdapter" needs to be exported by the entry point index.d.ts - // - // (undocumented) - data?: DataAdapter; // Warning: (ae-forgotten-export) The symbol "RequestAdapter" needs to be exported by the entry point index.d.ts // // (undocumented) diff --git a/src/plugins/expressions/common/execution/execution.test.ts b/src/plugins/expressions/common/execution/execution.test.ts index 10a18d0cbf43..9819c721d727 100644 --- a/src/plugins/expressions/common/execution/execution.test.ts +++ b/src/plugins/expressions/common/execution/execution.test.ts @@ -220,10 +220,10 @@ describe('Execution', () => { }); describe('inspector adapters', () => { - test('by default, "data" and "requests" inspector adapters are available', async () => { + test('by default, "tables" and "requests" inspector adapters are available', async () => { const { result } = (await run('introspectContext key="inspectorAdapters"')) as any; expect(result).toMatchObject({ - data: expect.any(Object), + tables: expect.any(Object), requests: expect.any(Object), }); }); diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index c5c7d82e223b..609022f8a55c 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -23,7 +23,7 @@ import { Executor } from '../executor'; import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; import { abortSignalToPromise, Defer, now } from '../../../kibana_utils/common'; -import { RequestAdapter, DataAdapter, Adapters } from '../../../inspector/common'; +import { RequestAdapter, Adapters } from '../../../inspector/common'; import { isExpressionValueError, ExpressionValueError } from '../expression_types/specs/error'; import { ExpressionAstExpression, @@ -34,11 +34,12 @@ import { ExpressionAstNode, } from '../ast'; import { ExecutionContext, DefaultInspectorAdapters } from './types'; -import { getType, ExpressionValue } from '../expression_types'; +import { getType, ExpressionValue, Datatable } from '../expression_types'; import { ArgumentType, ExpressionFunction } from '../expression_functions'; import { getByAlias } from '../util/get_by_alias'; import { ExecutionContract } from './execution_contract'; import { ExpressionExecutionParams } from '../service'; +import { TablesAdapter } from '../util/tables_adapter'; /** * AbortController is not available in Node until v15, so we @@ -72,7 +73,7 @@ export interface ExecutionParams { const createDefaultInspectorAdapters = (): DefaultInspectorAdapters => ({ requests: new RequestAdapter(), - data: new DataAdapter(), + tables: new TablesAdapter(), }); export class Execution< @@ -166,6 +167,9 @@ export class Execution< ast, }); + const inspectorAdapters = + execution.params.inspectorAdapters || createDefaultInspectorAdapters(); + this.context = { getSearchContext: () => this.execution.params.searchContext || {}, getSearchSessionId: () => execution.params.searchSessionId, @@ -175,7 +179,10 @@ export class Execution< variables: execution.params.variables || {}, types: executor.getTypes(), abortSignal: this.abortController.signal, - inspectorAdapters: execution.params.inspectorAdapters || createDefaultInspectorAdapters(), + inspectorAdapters, + logDatatable: (name: string, datatable: Datatable) => { + inspectorAdapters.tables[name] = datatable; + }, ...(execution.params as any).extraContext, }; } diff --git a/src/plugins/expressions/common/execution/execution_contract.test.ts b/src/plugins/expressions/common/execution/execution_contract.test.ts index eaf7e6ea862e..0a6704a8cb2f 100644 --- a/src/plugins/expressions/common/execution/execution_contract.test.ts +++ b/src/plugins/expressions/common/execution/execution_contract.test.ts @@ -71,7 +71,7 @@ describe('ExecutionContract', () => { const execution = createExecution('foo bar=123'); const contract = new ExecutionContract(execution); expect(contract.inspect()).toMatchObject({ - data: expect.any(Object), + tables: expect.any(Object), requests: expect.any(Object), }); }); diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index a41f97118c4b..a1b25c3802f4 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -21,8 +21,9 @@ import type { KibanaRequest } from 'src/core/server'; import { ExpressionType, SerializableState } from '../expression_types'; -import { Adapters, DataAdapter, RequestAdapter } from '../../../inspector/common'; +import { Adapters, RequestAdapter } from '../../../inspector/common'; import { SavedObject, SavedObjectAttributes } from '../../../../core/public'; +import { TablesAdapter } from '../util/tables_adapter'; /** * `ExecutionContext` is an object available to all functions during a single execution; @@ -89,5 +90,5 @@ export interface ExecutionContext< */ export interface DefaultInspectorAdapters extends Adapters { requests: RequestAdapter; - data: DataAdapter; + tables: TablesAdapter; } diff --git a/src/plugins/expressions/common/util/index.ts b/src/plugins/expressions/common/util/index.ts index ee677d54ce96..ea900687650f 100644 --- a/src/plugins/expressions/common/util/index.ts +++ b/src/plugins/expressions/common/util/index.ts @@ -19,3 +19,4 @@ export * from './create_error'; export * from './get_by_alias'; +export * from './tables_adapter'; diff --git a/src/plugins/inspector/common/adapters/data/formatted_data.ts b/src/plugins/expressions/common/util/tables_adapter.ts similarity index 66% rename from src/plugins/inspector/common/adapters/data/formatted_data.ts rename to src/plugins/expressions/common/util/tables_adapter.ts index 08c956f27d01..30b869818f99 100644 --- a/src/plugins/inspector/common/adapters/data/formatted_data.ts +++ b/src/plugins/expressions/common/util/tables_adapter.ts @@ -17,6 +17,18 @@ * under the License. */ -export class FormattedData { - constructor(public readonly raw: any, public readonly formatted: any) {} +import { EventEmitter } from 'events'; +import { Datatable } from '../expression_types/specs'; + +export class TablesAdapter extends EventEmitter { + private _tables: { [key: string]: Datatable } = {}; + + public logDatatable(name: string, datatable: Datatable): void { + this._tables[name] = datatable; + this.emit('change', this.tables); + } + + public get tables() { + return this._tables; + } } diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 385055bc2fdc..cd43c90d5ff4 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -117,4 +117,5 @@ export { ExpressionsService, ExpressionsServiceSetup, ExpressionsServiceStart, + TablesAdapter, } from '../common'; diff --git a/src/plugins/expressions/public/loader.test.ts b/src/plugins/expressions/public/loader.test.ts index 598b614a326a..0508b36fad38 100644 --- a/src/plugins/expressions/public/loader.test.ts +++ b/src/plugins/expressions/public/loader.test.ts @@ -166,7 +166,7 @@ describe('ExpressionLoader', () => { it('inspect() returns correct inspector adapters', () => { const expressionDataHandler = new ExpressionLoader(element, expressionString, {}); - expect(expressionDataHandler.inspect()).toHaveProperty('data'); + expect(expressionDataHandler.inspect()).toHaveProperty('tables'); expect(expressionDataHandler.inspect()).toHaveProperty('requests'); }); }); diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md index 6eb0e71c58e3..bb1f5dd9270d 100644 --- a/src/plugins/expressions/public/public.api.md +++ b/src/plugins/expressions/public/public.api.md @@ -1096,6 +1096,18 @@ export interface SerializedFieldFormat> { // @public (undocumented) export type Style = ExpressionTypeStyle; +// Warning: (ae-missing-release-tag) "TablesAdapter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class TablesAdapter extends EventEmitter { + // (undocumented) + logDatatable(name: string, datatable: Datatable): void; + // (undocumented) + get tables(): { + [key: string]: Datatable; + }; + } + // Warning: (ae-missing-release-tag) "TextAlignment" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/src/plugins/inspector/common/adapters/data/data_adapter.ts b/src/plugins/inspector/common/adapters/data/data_adapter.ts deleted file mode 100644 index a21aa7db3914..000000000000 --- a/src/plugins/inspector/common/adapters/data/data_adapter.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { EventEmitter } from 'events'; -import { TabularCallback, TabularHolder, TabularLoaderOptions } from './types'; - -export class DataAdapter extends EventEmitter { - private tabular?: TabularCallback; - private tabularOptions?: TabularLoaderOptions; - - public setTabularLoader(callback: TabularCallback, options: TabularLoaderOptions = {}): void { - this.tabular = callback; - this.tabularOptions = options; - this.emit('change', 'tabular'); - } - - public getTabular(): Promise { - if (!this.tabular || !this.tabularOptions) { - return Promise.resolve({ data: null, options: {} }); - } - const options = this.tabularOptions; - return Promise.resolve(this.tabular()).then((data) => ({ data, options })); - } -} diff --git a/src/plugins/inspector/common/adapters/data/data_adapters.test.ts b/src/plugins/inspector/common/adapters/data/data_adapters.test.ts deleted file mode 100644 index 7cc52807548f..000000000000 --- a/src/plugins/inspector/common/adapters/data/data_adapters.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { DataAdapter } from './data_adapter'; - -describe('DataAdapter', () => { - let adapter: DataAdapter; - - beforeEach(() => { - adapter = new DataAdapter(); - }); - - describe('getTabular()', () => { - it('should return a null promise when called before initialized', () => { - expect(adapter.getTabular()).resolves.toEqual({ - data: null, - options: {}, - }); - }); - - it('should call the provided callback and resolve with its value', async () => { - const data = { columns: [], rows: [] }; - const spy = jest.fn(() => data); - adapter.setTabularLoader(spy); - expect(spy).not.toBeCalled(); - const result = await adapter.getTabular(); - expect(spy).toBeCalled(); - expect(result.data).toBe(data); - }); - - it('should pass through options specified via setTabularLoader', async () => { - const data = { columns: [], rows: [] }; - adapter.setTabularLoader(() => data, { returnsFormattedValues: true }); - const result = await adapter.getTabular(); - expect(result.options).toEqual({ returnsFormattedValues: true }); - }); - - it('should return options set when starting loading data', async () => { - const data = { columns: [], rows: [] }; - adapter.setTabularLoader(() => data, { returnsFormattedValues: true }); - const waitForResult = adapter.getTabular(); - adapter.setTabularLoader(() => data, { returnsFormattedValues: false }); - const result = await waitForResult; - expect(result.options).toEqual({ returnsFormattedValues: true }); - }); - }); - - it('should emit a "tabular" event when a new tabular loader is specified', () => { - const data = { columns: [], rows: [] }; - const spy = jest.fn(); - adapter.once('change', spy); - adapter.setTabularLoader(() => data); - expect(spy).toBeCalled(); - }); -}); diff --git a/src/plugins/inspector/common/adapters/data/index.ts b/src/plugins/inspector/common/adapters/data/index.ts deleted file mode 100644 index a8b1abcd8cd7..000000000000 --- a/src/plugins/inspector/common/adapters/data/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export * from './data_adapter'; -export * from './formatted_data'; -export * from './types'; diff --git a/src/plugins/inspector/common/adapters/data/types.ts b/src/plugins/inspector/common/adapters/data/types.ts deleted file mode 100644 index 040724f4ae36..000000000000 --- a/src/plugins/inspector/common/adapters/data/types.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export interface TabularDataValue { - formatted: string; - raw: unknown; -} - -export interface TabularDataColumn { - name: string; - field: string; - filter?: (value: TabularDataValue) => void; - filterOut?: (value: TabularDataValue) => void; -} - -export type TabularDataRow = Record; - -export interface TabularData { - columns: TabularDataColumn[]; - rows: TabularDataRow[]; -} - -export type TabularCallback = () => TabularData | Promise; - -export interface TabularHolder { - data: TabularData | null; - options: TabularLoaderOptions; -} - -export interface TabularLoaderOptions { - returnsFormattedValues?: boolean; -} diff --git a/src/plugins/inspector/common/adapters/index.ts b/src/plugins/inspector/common/adapters/index.ts index 0c6319a2905a..152d7c54d7d8 100644 --- a/src/plugins/inspector/common/adapters/index.ts +++ b/src/plugins/inspector/common/adapters/index.ts @@ -17,6 +17,5 @@ * under the License. */ -export * from './data'; export * from './request'; export * from './types'; diff --git a/src/plugins/inspector/common/adapters/types.ts b/src/plugins/inspector/common/adapters/types.ts index b51c3e56c749..ee56c994be46 100644 --- a/src/plugins/inspector/common/adapters/types.ts +++ b/src/plugins/inspector/common/adapters/types.ts @@ -17,14 +17,12 @@ * under the License. */ -import type { DataAdapter } from './data'; import type { RequestAdapter } from './request'; /** * The interface that the adapters used to open an inspector have to fullfill. */ export interface Adapters { - data?: DataAdapter; requests?: RequestAdapter; [key: string]: any; } diff --git a/src/plugins/inspector/common/index.ts b/src/plugins/inspector/common/index.ts index c5755b22095d..f9f486521a76 100644 --- a/src/plugins/inspector/common/index.ts +++ b/src/plugins/inspector/common/index.ts @@ -19,15 +19,9 @@ export { Adapters, - DataAdapter, - FormattedData, RequestAdapter, RequestStatistic, RequestStatistics, RequestStatus, RequestResponder, - TabularData, - TabularDataColumn, - TabularDataRow, - TabularDataValue, } from './adapters'; diff --git a/src/plugins/inspector/public/plugin.tsx b/src/plugins/inspector/public/plugin.tsx index 07ef7c8fbab0..d3d867344a2a 100644 --- a/src/plugins/inspector/public/plugin.tsx +++ b/src/plugins/inspector/public/plugin.tsx @@ -26,7 +26,7 @@ import { InspectorOptions, InspectorSession } from './types'; import { InspectorPanel } from './ui/inspector_panel'; import { Adapters } from '../common'; -import { getRequestsViewDescription, getDataViewDescription } from './views'; +import { getRequestsViewDescription } from './views'; export interface Setup { registerView: InspectorViewRegistry['register']; @@ -70,7 +70,6 @@ export class InspectorPublicPlugin implements Plugin { public async setup(core: CoreSetup) { this.views = new InspectorViewRegistry(); - this.views.register(getDataViewDescription()); this.views.register(getRequestsViewDescription()); return { diff --git a/src/plugins/inspector/public/test/is_available.test.ts b/src/plugins/inspector/public/test/is_available.test.ts index c38d9d7a3f82..1f5220fc07a6 100644 --- a/src/plugins/inspector/public/test/is_available.test.ts +++ b/src/plugins/inspector/public/test/is_available.test.ts @@ -18,19 +18,12 @@ */ import { inspectorPluginMock } from '../mocks'; -import { DataAdapter, RequestAdapter } from '../../common/adapters'; +import { RequestAdapter } from '../../common/adapters'; -const adapter1 = new DataAdapter(); const adapter2 = new RequestAdapter(); describe('inspector', () => { describe('isAvailable()', () => { - it('should return false if no view would be available', async () => { - const { doStart } = await inspectorPluginMock.createPlugin(); - const start = await doStart(); - expect(start.isAvailable({ adapter1 })).toBe(false); - }); - it('should return true if views would be available, false otherwise', async () => { const { setup, doStart } = await inspectorPluginMock.createPlugin(); @@ -44,7 +37,6 @@ describe('inspector', () => { const start = await doStart(); - expect(start.isAvailable({ adapter1 })).toBe(true); expect(start.isAvailable({ adapter2 })).toBe(false); }); }); diff --git a/src/plugins/inspector/public/views/_index.scss b/src/plugins/inspector/public/views/_index.scss index 620a33e96584..43fbc09e921c 100644 --- a/src/plugins/inspector/public/views/_index.scss +++ b/src/plugins/inspector/public/views/_index.scss @@ -1,2 +1 @@ -@import './data/index'; @import './requests/index'; diff --git a/src/plugins/inspector/public/views/data/components/data_view.tsx b/src/plugins/inspector/public/views/data/components/data_view.tsx deleted file mode 100644 index 324094d8f93d..000000000000 --- a/src/plugins/inspector/public/views/data/components/data_view.tsx +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingChart, - EuiPanel, - EuiSpacer, - EuiText, -} from '@elastic/eui'; - -import { DataTableFormat } from './data_table'; -import { InspectorViewProps } from '../../../types'; -import { Adapters } from '../../../../common'; -import { - TabularLoaderOptions, - TabularData, - TabularHolder, -} from '../../../../common/adapters/data/types'; -import { IUiSettingsClient } from '../../../../../../core/public'; -import { withKibana, KibanaReactContextValue } from '../../../../../kibana_react/public'; - -interface DataViewComponentState { - tabularData: TabularData | null; - tabularOptions: TabularLoaderOptions; - adapters: Adapters; - tabularPromise: Promise | null; -} - -interface DataViewComponentProps extends InspectorViewProps { - kibana: KibanaReactContextValue<{ uiSettings: IUiSettingsClient }>; -} - -class DataViewComponent extends Component { - static propTypes = { - adapters: PropTypes.object.isRequired, - title: PropTypes.string.isRequired, - kibana: PropTypes.object, - }; - - state = {} as DataViewComponentState; - _isMounted = false; - - static getDerivedStateFromProps( - nextProps: DataViewComponentProps, - state: DataViewComponentState - ) { - if (state && nextProps.adapters === state.adapters) { - return null; - } - - return { - adapters: nextProps.adapters, - tabularData: null, - tabularOptions: {}, - tabularPromise: nextProps.adapters.data!.getTabular(), - }; - } - - onUpdateData = (type: string) => { - if (type === 'tabular') { - this.setState({ - tabularData: null, - tabularOptions: {}, - tabularPromise: this.props.adapters.data!.getTabular(), - }); - } - }; - - async finishLoadingData() { - const { tabularPromise } = this.state; - - if (tabularPromise) { - const tabularData: TabularHolder = await tabularPromise; - - if (this._isMounted) { - this.setState({ - tabularData: tabularData.data, - tabularOptions: tabularData.options, - tabularPromise: null, - }); - } - } - } - - componentDidMount() { - this._isMounted = true; - this.props.adapters.data!.on('change', this.onUpdateData); - this.finishLoadingData(); - } - - componentWillUnmount() { - this._isMounted = false; - this.props.adapters.data!.removeListener('change', this.onUpdateData); - } - - componentDidUpdate() { - this.finishLoadingData(); - } - - static renderNoData() { - return ( - - - - } - body={ - -

- -

-
- } - /> - ); - } - - static renderLoading() { - return ( - - - - - - -

- -

-
-
-
-
- ); - } - - render() { - if (this.state.tabularPromise) { - return DataViewComponent.renderLoading(); - } else if (!this.state.tabularData) { - return DataViewComponent.renderNoData(); - } - - return ( - - ); - } -} - -// default export required for React.Lazy -// eslint-disable-next-line import/no-default-export -export default withKibana(DataViewComponent); diff --git a/src/plugins/inspector/public/views/index.ts b/src/plugins/inspector/public/views/index.ts index c75ecfbd3e99..8aef30a68a32 100644 --- a/src/plugins/inspector/public/views/index.ts +++ b/src/plugins/inspector/public/views/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { getDataViewDescription } from './data'; export { getRequestsViewDescription } from './requests'; diff --git a/src/plugins/region_map/public/region_map_fn.js b/src/plugins/region_map/public/region_map_fn.js index fdb7c273720f..cc99a5595d09 100644 --- a/src/plugins/region_map/public/region_map_fn.js +++ b/src/plugins/region_map/public/region_map_fn.js @@ -34,9 +34,12 @@ export const createRegionMapFn = () => ({ default: '"{}"', }, }, - fn(context, args) { + fn(context, args, handlers) { const visConfig = JSON.parse(args.visConfig); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } return { type: 'render', as: 'visualization', diff --git a/src/plugins/region_map/public/region_map_fn.test.js b/src/plugins/region_map/public/region_map_fn.test.js index 32467541dee0..d83d04be6d38 100644 --- a/src/plugins/region_map/public/region_map_fn.test.js +++ b/src/plugins/region_map/public/region_map_fn.test.js @@ -57,7 +57,11 @@ describe('interpreter/functions#regionmap', () => { }; it('returns an object with the correct structure', () => { - const actual = fn(context, { visConfig: JSON.stringify(visConfig) }); + const actual = fn( + context, + { visConfig: JSON.stringify(visConfig) }, + { logDatatable: jest.fn() } + ); expect(actual).toMatchSnapshot(); }); }); diff --git a/src/plugins/tile_map/public/tile_map_fn.js b/src/plugins/tile_map/public/tile_map_fn.js index 3253598d98d9..7a5f36be1eb9 100644 --- a/src/plugins/tile_map/public/tile_map_fn.js +++ b/src/plugins/tile_map/public/tile_map_fn.js @@ -34,7 +34,7 @@ export const createTileMapFn = () => ({ default: '"{}"', }, }, - fn(context, args) { + fn(context, args, handlers) { const visConfig = JSON.parse(args.visConfig); const { geohash, metric, geocentroid } = visConfig.dimensions; const convertedData = convertToGeoJson(context, { @@ -47,6 +47,9 @@ export const createTileMapFn = () => ({ convertedData.meta.geohash = context.columns[geohash.accessor].meta; } + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } return { type: 'render', as: 'visualization', diff --git a/src/plugins/tile_map/public/tilemap_fn.test.js b/src/plugins/tile_map/public/tilemap_fn.test.js index df9fc10a7303..895842ea1e8f 100644 --- a/src/plugins/tile_map/public/tilemap_fn.test.js +++ b/src/plugins/tile_map/public/tilemap_fn.test.js @@ -80,13 +80,17 @@ describe('interpreter/functions#tilemap', () => { }); it('returns an object with the correct structure', () => { - const actual = fn(context, { visConfig: JSON.stringify(visConfig) }); + const actual = fn( + context, + { visConfig: JSON.stringify(visConfig) }, + { logDatatable: jest.fn() } + ); expect(actual).toMatchSnapshot(); }); it('calls response handler with correct values', () => { const { geohash, metric, geocentroid } = visConfig.dimensions; - fn(context, { visConfig: JSON.stringify(visConfig) }); + fn(context, { visConfig: JSON.stringify(visConfig) }, { logDatatable: jest.fn() }); expect(convertToGeoJson).toHaveBeenCalledTimes(1); expect(convertToGeoJson).toHaveBeenCalledWith(context, { geohash, diff --git a/src/plugins/vis_type_metric/public/metric_vis_fn.ts b/src/plugins/vis_type_metric/public/metric_vis_fn.ts index 20de22f50e63..ae6dc6683852 100644 --- a/src/plugins/vis_type_metric/public/metric_vis_fn.ts +++ b/src/plugins/vis_type_metric/public/metric_vis_fn.ts @@ -160,7 +160,7 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ }), }, }, - fn(input, args) { + fn(input, args, handlers) { const dimensions: DimensionsVisParam = { metrics: args.metric, }; @@ -175,6 +175,9 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({ const fontSize = Number.parseInt(args.font.spec.fontSize || '', 10); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'metric_vis', diff --git a/src/plugins/vis_type_table/public/table_vis_fn.ts b/src/plugins/vis_type_table/public/table_vis_fn.ts index 28990f28caf3..530f50ffd89b 100644 --- a/src/plugins/vis_type_table/public/table_vis_fn.ts +++ b/src/plugins/vis_type_table/public/table_vis_fn.ts @@ -55,10 +55,13 @@ export const createTableVisFn = (): TableExpressionFunctionDefinition => ({ help: '', }, }, - fn(input, args) { + fn(input, args, handlers) { const visConfig = args.visConfig && JSON.parse(args.visConfig); const convertedData = tableVisResponseHandler(input, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'table_vis', diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts b/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts index ff59572e0817..3ed203dd22ef 100644 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts +++ b/src/plugins/vis_type_tagcloud/public/tag_cloud_fn.ts @@ -95,7 +95,7 @@ export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({ }), }, }, - fn(input, args) { + fn(input, args, handlers) { const visParams = { scale: args.scale, orientation: args.orientation, @@ -109,6 +109,9 @@ export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({ visParams.bucket = args.bucket; } + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } return { type: 'render', as: 'tagloud_vis', diff --git a/src/plugins/vis_type_vislib/public/pie_fn.ts b/src/plugins/vis_type_vislib/public/pie_fn.ts index c9da9e9bd9fa..00aa73128c34 100644 --- a/src/plugins/vis_type_vislib/public/pie_fn.ts +++ b/src/plugins/vis_type_vislib/public/pie_fn.ts @@ -59,10 +59,14 @@ export const createPieVisFn = (): VisTypeVislibPieExpressionFunctionDefinition = help: 'vislib pie vis config', }, }, - fn(input, args) { + fn(input, args, handlers) { const visConfig = JSON.parse(args.visConfig) as PieVisParams; const visData = vislibSlicesResponseHandler(input, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', input); + } + return { type: 'render', as: vislibVisName, diff --git a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts index c5fa8f36f43e..dc4a6314fb01 100644 --- a/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts +++ b/src/plugins/vis_type_vislib/public/vis_type_vislib_vis_fn.ts @@ -64,11 +64,15 @@ export const createVisTypeVislibVisFn = (): VisTypeVislibExpressionFunctionDefin help: 'vislib vis config', }, }, - fn(context, args) { + fn(context, args, handlers) { const visType = args.type; const visConfig = JSON.parse(args.visConfig) as BasicVislibParams; const visData = vislibSeriesResponseHandler(context, visConfig.dimensions); + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } + return { type: 'render', as: vislibVisName, diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/app/components/main.tsx b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/app/components/main.tsx index 8c62fa246dd5..9ff5bc3d5937 100644 --- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/app/components/main.tsx +++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/public/app/components/main.tsx @@ -20,8 +20,12 @@ import React from 'react'; import { EuiPage, EuiPageBody, EuiPageContent, EuiPageContentHeader } from '@elastic/eui'; import { first } from 'rxjs/operators'; -import { IInterpreterRenderHandlers, ExpressionValue } from 'src/plugins/expressions'; -import { RequestAdapter, DataAdapter } from '../../../../../../../src/plugins/inspector/public'; +import { + IInterpreterRenderHandlers, + ExpressionValue, + TablesAdapter, +} from '../../../../../../../src/plugins/expressions/public'; +import { RequestAdapter } from '../../../../../../../src/plugins/inspector/public'; import { Adapters, ExpressionRenderHandler } from '../../types'; import { getExpressions } from '../../services'; @@ -58,7 +62,7 @@ class Main extends React.Component<{}, State> { this.setState({ expression }); const adapters: Adapters = { requests: new RequestAdapter(), - data: new DataAdapter(), + tables: new TablesAdapter(), }; return getExpressions() .execute(expression, context || { type: 'null' }, { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx index 33deb0356660..deb48027512c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.test.tsx @@ -290,7 +290,7 @@ describe('workspace_panel', () => { const onData = expressionRendererMock.mock.calls[0][0].onData$!; const tableData = { table1: { columns: [], rows: [] } }; - onData(undefined, { tables: tableData }); + onData(undefined, { tables: { tables: tableData } }); expect(dispatch).toHaveBeenCalledWith({ type: 'UPDATE_ACTIVE_DATA', tables: tableData }); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 52d1b2729c7a..8820f26479cf 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -51,9 +51,9 @@ import { import { VIS_EVENT_TO_TRIGGER } from '../../../../../../../src/plugins/visualizations/public'; import { WorkspacePanelWrapper } from './workspace_panel_wrapper'; import { DropIllustration } from '../../../assets/drop_illustration'; -import { LensInspectorAdapters } from '../../types'; import { getOriginalRequestErrorMessage } from '../../error_helper'; import { validateDatasourceAndVisualization } from '../state_helpers'; +import { DefaultInspectorAdapters } from '../../../../../../../src/plugins/expressions/common'; export interface WorkspacePanelProps { activeVisualizationId: string | null; @@ -382,11 +382,11 @@ export const InnerVisualizationWrapper = ({ ); const onData$ = useCallback( - (data: unknown, inspectorAdapters?: LensInspectorAdapters) => { + (data: unknown, inspectorAdapters?: Partial) => { if (inspectorAdapters && inspectorAdapters.tables) { dispatch({ type: 'UPDATE_ACTIVE_DATA', - tables: inspectorAdapters.tables, + tables: inspectorAdapters.tables.tables, }); } }, diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx index 6c86ae5cff2c..190470e6c423 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx @@ -20,7 +20,7 @@ import { PaletteOutput } from 'src/plugins/charts/public'; import { Subscription } from 'rxjs'; import { toExpression, Ast } from '@kbn/interpreter/common'; -import { RenderMode } from 'src/plugins/expressions'; +import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions'; import { map, distinctUntilChanged, skip } from 'rxjs/operators'; import isEqual from 'fast-deep-equal'; import { @@ -50,7 +50,6 @@ import { IndexPatternsContract } from '../../../../../../src/plugins/data/public import { getEditPath, DOC_TYPE } from '../../../common'; import { IBasePath } from '../../../../../../src/core/public'; import { LensAttributeService } from '../../lens_attribute_service'; -import { LensInspectorAdapters } from '../types'; export type LensSavedObjectAttributes = Omit; @@ -92,7 +91,7 @@ export class Embeddable private subscription: Subscription; private autoRefreshFetchSubscription: Subscription; private isInitialized = false; - private activeData: LensInspectorAdapters | undefined; + private activeData: Partial | undefined; private externalSearchContext: { timeRange?: TimeRange; @@ -229,7 +228,7 @@ export class Embeddable private updateActiveData = ( data: unknown, - inspectorAdapters?: LensInspectorAdapters | undefined + inspectorAdapters?: Partial | undefined ) => { this.activeData = inspectorAdapters; }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx index 2fc1cfee82fd..e2607886a421 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx @@ -14,9 +14,8 @@ import { ReactExpressionRendererProps, } from 'src/plugins/expressions/public'; import { ExecutionContextSearch } from 'src/plugins/data/public'; -import { RenderMode } from 'src/plugins/expressions'; +import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions'; import { getOriginalRequestErrorMessage } from '../error_helper'; -import { LensInspectorAdapters } from '../types'; export interface ExpressionWrapperProps { ExpressionRenderer: ReactExpressionRendererType; @@ -25,7 +24,10 @@ export interface ExpressionWrapperProps { searchContext: ExecutionContextSearch; searchSessionId?: string; handleEvent: (event: ExpressionRendererEvent) => void; - onData$: (data: unknown, inspectorAdapters?: LensInspectorAdapters | undefined) => void; + onData$: ( + data: unknown, + inspectorAdapters?: Partial | undefined + ) => void; renderMode?: RenderMode; hasCompatibleActions?: ReactExpressionRendererProps['hasCompatibleActions']; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts index 02c07d809e09..5521d585262d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts @@ -7,8 +7,12 @@ import moment from 'moment'; import { mergeTables } from './merge_tables'; import { ExpressionValueSearchContext } from 'src/plugins/data/public'; -import { Datatable, ExecutionContext } from 'src/plugins/expressions'; -import { LensInspectorAdapters } from './types'; +import { + Datatable, + ExecutionContext, + DefaultInspectorAdapters, + TablesAdapter, +} from 'src/plugins/expressions'; describe('lens_merge_tables', () => { const sampleTable1: Datatable = { @@ -50,12 +54,15 @@ describe('lens_merge_tables', () => { }); it('should store the current tables in the tables inspector', () => { - const adapters: LensInspectorAdapters = { tables: {} }; + const adapters: DefaultInspectorAdapters = { + tables: new TablesAdapter(), + requests: {} as never, + }; mergeTables.fn(null, { layerIds: ['first', 'second'], tables: [sampleTable1, sampleTable2] }, { inspectorAdapters: adapters, - } as ExecutionContext); - expect(adapters.tables!.first).toBe(sampleTable1); - expect(adapters.tables!.second).toBe(sampleTable2); + } as ExecutionContext); + expect(adapters.tables!.tables.first).toBe(sampleTable1); + expect(adapters.tables!.tables.second).toBe(sampleTable2); }); it('should pass the date range along', () => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts index 109b30144fc2..b13efa41ff6c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts @@ -14,7 +14,7 @@ import { ExpressionValueSearchContext, search } from '../../../../../src/plugins const { toAbsoluteDates } = search.aggs; import { LensMultiTable } from '../types'; -import { LensInspectorAdapters } from './types'; +import { Adapters } from '../../../../../src/plugins/inspector/common'; interface MergeTables { layerIds: string[]; @@ -26,7 +26,7 @@ export const mergeTables: ExpressionFunctionDefinition< ExpressionValueSearchContext | null, MergeTables, LensMultiTable, - ExecutionContext + ExecutionContext > = { name: 'lens_merge_tables', type: 'lens_multitable', @@ -48,17 +48,14 @@ export const mergeTables: ExpressionFunctionDefinition< }, inputTypes: ['kibana_context', 'null'], fn(input, { layerIds, tables }, context) { - if (!context.inspectorAdapters) { - context.inspectorAdapters = {}; - } - if (!context.inspectorAdapters.tables) { - context.inspectorAdapters.tables = {}; - } const resultTables: Record = {}; tables.forEach((table, index) => { resultTables[layerIds[index]] = table; // adapter is always defined at that point because we make sure by the beginning of the function - context.inspectorAdapters.tables![layerIds[index]] = table; + if (context?.inspectorAdapters?.tables) { + context.inspectorAdapters.tables.allowCsvExport = true; + context.inspectorAdapters.tables.logDatatable(layerIds[index], table); + } }); return { type: 'lens_multitable', diff --git a/x-pack/plugins/lens/public/editor_frame_service/types.ts b/x-pack/plugins/lens/public/editor_frame_service/types.ts index 2da95ec2fd66..5117c1ef85e6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/types.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/types.ts @@ -7,6 +7,3 @@ import { Datatable } from 'src/plugins/expressions'; export type TableInspectorAdapter = Record; -export interface LensInspectorAdapters { - tables?: TableInspectorAdapter; -} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index cfb923420df8..a50c91bb3989 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2711,22 +2711,6 @@ "inputControl.vis.listControl.selectPlaceholder": "選択してください…", "inputControl.vis.listControl.selectTextPlaceholder": "選択してください…", "inspector.closeButton": "インスペクターを閉じる", - "inspector.data.dataDescriptionTooltip": "ビジュアライゼーションの元のデータを表示", - "inspector.data.dataTitle": "データ", - "inspector.data.downloadCSVButtonLabel": "CSV をダウンロード", - "inspector.data.downloadCSVToggleButtonLabel": "CSV をダウンロード", - "inspector.data.downloadOptionsUnsavedFilename": "(未保存)", - "inspector.data.filterForValueButtonAriaLabel": "値でフィルタリング", - "inspector.data.filterForValueButtonTooltip": "値でフィルタリング", - "inspector.data.filterOutValueButtonAriaLabel": "値を除外", - "inspector.data.filterOutValueButtonTooltip": "値を除外", - "inspector.data.formattedCSVButtonLabel": "フォーマット済み CSV", - "inspector.data.formattedCSVButtonTooltip": "データを表形式でダウンロード", - "inspector.data.gatheringDataLabel": "データを収集中", - "inspector.data.noDataAvailableDescription": "エレメントがデータを提供しませんでした。", - "inspector.data.noDataAvailableTitle": "利用可能なデータがありません", - "inspector.data.rawCSVButtonLabel": "CSV", - "inspector.data.rawCSVButtonTooltip": "日付をタイムスタンプとしてなど、提供されたデータをそのままダウンロードします", "inspector.reqTimestampDescription": "リクエストの開始が記録された時刻です", "inspector.reqTimestampKey": "リクエストのタイムスタンプ", "inspector.requests.descriptionRowIconAriaLabel": "説明", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8588fcaf51d9..1cfc0cbc38eb 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2712,22 +2712,6 @@ "inputControl.vis.listControl.selectPlaceholder": "选择......", "inputControl.vis.listControl.selectTextPlaceholder": "选择......", "inspector.closeButton": "关闭检查器", - "inspector.data.dataDescriptionTooltip": "查看可视化后面的数据", - "inspector.data.dataTitle": "数据", - "inspector.data.downloadCSVButtonLabel": "下载 CSV", - "inspector.data.downloadCSVToggleButtonLabel": "下载 CSV", - "inspector.data.downloadOptionsUnsavedFilename": "未保存", - "inspector.data.filterForValueButtonAriaLabel": "筛留值", - "inspector.data.filterForValueButtonTooltip": "筛留值", - "inspector.data.filterOutValueButtonAriaLabel": "筛除值", - "inspector.data.filterOutValueButtonTooltip": "筛除值", - "inspector.data.formattedCSVButtonLabel": "格式化 CSV", - "inspector.data.formattedCSVButtonTooltip": "以表格式下载数据", - "inspector.data.gatheringDataLabel": "正在收集数据", - "inspector.data.noDataAvailableDescription": "该元素未提供任何数据。", - "inspector.data.noDataAvailableTitle": "没有可用数据", - "inspector.data.rawCSVButtonLabel": "原始 CSV", - "inspector.data.rawCSVButtonTooltip": "按原样下载数据,例如将日期作为时间戳下载", "inspector.reqTimestampDescription": "记录请求启动的时间", "inspector.reqTimestampKey": "请求时间戳", "inspector.requests.descriptionRowIconAriaLabel": "描述", From 93dcaeea680e1010ad79582f4a1d661685662fc7 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Thu, 17 Dec 2020 06:21:06 -0600 Subject: [PATCH 29/38] [Metrics UI] Only allow one panel to be open at a time (#85977) * Only allow one panel to be open at a time * Move EuiOutsideClickDetector inside the portal Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/node_details/overlay.tsx | 99 ++++++++++--------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx index b0e6ab751f02..4541a55dbeca 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx @@ -8,6 +8,7 @@ import { EuiPortal, EuiTabs, EuiTab, EuiPanel, EuiTitle, EuiSpacer } from '@elas import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; +import { EuiOutsideClickDetector } from '@elastic/eui'; import { euiStyled } from '../../../../../../../observability/public'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; import { InventoryItemType } from '../../../../../../common/inventory_models/types'; @@ -70,52 +71,58 @@ export const NodeContextPopover = ({ return ( - - - - - -

{node.name}

-
-
- - - - - - - - - - - - - - -
- - - {tabs.map((tab, i) => ( - setSelectedTab(i)}> - {tab.name} - - ))} - -
- {tabs[selectedTab].content} -
+ + + + + + +

{node.name}

+
+
+ + + + + + + + + + + + + + +
+ + + {tabs.map((tab, i) => ( + setSelectedTab(i)} + > + {tab.name} + + ))} + +
+ {tabs[selectedTab].content} +
+
); }; From 210641900790019764b5b62c6f771873fa7662d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 17 Dec 2020 14:47:26 +0100 Subject: [PATCH 30/38] [Logs UI] Fix value completion in the logs stream query bar (#85772) This ensures that the correct index name pattern is passed as the fake `IIndexPattern` `title`. --- .../infra/public/containers/logs/log_source/log_source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts index f430e6b5e4d9..879d2d95d794 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_source/log_source.ts @@ -89,7 +89,7 @@ export const useLogSource = ({ sourceId, fetch }: { sourceId: string; fetch: Htt const derivedIndexPattern = useMemo( () => ({ fields: sourceStatus?.logIndexFields ?? [], - title: sourceConfiguration?.configuration.name ?? 'unknown', + title: sourceConfiguration?.configuration.logAlias ?? 'unknown', }), [sourceConfiguration, sourceStatus] ); From b70cabbdcba2fb7f652aea3e93ad207197c34515 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Thu, 17 Dec 2020 14:11:51 +0000 Subject: [PATCH 31/38] [ML] Fix sort order of data recognizer module cards (#86250) * [ML] Fix sort order of data recognizer module cards * [ML] Add sort by ID to server side recognize endpoint * [ML] Enhance docs for recognize endpoint success response. --- .../application/components/data_recognizer/data_recognizer.js | 3 +++ .../ml/server/models/data_recognizer/data_recognizer.ts | 2 ++ x-pack/plugins/ml/server/routes/modules.ts | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/public/application/components/data_recognizer/data_recognizer.js b/x-pack/plugins/ml/public/application/components/data_recognizer/data_recognizer.js index 5790b8bd239e..e4ed8f67fd78 100644 --- a/x-pack/plugins/ml/public/application/components/data_recognizer/data_recognizer.js +++ b/x-pack/plugins/ml/public/application/components/data_recognizer/data_recognizer.js @@ -29,6 +29,9 @@ export class DataRecognizer extends Component { // once the mount is complete, call the recognize endpoint to see if the index format is known to us, ml.recognizeIndex({ indexPatternTitle: this.indexPattern.title }) .then((resp) => { + // Sort results by title prior to display + resp.sort((res1, res2) => res1.title.localeCompare(res2.title)); + const results = resp.map((r) => ( res1.id.localeCompare(res2.id)); + return results; } diff --git a/x-pack/plugins/ml/server/routes/modules.ts b/x-pack/plugins/ml/server/routes/modules.ts index 0e5fde8a34c7..a9bceb61d5e6 100644 --- a/x-pack/plugins/ml/server/routes/modules.ts +++ b/x-pack/plugins/ml/server/routes/modules.ts @@ -133,10 +133,11 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) { * @apiName RecognizeIndex * @apiDescription By supplying an index pattern, discover if any of the modules are a match for data in that index. * @apiSchema (params) modulesIndexPatternTitleSchema - * @apiSuccess {object[]} modules Array of objects describing the modules which match the index pattern. + * @apiSuccess {object[]} modules Array of objects describing the modules which match the index pattern, sorted by module ID. * @apiSuccessExample {json} Success-Response: * [{ * "id": "nginx_ecs", + * "title": "Nginx access logs", * "query": { * "bool": { * "filter": [ From bf60796cd3459cfc6fa29a1e81ea4b31860a24b1 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 17 Dec 2020 15:14:17 +0100 Subject: [PATCH 32/38] [ML] Fix Anomaly Explorer data refresh with relative time bounds (#86142) * [ML] use time bounds from the timeFilter * [ML] add manual type casting for times --- .../ml/common/types/ml_url_generator.ts | 2 +- .../explorer/actions/load_explorer_data.ts | 17 +++++--- .../explorer/explorer_constants.ts | 1 - .../explorer/explorer_dashboard_service.ts | 5 +-- .../application/explorer/explorer_utils.d.ts | 2 +- .../explorer/hooks/use_selected_cells.ts | 43 +++++++++++++++---- .../reducers/explorer_reducer/reducer.ts | 23 +++------- .../reducers/explorer_reducer/state.ts | 3 -- .../explorer/swimlane_container.tsx | 4 +- .../application/routing/routes/explorer.tsx | 9 ---- 10 files changed, 56 insertions(+), 53 deletions(-) diff --git a/x-pack/plugins/ml/common/types/ml_url_generator.ts b/x-pack/plugins/ml/common/types/ml_url_generator.ts index c91e3615514f..fb432189c6dd 100644 --- a/x-pack/plugins/ml/common/types/ml_url_generator.ts +++ b/x-pack/plugins/ml/common/types/ml_url_generator.ts @@ -90,7 +90,7 @@ export interface ExplorerAppState { mlExplorerSwimlane: { selectedType?: 'overall' | 'viewBy'; selectedLanes?: string[]; - selectedTimes?: number[]; + selectedTimes?: [number, number]; showTopFieldValues?: boolean; viewByFieldName?: string; viewByPerPage?: number; diff --git a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts index 5712f3c4843b..297da075d6d6 100644 --- a/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts +++ b/x-pack/plugins/ml/public/application/explorer/actions/load_explorer_data.ts @@ -26,7 +26,6 @@ import { loadTopInfluencers, AppStateSelectedCells, ExplorerJob, - TimeRangeBounds, } from '../explorer_utils'; import { ExplorerState } from '../reducers'; import { useMlKibana, useTimefilter } from '../../contexts/kibana'; @@ -34,6 +33,7 @@ import { AnomalyTimelineService } from '../../services/anomaly_timeline_service' import { mlResultsServiceProvider } from '../../services/results_service'; import { isViewBySwimLaneData } from '../swimlane_container'; import { ANOMALY_SWIM_LANE_HARD_LIMIT } from '../explorer_constants'; +import { TimefilterContract } from '../../../../../../../src/plugins/data/public'; // Memoize the data fetching methods. // wrapWithLastRefreshArg() wraps any given function and preprends a `lastRefresh` argument @@ -63,7 +63,6 @@ const memoizedLoadTopInfluencers = memoize(loadTopInfluencers); const memoizedLoadAnomaliesTableData = memoize(loadAnomaliesTableData); export interface LoadExplorerDataConfig { - bounds: TimeRangeBounds; influencersFilterQuery: any; lastRefresh: number; noInfluencersConfigured: boolean; @@ -82,7 +81,6 @@ export interface LoadExplorerDataConfig { export const isLoadExplorerDataConfig = (arg: any): arg is LoadExplorerDataConfig => { return ( arg !== undefined && - arg.bounds !== undefined && arg.selectedJobs !== undefined && arg.selectedJobs !== null && arg.viewBySwimlaneFieldName !== undefined @@ -92,7 +90,10 @@ export const isLoadExplorerDataConfig = (arg: any): arg is LoadExplorerDataConfi /** * Fetches the data necessary for the Anomaly Explorer using observables. */ -const loadExplorerDataProvider = (anomalyTimelineService: AnomalyTimelineService) => { +const loadExplorerDataProvider = ( + anomalyTimelineService: AnomalyTimelineService, + timefilter: TimefilterContract +) => { const memoizedLoadOverallData = memoize( anomalyTimelineService.loadOverallData, anomalyTimelineService @@ -107,7 +108,6 @@ const loadExplorerDataProvider = (anomalyTimelineService: AnomalyTimelineService } const { - bounds, lastRefresh, influencersFilterQuery, noInfluencersConfigured, @@ -125,6 +125,9 @@ const loadExplorerDataProvider = (anomalyTimelineService: AnomalyTimelineService const selectionInfluencers = getSelectionInfluencers(selectedCells, viewBySwimlaneFieldName); const jobIds = getSelectionJobIds(selectedCells, selectedJobs); + + const bounds = timefilter.getBounds(); + const timerange = getSelectionTimeRange( selectedCells, swimlaneBucketInterval.asSeconds(), @@ -287,12 +290,12 @@ export const useExplorerData = (): [Partial | undefined, (d: any) } = useMlKibana(); const loadExplorerData = useMemo(() => { - const service = new AnomalyTimelineService( + const anomalyTimelineService = new AnomalyTimelineService( timefilter, uiSettings, mlResultsServiceProvider(mlApiServices) ); - return loadExplorerDataProvider(service); + return loadExplorerDataProvider(anomalyTimelineService, timefilter); }, []); const loadExplorerData$ = useMemo(() => new Subject(), []); diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts index 7440bf321341..3f5f016fc365 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_constants.ts @@ -20,7 +20,6 @@ export const EXPLORER_ACTION = { CLEAR_INFLUENCER_FILTER_SETTINGS: 'clearInfluencerFilterSettings', CLEAR_JOBS: 'clearJobs', JOB_SELECTION_CHANGE: 'jobSelectionChange', - SET_BOUNDS: 'setBounds', SET_CHARTS: 'setCharts', SET_EXPLORER_DATA: 'setExplorerData', SET_FILTER_DATA: 'setFilterData', diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts index 8a95e5c6adbd..2e718990d749 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_dashboard_service.ts @@ -19,7 +19,7 @@ import { DeepPartial } from '../../../common/types/common'; import { jobSelectionActionCreator } from './actions'; import { ExplorerChartsData } from './explorer_charts/explorer_charts_container_service'; import { EXPLORER_ACTION } from './explorer_constants'; -import { AppStateSelectedCells, TimeRangeBounds } from './explorer_utils'; +import { AppStateSelectedCells } from './explorer_utils'; import { explorerReducer, getExplorerDefaultState, ExplorerState } from './reducers'; import { ExplorerAppState } from '../../../common/types/ml_url_generator'; @@ -115,9 +115,6 @@ export const explorerService = { updateJobSelection: (selectedJobIds: string[]) => { explorerAction$.next(jobSelectionActionCreator(selectedJobIds)); }, - setBounds: (payload: TimeRangeBounds) => { - explorerAction$.next({ type: EXPLORER_ACTION.SET_BOUNDS, payload }); - }, setCharts: (payload: ExplorerChartsData) => { explorerAction$.next({ type: EXPLORER_ACTION.SET_CHARTS, payload }); }, diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_utils.d.ts b/x-pack/plugins/ml/public/application/explorer/explorer_utils.d.ts index 94690b74a6f8..143a281be695 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_utils.d.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_utils.d.ts @@ -186,7 +186,7 @@ export declare interface FilterData { export declare interface AppStateSelectedCells { type: SwimlaneType; lanes: string[]; - times: number[]; + times: [number, number]; showTopFieldValues?: boolean; viewByFieldName?: string; } diff --git a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts index f940fdc2387e..7a279afc22ae 100644 --- a/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts +++ b/x-pack/plugins/ml/public/application/explorer/hooks/use_selected_cells.ts @@ -7,15 +7,19 @@ import { useCallback, useEffect, useMemo } from 'react'; import { Duration } from 'moment'; import { SWIMLANE_TYPE } from '../explorer_constants'; -import { AppStateSelectedCells, TimeRangeBounds } from '../explorer_utils'; +import { AppStateSelectedCells } from '../explorer_utils'; import { ExplorerAppState } from '../../../../common/types/ml_url_generator'; +import { useTimefilter } from '../../contexts/kibana'; export const useSelectedCells = ( appState: ExplorerAppState, setAppState: (update: Partial) => void, - timeBounds: TimeRangeBounds | undefined, bucketInterval: Duration | undefined ): [AppStateSelectedCells | undefined, (swimlaneSelectedCells: AppStateSelectedCells) => void] => { + const timeFilter = useTimefilter(); + + const timeBounds = timeFilter.getBounds(); + // keep swimlane selection, restore selectedCells from AppState const selectedCells = useMemo(() => { return appState?.mlExplorerSwimlane?.selectedType !== undefined @@ -73,12 +77,7 @@ export const useSelectedCells = ( * Reset it entirely when it out of range. */ useEffect(() => { - if ( - timeBounds === undefined || - selectedCells?.times === undefined || - bucketInterval === undefined - ) - return; + if (selectedCells?.times === undefined || bucketInterval === undefined) return; let [selectedFrom, selectedTo] = selectedCells.times; @@ -108,7 +107,33 @@ export const useSelectedCells = ( times: [selectedFrom, selectedTo], }); } - }, [timeBounds, selectedCells, bucketInterval]); + }, [ + timeBounds.min?.valueOf(), + timeBounds.max?.valueOf(), + selectedCells, + bucketInterval?.asMilliseconds(), + ]); return [selectedCells, setSelectedCells]; }; + +export interface SelectionTimeRange { + earliestMs: number; + latestMs: number; +} + +export function getTimeBoundsFromSelection( + selectedCells: AppStateSelectedCells | undefined +): SelectionTimeRange | undefined { + if (selectedCells?.times === undefined) { + return; + } + + // time property of the cell data is an array, with the elements being + // the start times of the first and last cell selected. + return { + earliestMs: selectedCells.times[0] * 1000, + // Subtract 1 ms so search does not include start of next bucket. + latestMs: selectedCells.times[1] * 1000 - 1, + }; +} diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts index 546f782f4d86..04aebe2a39d8 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/reducer.ts @@ -12,7 +12,6 @@ import { Action } from '../../explorer_dashboard_service'; import { getClearedSelectedAnomaliesState, getDefaultSwimlaneData, - getSelectionTimeRange, getSwimlaneBucketInterval, getViewBySwimlaneOptions, } from '../../explorer_utils'; @@ -23,6 +22,7 @@ import { jobSelectionChange } from './job_selection_change'; import { ExplorerState } from './state'; import { setInfluencerFilterSettings } from './set_influencer_filter_settings'; import { setKqlQueryBarPlaceholder } from './set_kql_query_bar_placeholder'; +import { getTimeBoundsFromSelection } from '../../hooks/use_selected_cells'; export const explorerReducer = (state: ExplorerState, nextAction: Action): ExplorerState => { const { type, payload } = nextAction; @@ -48,10 +48,6 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo nextState = jobSelectionChange(state, payload); break; - case EXPLORER_ACTION.SET_BOUNDS: - nextState = { ...state, bounds: payload }; - break; - case EXPLORER_ACTION.SET_CHARTS: nextState = { ...state, @@ -144,7 +140,7 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo nextState = state; } - if (nextState.selectedJobs === null || nextState.bounds === undefined) { + if (nextState.selectedJobs === null) { return nextState; } @@ -164,21 +160,16 @@ export const explorerReducer = (state: ExplorerState, nextAction: Action): Explo selectedCells: nextState.selectedCells!, }); - const { bounds, selectedCells } = nextState; + const { selectedCells } = nextState; - const timerange = getSelectionTimeRange( - selectedCells, - swimlaneBucketInterval.asSeconds(), - bounds - ); + const timeRange = getTimeBoundsFromSelection(selectedCells); return { ...nextState, swimlaneBucketInterval, - viewByLoadedForTimeFormatted: - selectedCells !== undefined && selectedCells.showTopFieldValues === true - ? formatHumanReadableDateTime(timerange.earliestMs) - : null, + viewByLoadedForTimeFormatted: timeRange + ? formatHumanReadableDateTime(timeRange.earliestMs) + : null, viewBySwimlaneFieldName, viewBySwimlaneOptions, ...checkSelectedCells(nextState), diff --git a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts index 14b0a6033999..0ae09a794bc5 100644 --- a/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts +++ b/x-pack/plugins/ml/public/application/explorer/reducers/explorer_reducer/state.ts @@ -17,7 +17,6 @@ import { AnomaliesTableData, ExplorerJob, AppStateSelectedCells, - TimeRangeBounds, OverallSwimlaneData, SwimlaneData, ViewBySwimLaneData, @@ -27,7 +26,6 @@ import { SWIM_LANE_DEFAULT_PAGE_SIZE } from '../../explorer_constants'; export interface ExplorerState { annotations: AnnotationsTable; - bounds: TimeRangeBounds | undefined; chartsData: ExplorerChartsData; fieldFormatsLoading: boolean; filterActive: boolean; @@ -69,7 +67,6 @@ export function getExplorerDefaultState(): ExplorerState { annotationsData: [], aggregations: {}, }, - bounds: undefined, chartsData: getDefaultChartsData(), fieldFormatsLoading: false, filterActive: false, diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index b166d90f040a..101d4857a89b 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -255,7 +255,7 @@ export const SwimlaneContainer: FC = ({ onBrushEnd: (e: HeatmapBrushEvent) => { onCellsSelection({ lanes: e.y as string[], - times: e.x.map((v) => (v as number) / 1000), + times: e.x.map((v) => (v as number) / 1000) as [number, number], type: swimlaneType, viewByFieldName: swimlaneData.fieldName, }); @@ -326,7 +326,7 @@ export const SwimlaneContainer: FC = ({ const startTime = (cell.datum.x as number) / 1000; const payload = { lanes: [String(cell.datum.y)], - times: [startTime, startTime + swimlaneData.interval], + times: [startTime, startTime + swimlaneData.interval] as [number, number], type: swimlaneType, viewByFieldName: swimlaneData.fieldName, }; diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index 2126cbceae6b..15ce3847f4d9 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -119,13 +119,6 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim from: globalState.time.from, to: globalState.time.to, }); - - const timefilterBounds = timefilter.getBounds(); - // Only if both min/max bounds are valid moment times set the bounds. - // An invalid string restored from globalState might return `undefined`. - if (timefilterBounds?.min !== undefined && timefilterBounds?.max !== undefined) { - explorerService.setBounds(timefilterBounds); - } } }, [globalState?.time?.from, globalState?.time?.to]); @@ -208,7 +201,6 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim const [selectedCells, setSelectedCells] = useSelectedCells( explorerUrlState, setExplorerUrlState, - explorerState?.bounds, explorerState?.swimlaneBucketInterval ); @@ -219,7 +211,6 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim const loadExplorerDataConfig = explorerState !== undefined ? { - bounds: explorerState.bounds, lastRefresh, influencersFilterQuery: explorerState.influencersFilterQuery, noInfluencersConfigured: explorerState.noInfluencersConfigured, From 1007c8713afa2ed1b27c6c2a74d240fb76cd65b5 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Thu, 17 Dec 2020 09:15:07 -0500 Subject: [PATCH 33/38] Closes #84094 by adding configuration xpack.apm.maxServiceSelection. (#86234) --- x-pack/plugins/apm/server/index.ts | 2 ++ .../lib/settings/agent_configuration/get_service_names.ts | 5 +++-- x-pack/plugins/apm/server/utils/test_helpers.tsx | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 29a0d1fdf424..b8cbdab9e9e5 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -44,6 +44,7 @@ export const config = { telemetryCollectionEnabled: schema.boolean({ defaultValue: true }), metricsInterval: schema.number({ defaultValue: 30 }), maxServiceEnvironments: schema.number({ defaultValue: 100 }), + maxServiceSelection: schema.number({ defaultValue: 50 }), }), }; @@ -76,6 +77,7 @@ export function mergeConfigs( apmConfig.serviceMapMaxTracesPerRequest, 'xpack.apm.ui.enabled': apmConfig.ui.enabled, 'xpack.apm.maxServiceEnvironments': apmConfig.maxServiceEnvironments, + 'xpack.apm.maxServiceSelection': apmConfig.maxServiceSelection, 'xpack.apm.ui.maxTraceItems': apmConfig.ui.maxTraceItems, 'xpack.apm.ui.transactionGroupBucketSize': apmConfig.ui.transactionGroupBucketSize, diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts index 3ca583c30c29..137acf1f3290 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_service_names.ts @@ -21,7 +21,8 @@ export async function getServiceNames({ setup: Setup; searchAggregatedTransactions: boolean; }) { - const { apmEventClient } = setup; + const { apmEventClient, config } = setup; + const maxServiceSelection = config['xpack.apm.maxServiceSelection']; const params = { apm: { @@ -40,7 +41,7 @@ export async function getServiceNames({ services: { terms: { field: SERVICE_NAME, - size: 50, + size: maxServiceSelection, min_doc_count: 0, }, }, diff --git a/x-pack/plugins/apm/server/utils/test_helpers.tsx b/x-pack/plugins/apm/server/utils/test_helpers.tsx index 9093b16fada0..208dd8b91f13 100644 --- a/x-pack/plugins/apm/server/utils/test_helpers.tsx +++ b/x-pack/plugins/apm/server/utils/test_helpers.tsx @@ -79,6 +79,9 @@ export async function inspectSearchParams( case 'xpack.apm.maxServiceEnvironments': return 100; + + case 'xpack.apm.maxServiceSelection': + return 50; } }, } From 6f8697e198bd3f304a001c88ed2f9da6a0ec2639 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 17 Dec 2020 14:21:31 +0000 Subject: [PATCH 34/38] [ML] Removing space awareness for trained models (#86132) --- .../ml/server/lib/ml_client/ml_client.ts | 66 +------------------ 1 file changed, 2 insertions(+), 64 deletions(-) diff --git a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts index 8cfb066c9d09..2fe49064cb16 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts @@ -19,7 +19,6 @@ import { Calendar } from '../../../common/types/calendars'; import { searchProvider } from './search'; import { DataFrameAnalyticsConfig } from '../../../common/types/data_frame_analytics'; -import { InferenceConfigResponse, TrainedModelStat } from '../../../common/types/trained_models'; import { MLJobNotFound } from './errors'; import { MlClient, @@ -131,50 +130,6 @@ export function getMlClient( } } - async function getFilterTrainedModels( - p: Parameters, - allowWildcards: boolean = false - ) { - let configs = []; - try { - const resp = await mlClient.getTrainedModels(...p); - configs = resp.body.trained_model_configs; - } catch (error) { - if (error.statusCode === 404) { - throw new MLJobNotFound(error.body.error.reason); - } - throw error.body ?? error; - } - - const modelIds = getTrainedModelIdsFromRequest(p); - - const modelJobIds: string[] = configs - .map((m) => m.metadata?.analytics_config.id) - .filter((id) => id !== undefined); - const filteredModelJobIds = await jobSavedObjectService.filterJobIdsForSpace( - 'data-frame-analytics', - modelJobIds - ); - - const filteredConfigs = configs.filter((m) => { - const jobId = m.metadata?.analytics_config.id; - return jobId === undefined || filteredModelJobIds.includes(jobId); - }); - const filteredConfigsIds = filteredConfigs.map((c) => c.model_id); - - if (modelIds.length > filteredConfigs.length) { - let missingIds = modelIds.filter((j) => filteredConfigsIds.indexOf(j) === -1); - if (allowWildcards === true && missingIds.join().match('\\*') !== null) { - // filter out wildcard ids from the error - missingIds = missingIds.filter((id) => id.match('\\*') === null); - } - if (missingIds.length) { - throw new MLJobNotFound(`No known trained model with model_id [${missingIds.join(',')}]`); - } - } - return filteredConfigs; - } - return { async closeJob(...p: Parameters) { await jobIdsCheck('anomaly-detector', p); @@ -228,7 +183,6 @@ export function getMlClient( return mlClient.deleteModelSnapshot(...p); }, async deleteTrainedModel(...p: Parameters) { - await getFilterTrainedModels(p, true); return mlClient.deleteTrainedModel(...p); }, async estimateModelMemory(...p: Parameters) { @@ -428,20 +382,10 @@ export function getMlClient( return mlClient.getRecords(...p); }, async getTrainedModels(...p: Parameters) { - const models = await getFilterTrainedModels(p, true); - return { body: { trained_model_configs: models } }; + return mlClient.getTrainedModels(...p); }, async getTrainedModelsStats(...p: Parameters) { - await getFilterTrainedModels(p, true); - const models = await getFilterTrainedModels(p); - const filteredModelIds = models.map((m) => m.model_id); - const { body: allModelStats } = await mlClient.getTrainedModelsStats<{ - trained_model_stats: TrainedModelStat[]; - }>(...p); - const modelStats = allModelStats.trained_model_stats.filter((m) => - filteredModelIds.includes(m.model_id) - ); - return { body: { trained_model_stats: modelStats } }; + return mlClient.getTrainedModelsStats(...p); }, async info(...p: Parameters) { return mlClient.info(...p); @@ -571,9 +515,3 @@ function getJobIdFromBody(p: any): string | undefined { const [params] = p; return params?.body?.job_id; } - -function getTrainedModelIdsFromRequest(p: any): string[] { - const [params] = p; - const ids = params?.model_id?.split(','); - return ids || []; -} From d2a7c32025c012ca2c4c1d9d8ef7b203850ee373 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Thu, 17 Dec 2020 08:24:13 -0600 Subject: [PATCH 35/38] Fixes for service overview layout (#86205) * Fixes for service overview layout * Use 3/7 instead of 4/6 for `grow` between charts/tables * Decrease chart height * Use "s" gutterSize on tables * Decrease table height * Use `TruncateWithToolTip` on errors and transactions tables to remove tooltip inline-block style * Use `responsive={false}` on dependency titles so icon/name pairs don't wrap * Use `responsive={false}` on spark plots so plot/value pairs don't wrap * Use `responsive={false}` on latency chart and table titles so controls and links don't wrap * Make the fixed sizing overrides for the tables only be applied when we're using a wide, non-mobile (> 992) viewport * Switch to "mobile" viewport (with one item per row) at 992 instead of 768 Since you cannot control the breakpoints at which EUI switches to "responsive" mode, we trigger these manually to change the number of columns. and whether or not the tables use a fixed height. The overview now has three "modes": * Two columns for chart/table rows * Tables in non-responsive mode * One column for charts/tables * Tables in non-responsive mode * One column for charts/tables * Tables in non-responsive mode Fixes #85781. * remove unused imports --- .../components/app/service_overview/index.tsx | 38 +++++++++++---- .../index.tsx | 6 +-- .../service_overview_errors_table/index.tsx | 38 ++++++--------- .../index.tsx | 2 +- .../service_overview_table_container.tsx | 34 ++++++++++++-- .../index.tsx | 46 +++++++------------ .../use_should_use_mobile_layout.ts | 27 +++++++++++ .../shared/charts/latency_chart/index.tsx | 4 +- .../shared/charts/spark_plot/index.tsx | 2 +- 9 files changed, 123 insertions(+), 74 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/service_overview/use_should_use_mobile_layout.ts diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index 976fb127604a..2e04cce5ff67 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -21,12 +21,13 @@ import { ServiceOverviewErrorsTable } from './service_overview_errors_table'; import { ServiceOverviewInstancesTable } from './service_overview_instances_table'; import { ServiceOverviewThroughputChart } from './service_overview_throughput_chart'; import { ServiceOverviewTransactionsTable } from './service_overview_transactions_table'; +import { useShouldUseMobileLayout } from './use_should_use_mobile_layout'; /** * The height a chart should be if it's next to a table with 5 rows and a title. * Add the height of the pagination row. */ -export const chartHeight = 322; +export const chartHeight = 288; interface ServiceOverviewProps { agentName?: string; @@ -40,6 +41,11 @@ export function ServiceOverview({ useTrackPageview({ app: 'apm', path: 'service_overview' }); useTrackPageview({ app: 'apm', path: 'service_overview', delay: 15000 }); + // The default EuiFlexGroup breaks at 768, but we want to break at 992, so we + // observe the window width and set the flex directions of rows accordingly + const shouldUseMobileLayout = useShouldUseMobileLayout(); + const rowDirection = shouldUseMobileLayout ? 'column' : 'row'; + const { transactionType } = useApmServiceContext(); const transactionTypeLabel = i18n.translate( 'xpack.apm.serviceOverview.searchBar.transactionTypeLabel', @@ -58,11 +64,15 @@ export function ServiceOverview({

ENktvO=`{$?Q~!F>`pjR(`G1%Y!{S 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

*bh5(s8xE@r^oAy(fHT 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 | Copy, edit, delete, import, and export your saved objects. These include dashboards, visualizations, maps, index patterns, Canvas workpads, and more. +| <> +|Create, manage, and assign tags to your saved objects. + | <> | Create spaces to organize your dashboards and other saved objects into categories. A space is isolated from all other spaces, @@ -196,6 +199,8 @@ include::{kib-repo-dir}/management/rollups/create_and_manage_rollups.asciidoc[] include::{kib-repo-dir}/management/managing-saved-objects.asciidoc[] +include::{kib-repo-dir}/management/managing-tags.asciidoc[] + include::security/index.asciidoc[] include::{kib-repo-dir}/management/snapshot-restore/index.asciidoc[] From 2066b3d7ca87f1a4e7c495e5fba6aedded26a8b3 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 17 Dec 2020 09:08:17 +0000 Subject: [PATCH 25/38] [ML] Fix synching jobs from other spaces (#86086) * [ML] Fix synching jobs from other spaces * updating text in delete modal * updating translations Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../delete_job_modal/delete_job_modal.tsx | 5 +- .../delete_job_modal/delete_job_modal_.js | 167 ------------------ .../ml/server/saved_objects/service.ts | 23 +++ .../plugins/ml/server/saved_objects/sync.ts | 16 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 6 files changed, 38 insertions(+), 175 deletions(-) delete mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal_.js diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx index 90ae44eb85e5..0cb23c2b264b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx @@ -17,6 +17,7 @@ import { EuiButtonEmpty, EuiButton, EuiLoadingSpinner, + EuiText, } from '@elastic/eui'; import { deleteJobs } from '../utils'; @@ -103,7 +104,7 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, ) : ( - <> + - ); - modal = ( - - - } - confirmButtonText={ - - } - buttonColor="danger" - defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} - className="eui-textBreakWord" - > - {this.state.deleting === true && ( -

- - -
- -
-
- )} - - {this.state.deleting === false && ( - -

- -

-
- )} - - - ); - } - - return
{modal}
; - } -} diff --git a/x-pack/plugins/ml/server/saved_objects/service.ts b/x-pack/plugins/ml/server/saved_objects/service.ts index bfc5b165fe55..207f10dc33d4 100644 --- a/x-pack/plugins/ml/server/saved_objects/service.ts +++ b/x-pack/plugins/ml/server/saved_objects/service.ts @@ -114,6 +114,19 @@ export function jobSavedObjectServiceFactory( await savedObjectsClient.delete(ML_SAVED_OBJECT_TYPE, job.id, { force: true }); } + async function _forceDeleteJob(jobType: JobType, jobId: string, namespace: string) { + const id = savedObjectId({ + job_id: jobId, + datafeed_id: null, + type: jobType, + }); + + await internalSavedObjectsClient.delete(ML_SAVED_OBJECT_TYPE, id, { + namespace, + force: true, + }); + } + async function createAnomalyDetectionJob(jobId: string, datafeedId?: string) { await _createJob('anomaly-detector', jobId, datafeedId); } @@ -122,6 +135,10 @@ export function jobSavedObjectServiceFactory( await _deleteJob('anomaly-detector', jobId); } + async function forceDeleteAnomalyDetectionJob(jobId: string, namespace: string) { + await _forceDeleteJob('anomaly-detector', jobId, namespace); + } + async function createDataFrameAnalyticsJob(jobId: string) { await _createJob('data-frame-analytics', jobId); } @@ -130,6 +147,10 @@ export function jobSavedObjectServiceFactory( await _deleteJob('data-frame-analytics', jobId); } + async function forceDeleteDataFrameAnalyticsJob(jobId: string, namespace: string) { + await _forceDeleteJob('data-frame-analytics', jobId, namespace); + } + async function bulkCreateJobs(jobs: Array<{ job: JobObject; namespaces: string[] }>) { return await _bulkCreateJobs(jobs); } @@ -325,7 +346,9 @@ export function jobSavedObjectServiceFactory( createAnomalyDetectionJob, createDataFrameAnalyticsJob, deleteAnomalyDetectionJob, + forceDeleteAnomalyDetectionJob, deleteDataFrameAnalyticsJob, + forceDeleteDataFrameAnalyticsJob, addDatafeed, deleteDatafeed, filterJobsForSpace, diff --git a/x-pack/plugins/ml/server/saved_objects/sync.ts b/x-pack/plugins/ml/server/saved_objects/sync.ts index 16e052056705..00dfdba178fe 100644 --- a/x-pack/plugins/ml/server/saved_objects/sync.ts +++ b/x-pack/plugins/ml/server/saved_objects/sync.ts @@ -94,10 +94,14 @@ export function syncSavedObjectsFactory( results.savedObjectsDeleted[job.jobId] = { success: true }; } else { // Delete AD saved objects for jobs which no longer exist - const jobId = job.jobId; + const { jobId, namespaces } = job; tasks.push(async () => { try { - await jobSavedObjectService.deleteAnomalyDetectionJob(jobId); + if (namespaces !== undefined && namespaces.length) { + await jobSavedObjectService.forceDeleteAnomalyDetectionJob(jobId, namespaces[0]); + } else { + await jobSavedObjectService.deleteAnomalyDetectionJob(jobId); + } results.savedObjectsDeleted[job.jobId] = { success: true }; } catch (error) { results.savedObjectsDeleted[job.jobId] = { @@ -115,10 +119,14 @@ export function syncSavedObjectsFactory( results.savedObjectsDeleted[job.jobId] = { success: true }; } else { // Delete DFA saved objects for jobs which no longer exist - const jobId = job.jobId; + const { jobId, namespaces } = job; tasks.push(async () => { try { - await jobSavedObjectService.deleteDataFrameAnalyticsJob(jobId); + if (namespaces !== undefined && namespaces.length) { + await jobSavedObjectService.forceDeleteDataFrameAnalyticsJob(jobId, namespaces[0]); + } else { + await jobSavedObjectService.deleteDataFrameAnalyticsJob(jobId); + } results.savedObjectsDeleted[job.jobId] = { success: true }; } catch (error) { results.savedObjectsDeleted[job.jobId] = { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 377e38b71d45..cfb923420df8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -12498,7 +12498,6 @@ "xpack.ml.jobsList.deletedActionStatusText": "削除されました", "xpack.ml.jobsList.deleteJobErrorMessage": "ジョブの削除に失敗しました", "xpack.ml.jobsList.deleteJobModal.cancelButtonLabel": "キャンセル", - "xpack.ml.jobsList.deleteJobModal.closeButtonLabel": "閉じる", "xpack.ml.jobsList.deleteJobModal.deleteButtonLabel": "削除", "xpack.ml.jobsList.deleteJobModal.deleteJobsTitle": "{jobsCount, plural, one {{jobId}} other {# 件のジョブ}}を削除しますか?", "xpack.ml.jobsList.deleteJobModal.deleteMultipleJobsDescription": "{jobsCount, plural, one {ジョブ} other {複数ジョブ}}の削除には時間がかかる場合があります。{jobsCount, plural, one {} other {}}バックグラウンドで削除され、ジョブリストからすぐに消えない場合があります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7c9fa7f0fd1f..8588fcaf51d9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12512,7 +12512,6 @@ "xpack.ml.jobsList.deletedActionStatusText": "已删除", "xpack.ml.jobsList.deleteJobErrorMessage": "作业无法删除", "xpack.ml.jobsList.deleteJobModal.cancelButtonLabel": "取消", - "xpack.ml.jobsList.deleteJobModal.closeButtonLabel": "关闭", "xpack.ml.jobsList.deleteJobModal.deleteButtonLabel": "删除", "xpack.ml.jobsList.deleteJobModal.deleteJobsTitle": "删除 {jobsCount, plural, one {{jobId}} other {# 个作业}}?", "xpack.ml.jobsList.deleteJobModal.deleteMultipleJobsDescription": "删除{jobsCount, plural, one {一个作业} other {多个作业}}可能很费时。将在后台删除{jobsCount, plural, one {该作业} other {这些作业}},但删除的作业可能不会从作业列表中立即消失。", From 5be169a4fc9e59de5be129449c974783f6a24a75 Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Thu, 17 Dec 2020 12:17:02 +0200 Subject: [PATCH 26/38] [Search] Use filter to bulk find (#85551) * Use filter to bulk find * Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts Co-authored-by: Lukas Olson * Dashboard in space test * Add warning on update failure * fix merge * Added functional test for sessions in space * snapshot * test cleanup * Update src/plugins/data/common/es_query/kuery/node_types/node_builder.ts Co-authored-by: Lukas Olson * Revert "Update src/plugins/data/common/es_query/kuery/node_types/node_builder.ts" This reverts commit 4b7e781fe67d274b04a94f62c50a8c0570fb05e5. Co-authored-by: Lukas Olson Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../data/common/es_query/kuery/index.ts | 2 +- .../common/es_query/kuery/node_types/index.ts | 1 + .../es_query/kuery/node_types/node_builder.ts | 38 ++ .../server/alerts_client/alerts_client.ts | 7 +- .../alerts_authorization_kuery.ts | 25 +- .../server/search/session/session_service.ts | 36 +- .../__snapshots__/oss_features.test.ts.snap | 4 + .../plugins/features/server/oss_features.ts | 3 +- .../dashboard/session_in_space/data.json | 328 ++++++++++++++++++ .../dashboard/session_in_space/mappings.json | 244 +++++++++++++ .../dashboard/async_search/async_search.ts | 15 +- .../get_search_session_id_by_panel.ts | 22 ++ .../apps/dashboard/async_search/index.ts | 1 + .../async_search/sessions_in_space.ts | 90 +++++ 14 files changed, 771 insertions(+), 45 deletions(-) create mode 100644 src/plugins/data/common/es_query/kuery/node_types/node_builder.ts create mode 100644 x-pack/test/functional/es_archives/dashboard/session_in_space/data.json create mode 100644 x-pack/test/functional/es_archives/dashboard/session_in_space/mappings.json create mode 100644 x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/get_search_session_id_by_panel.ts create mode 100644 x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/sessions_in_space.ts diff --git a/src/plugins/data/common/es_query/kuery/index.ts b/src/plugins/data/common/es_query/kuery/index.ts index 4184dea62ef2..5b6cfab030ac 100644 --- a/src/plugins/data/common/es_query/kuery/index.ts +++ b/src/plugins/data/common/es_query/kuery/index.ts @@ -18,7 +18,7 @@ */ export { KQLSyntaxError } from './kuery_syntax_error'; -export { nodeTypes } from './node_types'; +export { nodeTypes, nodeBuilder } from './node_types'; export * from './ast'; export * from './types'; diff --git a/src/plugins/data/common/es_query/kuery/node_types/index.ts b/src/plugins/data/common/es_query/kuery/node_types/index.ts index 22e73e791df9..bec42f89c5b7 100644 --- a/src/plugins/data/common/es_query/kuery/node_types/index.ts +++ b/src/plugins/data/common/es_query/kuery/node_types/index.ts @@ -24,6 +24,7 @@ import * as wildcard from './wildcard'; import { NodeTypes } from './types'; export { NodeTypes }; +export { nodeBuilder } from './node_builder'; export const nodeTypes: NodeTypes = { // This requires better typing of the different typings and their return types. diff --git a/src/plugins/data/common/es_query/kuery/node_types/node_builder.ts b/src/plugins/data/common/es_query/kuery/node_types/node_builder.ts new file mode 100644 index 000000000000..4b77566dbc32 --- /dev/null +++ b/src/plugins/data/common/es_query/kuery/node_types/node_builder.ts @@ -0,0 +1,38 @@ +/* + * 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 { KueryNode, nodeTypes } from '../types'; + +export const nodeBuilder = { + is: (fieldName: string, value: string | KueryNode) => { + return nodeTypes.function.buildNodeWithArgumentNodes('is', [ + nodeTypes.literal.buildNode(fieldName), + typeof value === 'string' ? nodeTypes.literal.buildNode(value) : value, + nodeTypes.literal.buildNode(false), + ]); + }, + or: ([first, ...args]: KueryNode[]): KueryNode => { + return args.length ? nodeTypes.function.buildNode('or', [first, nodeBuilder.or(args)]) : first; + }, + and: ([first, ...args]: KueryNode[]): KueryNode => { + return args.length + ? nodeTypes.function.buildNode('and', [first, nodeBuilder.and(args)]) + : first; + }, +}; diff --git a/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts index 095823952722..f21cd2b02943 100644 --- a/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerts/server/alerts_client/alerts_client.ts @@ -45,7 +45,7 @@ import { TaskManagerStartContract } from '../../../task_manager/server'; import { taskInstanceToAlertTaskInstance } from '../task_runner/alert_task_instance'; import { deleteTaskIfItExists } from '../lib/delete_task_if_it_exists'; import { RegistryAlertType } from '../alert_type_registry'; -import { AlertsAuthorization, WriteOperations, ReadOperations, and } from '../authorization'; +import { AlertsAuthorization, WriteOperations, ReadOperations } from '../authorization'; import { IEventLogClient } from '../../../../plugins/event_log/server'; import { parseIsoOrRelativeDate } from '../lib/iso_or_relative_date'; import { alertInstanceSummaryFromEventLog } from '../lib/alert_instance_summary_from_event_log'; @@ -56,6 +56,7 @@ import { retryIfConflicts } from '../lib/retry_if_conflicts'; import { partiallyUpdateAlert } from '../saved_objects'; import { markApiKeyForInvalidation } from '../invalidate_pending_api_keys/mark_api_key_for_invalidation'; import { alertAuditEvent, AlertAuditAction } from './audit_events'; +import { nodeBuilder } from '../../../../../src/plugins/data/common'; export interface RegistryAlertTypeWithAuth extends RegistryAlertType { authorizedConsumers: string[]; @@ -455,7 +456,7 @@ export class AlertsClient { ...options, filter: (authorizationFilter && options.filter - ? and([esKuery.fromKueryExpression(options.filter), authorizationFilter]) + ? nodeBuilder.and([esKuery.fromKueryExpression(options.filter), authorizationFilter]) : authorizationFilter) ?? options.filter, fields: fields ? this.includeFieldsRequiredForAuthentication(fields) : fields, type: 'alert', @@ -517,7 +518,7 @@ export class AlertsClient { ...options, filter: (authorizationFilter && filter - ? and([esKuery.fromKueryExpression(filter), authorizationFilter]) + ? nodeBuilder.and([esKuery.fromKueryExpression(filter), authorizationFilter]) : authorizationFilter) ?? filter, page: 1, perPage: 0, diff --git a/x-pack/plugins/alerts/server/authorization/alerts_authorization_kuery.ts b/x-pack/plugins/alerts/server/authorization/alerts_authorization_kuery.ts index f236ee7f3c25..adab78b69e8a 100644 --- a/x-pack/plugins/alerts/server/authorization/alerts_authorization_kuery.ts +++ b/x-pack/plugins/alerts/server/authorization/alerts_authorization_kuery.ts @@ -5,36 +5,23 @@ */ import { remove } from 'lodash'; -import { nodeTypes } from '../../../../../src/plugins/data/common'; +import { nodeBuilder } from '../../../../../src/plugins/data/common'; import { KueryNode } from '../../../../../src/plugins/data/server'; import { RegistryAlertTypeWithAuth } from './alerts_authorization'; -export const is = (fieldName: string, value: string | KueryNode) => - nodeTypes.function.buildNodeWithArgumentNodes('is', [ - nodeTypes.literal.buildNode(fieldName), - typeof value === 'string' ? nodeTypes.literal.buildNode(value) : value, - nodeTypes.literal.buildNode(false), - ]); - -export const or = ([first, ...args]: KueryNode[]): KueryNode => - args.length ? nodeTypes.function.buildNode('or', [first, or(args)]) : first; - -export const and = ([first, ...args]: KueryNode[]): KueryNode => - args.length ? nodeTypes.function.buildNode('and', [first, and(args)]) : first; - export function asFiltersByAlertTypeAndConsumer( alertTypes: Set ): KueryNode { - return or( + return nodeBuilder.or( Array.from(alertTypes).reduce((filters, { id, authorizedConsumers }) => { ensureFieldIsSafeForQuery('alertTypeId', id); filters.push( - and([ - is(`alert.attributes.alertTypeId`, id), - or( + nodeBuilder.and([ + nodeBuilder.is(`alert.attributes.alertTypeId`, id), + nodeBuilder.or( Object.keys(authorizedConsumers).map((consumer) => { ensureFieldIsSafeForQuery('consumer', consumer); - return is(`alert.attributes.consumer`, consumer); + return nodeBuilder.is(`alert.attributes.consumer`, consumer); }) ), ]) diff --git a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts index 96d66157c48e..d426e73b4851 100644 --- a/x-pack/plugins/data_enhanced/server/search/session/session_service.ts +++ b/x-pack/plugins/data_enhanced/server/search/session/session_service.ts @@ -14,11 +14,14 @@ import { SavedObjectsClientContract, Logger, SavedObject, + SavedObjectsBulkUpdateObject, } from '../../../../../../src/core/server'; import { IKibanaSearchRequest, IKibanaSearchResponse, ISearchOptions, + KueryNode, + nodeBuilder, tapFirst, } from '../../../../../../src/plugins/data/common'; import { @@ -81,6 +84,18 @@ export class BackgroundSessionService implements ISessionService { } }; + /** + * Compiles a KQL Query to fetch sessions by ID. + * Done as a performance optimization workaround. + */ + private sessionIdsAsFilters(sessionIds: string[]): KueryNode { + return nodeBuilder.or( + sessionIds.map((id) => { + return nodeBuilder.is(`${BACKGROUND_SESSION_TYPE}.attributes.sessionId`, id); + }) + ); + } + /** * Gets all {@link SessionSavedObjectAttributes | Background Searches} that * currently being tracked by the service. @@ -90,17 +105,14 @@ export class BackgroundSessionService implements ISessionService { * context of a user's session. */ private async getAllMappedSavedObjects() { - const activeMappingIds = Array.from(this.sessionSearchMap.keys()) - .map((sessionId) => `"${sessionId}"`) - .join(' | '); + const filter = this.sessionIdsAsFilters(Array.from(this.sessionSearchMap.keys())); const res = await this.internalSavedObjectsClient.find({ perPage: INMEM_MAX_SESSIONS, // If there are more sessions in memory, they will be synced when some items are cleared out. type: BACKGROUND_SESSION_TYPE, - search: activeMappingIds, - searchFields: ['sessionId'], + filter, namespaces: ['*'], }); - this.logger.debug(`getAllMappedSavedObjects | Got ${res.saved_objects.length} items`); + this.logger.warn(`getAllMappedSavedObjects | Got ${res.saved_objects.length} items`); return res.saved_objects; } @@ -135,6 +147,9 @@ export class BackgroundSessionService implements ISessionService { updatedSessions.forEach((updatedSavedObject) => { const sessionInfo = this.sessionSearchMap.get(updatedSavedObject.id)!; if (updatedSavedObject.error) { + this.logger.warn( + `monitorMappedIds | update error ${JSON.stringify(updatedSavedObject.error) || ''}` + ); // Retry next time sessionInfo.retryCount++; } else if (updatedSavedObject.attributes.idMapping) { @@ -164,7 +179,9 @@ export class BackgroundSessionService implements ISessionService { if (!activeMappingObjects.length) return []; this.logger.debug(`updateAllSavedObjects | Updating ${activeMappingObjects.length} items`); - const updatedSessions = activeMappingObjects + const updatedSessions: Array< + SavedObjectsBulkUpdateObject + > = activeMappingObjects .filter((so) => !so.error) .map((sessionSavedObject) => { const sessionInfo = this.sessionSearchMap.get(sessionSavedObject.id); @@ -173,7 +190,10 @@ export class BackgroundSessionService implements ISessionService { ...sessionSavedObject.attributes.idMapping, ...idMapping, }; - return sessionSavedObject; + return { + ...sessionSavedObject, + namespace: sessionSavedObject.namespaces?.[0], + }; }); const updateResults = await this.internalSavedObjectsClient.bulkUpdate( diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index e18acbfea8f4..680429a4f594 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -83,6 +83,7 @@ Array [ "lens", "map", "tag", + "background-session", ], }, "ui": Array [ @@ -204,6 +205,7 @@ Array [ "search", "query", "index-pattern", + "background-session", "url", ], "read": Array [], @@ -565,6 +567,7 @@ Array [ "lens", "map", "tag", + "background-session", ], }, "ui": Array [ @@ -686,6 +689,7 @@ Array [ "search", "query", "index-pattern", + "background-session", "url", ], "read": Array [], diff --git a/x-pack/plugins/features/server/oss_features.ts b/x-pack/plugins/features/server/oss_features.ts index 46dd5fd086b4..209e26821aed 100644 --- a/x-pack/plugins/features/server/oss_features.ts +++ b/x-pack/plugins/features/server/oss_features.ts @@ -28,7 +28,7 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS app: ['discover', 'kibana'], catalogue: ['discover'], savedObject: { - all: ['search', 'query', 'index-pattern'], + all: ['search', 'query', 'index-pattern', 'background-session'], read: [], }, ui: ['show', 'save', 'saveQuery'], @@ -156,6 +156,7 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS 'lens', 'map', 'tag', + 'background-session', ], }, ui: ['createNew', 'show', 'showWriteControls', 'saveQuery'], diff --git a/x-pack/test/functional/es_archives/dashboard/session_in_space/data.json b/x-pack/test/functional/es_archives/dashboard/session_in_space/data.json new file mode 100644 index 000000000000..64756843245a --- /dev/null +++ b/x-pack/test/functional/es_archives/dashboard/session_in_space/data.json @@ -0,0 +1,328 @@ +{ + "type": "doc", + "value": { + "id": "space:default", + "index": ".kibana", + "source": { + "space": { + "description": "This is the default space!", + "name": "Default" + }, + "type": "space" + } + } +} + +{ + "type": "doc", + "value": { + "id": "space:another-space", + "index": ".kibana", + "source": { + "space": { + "description": "This is another space", + "name": "Another Space" + }, + "type": "space" + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:6c9f3830-01e3-11eb-9b63-176d7b28a352", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Sum of Bytes by Extension (Delayed 5s)", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"Sum of Bytes by Extension (Delayed 5s)\",\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"params\":{\"field\":\"bytes\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"extension.raw\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"shard_delay\",\"params\":{\"delay\":\"5s\"},\"schema\":\"group\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Sum of bytes\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Sum of bytes\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"row\":true}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:14501a50-01e3-11eb-9b63-176d7b28a352", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Sum of Bytes by Extension", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"Sum of Bytes by Extension\",\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"params\":{\"field\":\"bytes\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"extension.raw\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Sum of bytes\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Sum of bytes\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"row\":true}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:50a67010-075d-11eb-be70-0bd5e8b57d02", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Sum of Bytes by Extension (Delayed 15s)", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"Sum of Bytes by Extension (Delayed 15s)\",\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"params\":{\"field\":\"bytes\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"extension.raw\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"shard_delay\",\"params\":{\"delay\":\"15s\"},\"schema\":\"group\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":true,\"truncate\":100},\"title\":{}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Sum of bytes\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Sum of bytes\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"row\":true}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "index-pattern:logstash-*", + "index": ".kibana", + "source": { + "index-pattern": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "type": "index-pattern" + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:24f3f950-69d9-11ea-a14d-e341629a29e6", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.10.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"f8f7f5b5-b840-443c-a766-d22a8a87c493\"},\"panelIndex\":\"f8f7f5b5-b840-443c-a766-d22a8a87c493\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title" : "Delayed 5s", + "version": 1 + }, + "references": [ + { + "name" : "panel_0", + "type" : "visualization", + "id" : "6c9f3830-01e3-11eb-9b63-176d7b28a352" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:41e77910-69d9-11ea-a14d-e341629a29e6", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\"},\"panelIndex\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Not Delayed", + "version": 1 + }, + "references": [ + { + "name" : "panel_0", + "type" : "visualization", + "id" : "14501a50-01e3-11eb-9b63-176d7b28a352" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:a41c6790-075d-11eb-be70-0bd5e8b57d02", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"eedeb943-5cfc-4e2c-bc1a-10ce06345cc1\"},\"panelIndex\":\"eedeb943-5cfc-4e2c-bc1a-10ce06345cc1\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Delayed 15s", + "version": 1 + }, + "references": [ + { + "name" : "panel_0", + "type" : "visualization", + "id" : "50a67010-075d-11eb-be70-0bd5e8b57d02" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:a41c6790-075d-11eb-be70-0bd5e8b57d03", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"ec585931-ce8e-43fd-aa94-a1a9612d24ba\"},\"panelIndex\":\"ec585931-ce8e-43fd-aa94-a1a9612d24ba\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":0,\"w\":24,\"h\":15,\"i\":\"c7b18010-462b-4e55-a974-fdec2ae64b06\"},\"panelIndex\":\"c7b18010-462b-4e55-a974-fdec2ae64b06\",\"embeddableConfig\":{},\"panelRefName\":\"panel_1\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":0,\"y\":15,\"w\":24,\"h\":15,\"i\":\"e67704f7-20b7-4ade-8dee-972a9d187107\"},\"panelIndex\":\"e67704f7-20b7-4ade-8dee-972a9d187107\",\"embeddableConfig\":{},\"panelRefName\":\"panel_2\"},{\"version\":\"8.0.0\",\"gridData\":{\"x\":24,\"y\":15,\"w\":24,\"h\":15,\"i\":\"f0b03592-10f1-41cd-9929-0cb4163bcd16\"},\"panelIndex\":\"f0b03592-10f1-41cd-9929-0cb4163bcd16\",\"embeddableConfig\":{},\"panelRefName\":\"panel_3\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Multiple delayed", + "version": 1 + }, + "references": [ + { + "id": "14501a50-01e3-11eb-9b63-176d7b28a352", + "name": "panel_0", + "type": "visualization" + }, + { + "id": "50a67010-075d-11eb-be70-0bd5e8b57d02", + "name": "panel_1", + "type": "visualization" + }, + { + "id": "6c9f3830-01e3-11eb-9b63-176d7b28a352", + "name": "panel_2", + "type": "visualization" + }, + { + "id": "50a67010-075d-11eb-be70-0bd5e8b57d02", + "name": "panel_3", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "another-space:index-pattern:logstash-*", + "source": { + "index-pattern": { + "title": "logstash-*", + "timeFieldName": "@timestamp", + "fields": "[{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]" + }, + "type": "index-pattern", + "namespace": "another-space", + "updated_at": "2018-12-21T00:43:07.096Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "another-space:visualization:75c3e060-1e7c-11e9-8488-65449e65d0ed", + "source": { + "visualization": { + "title": "A Pie in another space", + "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}", + "uiStateJSON": "{}", + "description": "", + "version": 1, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "namespace": "another-space", + "type": "visualization", + "updated_at": "2019-01-22T19:32:31.206Z" + } + } +} + +{ + "type": "doc", + "value": { + "index": ".kibana", + "type": "doc", + "id": "another-space:dashboard:my-dashboard", + "source": { + "dashboard": { + "title": "A Dashboard in another space", + "hits": 0, + "description": "", + "panelsJSON": "[{\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"1\"},\"version\":\"7.0.0\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"id\":\"75c3e060-1e7c-11e9-8488-65449e65d0ed\",\"embeddableConfig\":{}}]", + "optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}", + "version": 1, + "timeRestore": false, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}" + } + }, + "namespace": "another-space", + "type": "dashboard", + "updated_at": "2019-01-22T19:32:47.232Z" + } + } +} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/dashboard/session_in_space/mappings.json b/x-pack/test/functional/es_archives/dashboard/session_in_space/mappings.json new file mode 100644 index 000000000000..210fade40c64 --- /dev/null +++ b/x-pack/test/functional/es_archives/dashboard/session_in_space/mappings.json @@ -0,0 +1,244 @@ +{ + "type": "index", + "value": { + "index": ".kibana", + "mappings": { + "properties": { + "config": { + "dynamic": "true", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "dashboard": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "optionsJSON": { + "type": "text" + }, + "panelsJSON": { + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "type": "keyword" + }, + "pause": { + "type": "boolean" + }, + "section": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "timeFrom": { + "type": "keyword" + }, + "timeRestore": { + "type": "boolean" + }, + "timeTo": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "index-pattern": { + "dynamic": "strict", + "properties": { + "fieldFormatMap": { + "type": "text" + }, + "fields": { + "type": "text" + }, + "intervalName": { + "type": "keyword" + }, + "notExpandable": { + "type": "boolean" + }, + "sourceFilters": { + "type": "text" + }, + "timeFieldName": { + "type": "keyword" + }, + "title": { + "type": "text" + } + } + }, + "search": { + "dynamic": "strict", + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "server": { + "dynamic": "strict", + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "timelion-sheet": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "type": { + "type": "keyword" + }, + "url": { + "dynamic": "strict", + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "visualization": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "savedSearchId": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "type": "text" + } + } + } + } + }, + "settings": { + "index": { + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/async_search.ts b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/async_search.ts index 1e92019899b5..4859b2474f86 100644 --- a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/async_search.ts +++ b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/async_search.ts @@ -6,14 +6,14 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { getSearchSessionIdByPanelProvider } from './get_search_session_id_by_panel'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const es = getService('es'); const testSubjects = getService('testSubjects'); const log = getService('log'); const PageObjects = getPageObjects(['common', 'header', 'dashboard', 'visChart']); - const dashboardPanelActions = getService('dashboardPanelActions'); - const inspector = getService('inspector'); + const getSearchSessionIdByPanel = getSearchSessionIdByPanelProvider(getService); const queryBar = getService('queryBar'); const browser = getService('browser'); const sendToBackground = getService('sendToBackground'); @@ -133,15 +133,4 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); - - // HELPERS - async function getSearchSessionIdByPanel(panelTitle: string) { - await dashboardPanelActions.openInspectorByTitle(panelTitle); - await inspector.openInspectorRequestsView(); - const searchSessionId = await ( - await testSubjects.find('inspectorRequestSearchSessionId') - ).getAttribute('data-search-session-id'); - await inspector.close(); - return searchSessionId; - } } diff --git a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/get_search_session_id_by_panel.ts b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/get_search_session_id_by_panel.ts new file mode 100644 index 000000000000..6de85ca5459d --- /dev/null +++ b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/get_search_session_id_by_panel.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// HELPERS +export function getSearchSessionIdByPanelProvider(getService: any) { + const dashboardPanelActions = getService('dashboardPanelActions'); + const inspector = getService('inspector'); + const testSubjects = getService('testSubjects'); + + return async function getSearchSessionIdByPanel(panelTitle: string) { + await dashboardPanelActions.openInspectorByTitle(panelTitle); + await inspector.openInspectorRequestsView(); + const searchSessionId = await ( + await testSubjects.find('inspectorRequestSearchSessionId') + ).getAttribute('data-search-session-id'); + await inspector.close(); + return searchSessionId; + }; +} diff --git a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/index.ts b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/index.ts index 6719500d2eb3..83085983fef0 100644 --- a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/index.ts +++ b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/index.ts @@ -24,5 +24,6 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { }); loadTestFile(require.resolve('./async_search')); + loadTestFile(require.resolve('./sessions_in_space')); }); } diff --git a/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/sessions_in_space.ts b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/sessions_in_space.ts new file mode 100644 index 000000000000..e2e0adf447af --- /dev/null +++ b/x-pack/test/send_search_to_background_integration/tests/apps/dashboard/async_search/sessions_in_space.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 { FtrProviderContext } from '../../../../ftr_provider_context'; +import { getSearchSessionIdByPanelProvider } from './get_search_session_id_by_panel'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const esArchiver = getService('esArchiver'); + const security = getService('security'); + const PageObjects = getPageObjects([ + 'common', + 'header', + 'dashboard', + 'visChart', + 'security', + 'timePicker', + ]); + const getSearchSessionIdByPanel = getSearchSessionIdByPanelProvider(getService); + const browser = getService('browser'); + const sendToBackground = getService('sendToBackground'); + + describe('dashboard in space', () => { + describe('Send to background in space', () => { + before(async () => { + await esArchiver.load('dashboard/session_in_space'); + + await security.role.create('data_analyst', { + elasticsearch: { + indices: [{ names: ['logstash-*'], privileges: ['all'] }], + }, + kibana: [ + { + base: ['all'], + spaces: ['another-space'], + }, + ], + }); + + await security.user.create('analyst', { + password: 'analyst-password', + roles: ['data_analyst'], + full_name: 'test user', + }); + + await PageObjects.security.forceLogout(); + + await PageObjects.security.login('analyst', 'analyst-password', { + expectSpaceSelector: false, + }); + }); + + after(async () => { + await esArchiver.unload('dashboard/session_in_space'); + await PageObjects.security.forceLogout(); + }); + + it('Saves and restores a session', async () => { + await PageObjects.common.navigateToApp('dashboard', { basePath: 's/another-space' }); + await PageObjects.dashboard.loadSavedDashboard('A Dashboard in another space'); + + await PageObjects.timePicker.setAbsoluteRange( + 'Sep 1, 2015 @ 00:00:00.000', + 'Oct 1, 2015 @ 00:00:00.000' + ); + + await PageObjects.dashboard.waitForRenderComplete(); + + await sendToBackground.expectState('completed'); + await sendToBackground.save(); + await sendToBackground.expectState('backgroundCompleted'); + const savedSessionId = await getSearchSessionIdByPanel('A Pie in another space'); + + // load URL to restore a saved session + const url = await browser.getCurrentUrl(); + const savedSessionURL = `${url}&searchSessionId=${savedSessionId}`; + await browser.get(savedSessionURL); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + + // Check that session is restored + await sendToBackground.expectState('restored'); + await testSubjects.missingOrFail('embeddableErrorLabel'); + }); + }); + }); +} From df32ff80ca1f5eee3f0742833b329f7b6d0ba487 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Thu, 17 Dec 2020 11:42:37 +0100 Subject: [PATCH 27/38] [Dashboard] Change filename fallback for no title panels to "untitled" (#86110) --- src/plugins/dashboard/public/dashboard_strings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/dashboard/public/dashboard_strings.ts b/src/plugins/dashboard/public/dashboard_strings.ts index 4aa552893ab9..9bede02c75b9 100644 --- a/src/plugins/dashboard/public/dashboard_strings.ts +++ b/src/plugins/dashboard/public/dashboard_strings.ts @@ -134,7 +134,7 @@ export const dashboardExportCsvAction = { }), getUntitledFilename: () => i18n.translate('dashboard.actions.downloadOptionsUnsavedFilename', { - defaultMessage: 'unsaved', + defaultMessage: 'untitled', }), }; From b93034b72c2f183ce038bee81544d41bbd3e0364 Mon Sep 17 00:00:00 2001 From: Peter Pisljar Date: Thu, 17 Dec 2020 12:14:07 +0100 Subject: [PATCH 28/38] inspector table adapter cleanup (#84232) --- ...plugin-plugins-data-public.plugin.setup.md | 4 +- ...plugins-embeddable-public.adapters.data.md | 11 -- ...ugin-plugins-embeddable-public.adapters.md | 1 - ...ibana-plugin-plugins-expressions-public.md | 1 + ...sions-public.tablesadapter.logdatatable.md | 23 +++ ...lugins-expressions-public.tablesadapter.md | 24 +++ ...expressions-public.tablesadapter.tables.md | 13 ++ .../application/actions/export_csv_action.tsx | 4 +- .../common/search/aggs/aggs_service.test.ts | 3 +- .../data/common/search/aggs/aggs_service.ts | 23 ++- src/plugins/data/common/search/aggs/types.ts | 9 +- .../aggs/utils/datatable_column_meta.ts | 68 +++++++ .../esaggs/build_tabular_inspector_data.ts | 120 ----------- .../search/expressions/esaggs/esaggs_fn.ts | 2 - .../esaggs/request_handler.test.ts | 1 - .../expressions/esaggs/request_handler.ts | 16 -- src/plugins/data/kibana.json | 3 +- src/plugins/data/public/index.scss | 1 + src/plugins/data/public/plugin.ts | 12 +- src/plugins/data/public/public.api.md | 8 +- .../public/search/aggs/aggs_service.test.ts | 3 +- .../data/public/search/aggs/aggs_service.ts | 4 +- src/plugins/data/public/search/aggs/mocks.ts | 5 + .../public/search/expressions/esaggs.test.ts | 2 - .../data/public/search/expressions/esaggs.ts | 5 +- src/plugins/data/public/types.ts | 2 + .../table_inspector_view}/_data_table.scss | 0 .../utils/table_inspector_view}/_index.scss | 0 .../__snapshots__/data_view.test.tsx.snap | 163 +++------------ .../components/data_table.tsx | 109 +++++++--- .../components/data_view.test.tsx | 23 ++- .../components/data_view.tsx | 137 +++++++++++++ .../components/data_view_wrapper.tsx | 47 +++++ .../components/download_options.tsx | 47 ++--- .../components}/export_csv.ts | 30 ++- .../utils/table_inspector_view}/index.ts | 29 +-- .../utils/table_inspector_view}/types.ts | 13 +- .../data/server/search/aggs/aggs_service.ts | 4 +- src/plugins/data/server/search/aggs/mocks.ts | 5 + .../contact_card_exportable_embeddable.tsx | 27 +-- src/plugins/embeddable/public/public.api.md | 4 - .../common/execution/execution.test.ts | 4 +- .../expressions/common/execution/execution.ts | 15 +- .../execution/execution_contract.test.ts | 2 +- .../expressions/common/execution/types.ts | 5 +- src/plugins/expressions/common/util/index.ts | 1 + .../common/util/tables_adapter.ts} | 16 +- src/plugins/expressions/public/index.ts | 1 + src/plugins/expressions/public/loader.test.ts | 2 +- src/plugins/expressions/public/public.api.md | 12 ++ .../common/adapters/data/data_adapter.ts | 40 ---- .../adapters/data/data_adapters.test.ts | 71 ------- .../inspector/common/adapters/data/index.ts | 22 --- .../inspector/common/adapters/data/types.ts | 48 ----- .../inspector/common/adapters/index.ts | 1 - .../inspector/common/adapters/types.ts | 2 - src/plugins/inspector/common/index.ts | 6 - src/plugins/inspector/public/plugin.tsx | 3 +- .../public/test/is_available.test.ts | 10 +- .../inspector/public/views/_index.scss | 1 - .../views/data/components/data_view.tsx | 187 ------------------ src/plugins/inspector/public/views/index.ts | 1 - .../region_map/public/region_map_fn.js | 5 +- .../region_map/public/region_map_fn.test.js | 6 +- src/plugins/tile_map/public/tile_map_fn.js | 5 +- .../tile_map/public/tilemap_fn.test.js | 8 +- .../vis_type_metric/public/metric_vis_fn.ts | 5 +- .../vis_type_table/public/table_vis_fn.ts | 5 +- .../vis_type_tagcloud/public/tag_cloud_fn.ts | 5 +- src/plugins/vis_type_vislib/public/pie_fn.ts | 6 +- .../public/vis_type_vislib_vis_fn.ts | 6 +- .../public/app/components/main.tsx | 10 +- .../workspace_panel/workspace_panel.test.tsx | 2 +- .../workspace_panel/workspace_panel.tsx | 6 +- .../embeddable/embeddable.tsx | 7 +- .../embeddable/expression_wrapper.tsx | 8 +- .../editor_frame_service/merge_tables.test.ts | 19 +- .../editor_frame_service/merge_tables.ts | 15 +- .../lens/public/editor_frame_service/types.ts | 3 - .../translations/translations/ja-JP.json | 16 -- .../translations/translations/zh-CN.json | 16 -- 81 files changed, 719 insertions(+), 890 deletions(-) delete mode 100644 docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md create mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md create mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md create mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md create mode 100644 src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts delete mode 100644 src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/_data_table.scss (100%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/_index.scss (100%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/components/__snapshots__/data_view.test.tsx.snap (68%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/components/data_table.tsx (57%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/components/data_view.test.tsx (77%) create mode 100644 src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx create mode 100644 src/plugins/data/public/utils/table_inspector_view/components/data_view_wrapper.tsx rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/components/download_options.tsx (77%) rename src/plugins/{inspector/public/views/data/lib => data/public/utils/table_inspector_view/components}/export_csv.ts (76%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/index.ts (51%) rename src/plugins/{inspector/public/views/data => data/public/utils/table_inspector_view}/types.ts (70%) rename src/plugins/{inspector/common/adapters/data/formatted_data.ts => expressions/common/util/tables_adapter.ts} (66%) delete mode 100644 src/plugins/inspector/common/adapters/data/data_adapter.ts delete mode 100644 src/plugins/inspector/common/adapters/data/data_adapters.test.ts delete mode 100644 src/plugins/inspector/common/adapters/data/index.ts delete mode 100644 src/plugins/inspector/common/adapters/data/types.ts delete mode 100644 src/plugins/inspector/public/views/data/components/data_view.tsx diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 1ed6059c2306..20181a5208b5 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters @@ -15,7 +15,7 @@ setup(core: CoreSetup, { bfetch, e | Parameter | Type | Description | | --- | --- | --- | | core | CoreSetup<DataStartDependencies, DataPublicPluginStart> | | -| { bfetch, expressions, uiActions, usageCollection } | DataSetupDependencies | | +| { bfetch, expressions, uiActions, usageCollection, inspector } | DataSetupDependencies | | Returns: diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md deleted file mode 100644 index 0ddbcb3546d1..000000000000 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.data.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [Adapters](./kibana-plugin-plugins-embeddable-public.adapters.md) > [data](./kibana-plugin-plugins-embeddable-public.adapters.data.md) - -## Adapters.data property - -Signature: - -```typescript -data?: DataAdapter; -``` diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md index 47484dc79d88..8ba759e333fa 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.adapters.md @@ -16,6 +16,5 @@ export interface Adapters | Property | Type | Description | | --- | --- | --- | -| [data](./kibana-plugin-plugins-embeddable-public.adapters.data.md) | DataAdapter | | | [requests](./kibana-plugin-plugins-embeddable-public.adapters.requests.md) | RequestAdapter | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md index a03ea3248201..1b97c9e11f83 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md @@ -20,6 +20,7 @@ | [ExpressionsService](./kibana-plugin-plugins-expressions-public.expressionsservice.md) | ExpressionsService class is used for multiple purposes:1. It implements the same Expressions service that can be used on both: (1) server-side and (2) browser-side. 2. It implements the same Expressions service that users can fork/clone, thus have their own instance of the Expressions plugin. 3. ExpressionsService defines the public contracts of \*setup\* and \*start\* Kibana Platform life-cycles for ease-of-use on server-side and browser-side. 4. ExpressionsService creates a bound version of all exported contract functions. 5. Functions are bound the way there are:\`\`\`ts registerFunction = (...args: Parameters<Executor\['registerFunction'\]> ): ReturnType<Executor\['registerFunction'\]> => this.executor.registerFunction(...args); \`\`\`so that JSDoc appears in developers IDE when they use those plugins.expressions.registerFunction(. | | [ExpressionType](./kibana-plugin-plugins-expressions-public.expressiontype.md) | | | [FunctionsRegistry](./kibana-plugin-plugins-expressions-public.functionsregistry.md) | | +| [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) | | | [TypesRegistry](./kibana-plugin-plugins-expressions-public.typesregistry.md) | | ## Enumerations diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md new file mode 100644 index 000000000000..281f48918416 --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) > [logDatatable](./kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md) + +## TablesAdapter.logDatatable() method + +Signature: + +```typescript +logDatatable(name: string, datatable: Datatable): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | | +| datatable | Datatable | | + +Returns: + +`void` + diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md new file mode 100644 index 000000000000..c489eff4cc25 --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) + +## TablesAdapter class + +Signature: + +```typescript +export declare class TablesAdapter extends EventEmitter +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [tables](./kibana-plugin-plugins-expressions-public.tablesadapter.tables.md) | | {
[key: string]: Datatable;
} | | + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [logDatatable(name, datatable)](./kibana-plugin-plugins-expressions-public.tablesadapter.logdatatable.md) | | | + diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md new file mode 100644 index 000000000000..ef5ada66e50b --- /dev/null +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.tablesadapter.tables.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [TablesAdapter](./kibana-plugin-plugins-expressions-public.tablesadapter.md) > [tables](./kibana-plugin-plugins-expressions-public.tablesadapter.tables.md) + +## TablesAdapter.tables property + +Signature: + +```typescript +get tables(): { + [key: string]: Datatable; + }; +``` diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx index 4f78a738095d..a31ecbea88ba 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx @@ -65,7 +65,7 @@ export class ExportCSVAction implements ActionByType { } private hasDatatableContent = (adapters: Adapters | undefined) => { - return Object.keys(adapters?.tables || {}).length > 0; + return Object.keys(adapters?.tables || {}).length > 0 && adapters!.tables.allowCsvExport; }; private getFormatter = (): FormatFactory | undefined => { @@ -76,7 +76,7 @@ export class ExportCSVAction implements ActionByType { private getDataTableContent = (adapters: Adapters | undefined) => { if (this.hasDatatableContent(adapters)) { - return adapters?.tables; + return adapters?.tables.tables; } return; }; diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts index 160860bcce59..eeaebecfe7f7 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts @@ -203,11 +203,12 @@ describe('Aggs service', () => { describe('start()', () => { test('exposes proper contract', () => { const start = service.start(startDeps); - expect(Object.keys(start).length).toBe(4); + expect(Object.keys(start).length).toBe(5); expect(start).toHaveProperty('calculateAutoTimeExpression'); expect(start).toHaveProperty('getDateMetaByDatatableColumn'); expect(start).toHaveProperty('createAggConfigs'); expect(start).toHaveProperty('types'); + expect(start).toHaveProperty('datatableUtilities'); }); test('types registry returns uninitialized type providers', () => { diff --git a/src/plugins/data/common/search/aggs/aggs_service.ts b/src/plugins/data/common/search/aggs/aggs_service.ts index b6afa708f9e6..4b1756fabf1a 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.ts @@ -18,7 +18,7 @@ */ import { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; -import { IndexPattern, UI_SETTINGS } from '../../../common'; +import { CreateAggConfigParams, IndexPattern, UI_SETTINGS } from '../../../common'; import { GetConfigFn } from '../../types'; import { AggConfigs, @@ -29,6 +29,7 @@ import { } from './'; import { AggsCommonSetup, AggsCommonStart } from './types'; import { getDateMetaByDatatableColumn } from './utils/time_column_meta'; +import { getDatatableColumnUtilities } from './utils/datatable_column_meta'; /** @internal */ export const aggsRequiredUiSettings = [ @@ -88,6 +89,15 @@ export class AggsCommonService { const aggTypesStart = this.aggTypesRegistry.start(); const calculateAutoTimeExpression = getCalculateAutoTimeExpression(getConfig); + const createAggConfigs = ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[] + ) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: aggTypesStart, + }); + }; + return { calculateAutoTimeExpression, getDateMetaByDatatableColumn: getDateMetaByDatatableColumn({ @@ -96,11 +106,12 @@ export class AggsCommonService { getConfig, isDefaultTimezone, }), - createAggConfigs: (indexPattern, configStates = [], schemas) => { - return new AggConfigs(indexPattern, configStates, { - typesRegistry: aggTypesStart, - }); - }, + datatableUtilities: getDatatableColumnUtilities({ + getIndexPattern, + createAggConfigs, + aggTypesStart, + }), + createAggConfigs, types: aggTypesStart, }; } diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts index f3ae7d66dca9..1055777396f5 100644 --- a/src/plugins/data/common/search/aggs/types.ts +++ b/src/plugins/data/common/search/aggs/types.ts @@ -94,6 +94,7 @@ import { CreateAggConfigParams, getCalculateAutoTimeExpression, METRIC_TYPES, + AggConfig, } from './'; export { IAggConfig, AggConfigSerialized } from './agg_config'; @@ -127,10 +128,14 @@ export interface AggsCommonStart { getDateMetaByDatatableColumn: ( column: DatatableColumn ) => Promise; + datatableUtilities: { + getIndexPattern: (column: DatatableColumn) => Promise; + getAggConfig: (column: DatatableColumn) => Promise; + isFilterable: (column: DatatableColumn) => boolean; + }; createAggConfigs: ( indexPattern: IndexPattern, - configStates?: CreateAggConfigParams[], - schemas?: Record + configStates?: CreateAggConfigParams[] ) => InstanceType; types: ReturnType; } diff --git a/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts b/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts new file mode 100644 index 000000000000..38865f05727a --- /dev/null +++ b/src/plugins/data/common/search/aggs/utils/datatable_column_meta.ts @@ -0,0 +1,68 @@ +/* + * 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 { DatatableColumn } from 'src/plugins/expressions/common'; +import { IndexPattern } from '../../../index_patterns'; +import { AggConfigs, CreateAggConfigParams } from '../agg_configs'; +import { AggTypesRegistryStart } from '../agg_types_registry'; +import { IAggType } from '../agg_type'; + +export interface MetaByColumnDeps { + getIndexPattern: (id: string) => Promise; + createAggConfigs: ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[] + ) => InstanceType; + aggTypesStart: AggTypesRegistryStart; +} + +export const getDatatableColumnUtilities = (deps: MetaByColumnDeps) => { + const { getIndexPattern, createAggConfigs, aggTypesStart } = deps; + + const getIndexPatternFromDatatableColumn = async (column: DatatableColumn) => { + if (!column.meta.index) return; + + return await getIndexPattern(column.meta.index); + }; + + const getAggConfigFromDatatableColumn = async (column: DatatableColumn) => { + const indexPattern = await getIndexPatternFromDatatableColumn(column); + + if (!indexPattern) return; + + const aggConfigs = await createAggConfigs(indexPattern, [column.meta.sourceParams as any]); + return aggConfigs.aggs[0]; + }; + + const isFilterableAggDatatableColumn = (column: DatatableColumn) => { + if (column.meta.source !== 'esaggs') { + return false; + } + const aggType = (aggTypesStart.get(column.meta.sourceParams?.type as string) as any)( + {} + ) as IAggType; + return Boolean(aggType.createFilter); + }; + + return { + getIndexPattern: getIndexPatternFromDatatableColumn, + getAggConfig: getAggConfigFromDatatableColumn, + isFilterable: isFilterableAggDatatableColumn, + }; +}; diff --git a/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts b/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts deleted file mode 100644 index 2db3694884e2..000000000000 --- a/src/plugins/data/common/search/expressions/esaggs/build_tabular_inspector_data.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { set } from '@elastic/safer-lodash-set'; -import { - FormattedData, - TabularData, - TabularDataValue, -} from '../../../../../../plugins/inspector/common'; -import { Filter } from '../../../es_query'; -import { FormatFactory } from '../../../field_formats/utils'; -import { TabbedTable } from '../../tabify'; -import { createFilter } from './create_filter'; - -/** - * Type borrowed from the client-side FilterManager['addFilters']. - * - * We need to use a custom type to make this isomorphic since FilterManager - * doesn't exist on the server. - * - * @internal - */ -export type AddFilters = (filters: Filter[] | Filter, pinFilterStatus?: boolean) => void; - -/** - * This function builds tabular data from the response and attaches it to the - * inspector. It will only be called when the data view in the inspector is opened. - * - * @internal - */ -export async function buildTabularInspectorData( - table: TabbedTable, - { - addFilters, - deserializeFieldFormat, - }: { - addFilters?: AddFilters; - deserializeFieldFormat: FormatFactory; - } -): Promise { - const aggConfigs = table.columns.map((column) => column.aggConfig); - const rows = table.rows.map((row) => { - return table.columns.reduce>((prev, cur, colIndex) => { - const value = row[cur.id]; - - let format = cur.aggConfig.toSerializedFieldFormat(); - if (Object.keys(format).length < 1) { - // If no format exists, fall back to string as a default - format = { id: 'string' }; - } - const fieldFormatter = deserializeFieldFormat(format); - - prev[`col-${colIndex}-${cur.aggConfig.id}`] = new FormattedData( - value, - fieldFormatter.convert(value) - ); - return prev; - }, {}); - }); - - const columns = table.columns.map((col, colIndex) => { - const field = col.aggConfig.getField(); - const isCellContentFilterable = col.aggConfig.isFilterable() && (!field || field.filterable); - return { - name: col.name, - field: `col-${colIndex}-${col.aggConfig.id}`, - filter: - addFilters && - isCellContentFilterable && - ((value: TabularDataValue) => { - const rowIndex = rows.findIndex( - (row) => row[`col-${colIndex}-${col.aggConfig.id}`].raw === value.raw - ); - const filter = createFilter(aggConfigs, table, colIndex, rowIndex, value.raw); - - if (filter) { - addFilters(filter); - } - }), - filterOut: - addFilters && - isCellContentFilterable && - ((value: TabularDataValue) => { - const rowIndex = rows.findIndex( - (row) => row[`col-${colIndex}-${col.aggConfig.id}`].raw === value.raw - ); - const filter = createFilter(aggConfigs, table, colIndex, rowIndex, value.raw); - - if (filter) { - const notOther = value.raw !== '__other__'; - const notMissing = value.raw !== '__missing__'; - if (Array.isArray(filter)) { - filter.forEach((f) => set(f, 'meta.negate', notOther && notMissing)); - } else { - set(filter, 'meta.negate', notOther && notMissing); - } - addFilters(filter); - } - }), - }; - }); - - return { columns, rows }; -} diff --git a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts index 6c53a8a09274..2274fcfd6b8d 100644 --- a/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts +++ b/src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts @@ -34,7 +34,6 @@ import { AggsStart, AggExpressionType } from '../../aggs'; import { ISearchStartSearchSource } from '../../search_source'; import { KibanaContext } from '../kibana_context_type'; -import { AddFilters } from './build_tabular_inspector_data'; import { handleRequest, RequestHandlerParams } from './request_handler'; const name = 'esaggs'; @@ -59,7 +58,6 @@ export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition< /** @internal */ export interface EsaggsStartDependencies { - addFilters?: AddFilters; aggs: AggsStart; deserializeFieldFormat: FormatFactory; indexPatterns: IndexPatternsContract; diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts index aba498f720ec..78d169e8529c 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts @@ -39,7 +39,6 @@ describe('esaggs expression function - public', () => { jest.clearAllMocks(); mockParams = { abortSignal: (jest.fn() as unknown) as jest.Mocked, - addFilters: jest.fn(), aggs: ({ aggs: [{ type: { name: 'terms', postFlightRequest: jest.fn().mockResolvedValue({}) } }], setTimeRange: jest.fn(), diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts index 3c1745409ebc..e4385526ee6e 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts @@ -36,13 +36,9 @@ import { ISearchStartSearchSource } from '../../search_source'; import { tabifyAggResponse } from '../../tabify'; import { getRequestInspectorStats, getResponseInspectorStats } from '../utils'; -import type { AddFilters } from './build_tabular_inspector_data'; -import { buildTabularInspectorData } from './build_tabular_inspector_data'; - /** @internal */ export interface RequestHandlerParams { abortSignal?: AbortSignal; - addFilters?: AddFilters; aggs: IAggConfigs; deserializeFieldFormat: FormatFactory; filters?: Filter[]; @@ -59,7 +55,6 @@ export interface RequestHandlerParams { export const handleRequest = async ({ abortSignal, - addFilters, aggs, deserializeFieldFormat, filters, @@ -199,16 +194,5 @@ export const handleRequest = async ({ const tabifiedResponse = tabifyAggResponse(aggs, response, tabifyParams); - if (inspectorAdapters.data) { - inspectorAdapters.data.setTabularLoader( - () => - buildTabularInspectorData(tabifiedResponse, { - addFilters, - deserializeFieldFormat, - }), - { returnsFormattedValues: true } - ); - } - return tabifiedResponse; }; diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index 06b083e0ff3a..a09ab12f0c6f 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -7,7 +7,8 @@ "bfetch", "expressions", "uiActions", - "share" + "share", + "inspector" ], "optionalPlugins": ["usageCollection"], "extraPublicDirs": ["common"], diff --git a/src/plugins/data/public/index.scss b/src/plugins/data/public/index.scss index a51fde079f10..467efa98934e 100644 --- a/src/plugins/data/public/index.scss +++ b/src/plugins/data/public/index.scss @@ -1 +1,2 @@ @import './ui/index'; +@import './utils/table_inspector_view/index'; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 458024151c58..eb3a053b78a2 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -70,6 +70,7 @@ import { import { SavedObjectsClientPublicToCommon } from './index_patterns'; import { getIndexPatternLoad } from './index_patterns/expressions'; import { UsageCollectionSetup } from '../../usage_collection/public'; +import { getTableViewDescription } from './utils/table_inspector_view'; declare module '../../ui_actions/public' { export interface ActionContextMapping { @@ -104,7 +105,7 @@ export class DataPublicPlugin public setup( core: CoreSetup, - { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies + { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies ): DataPublicPluginSetup { const startServices = createStartServicesGetter(core.getStartServices); @@ -141,6 +142,15 @@ export class DataPublicPlugin expressions, }); + inspector.registerView( + getTableViewDescription(() => ({ + uiActions: startServices().plugins.uiActions, + uiSettings: startServices().core.uiSettings, + fieldFormats: startServices().self.fieldFormats, + isFilterable: startServices().self.search.aggs.datatableUtilities.isFilterable, + })) + ); + return { autocomplete: this.autocomplete.setup(core, { timefilter: queryService.timefilter }), search: searchService, diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 373aa4dee53f..e5df6d860b40 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -20,6 +20,7 @@ import { CoreSetup } from 'src/core/public'; import { CoreSetup as CoreSetup_2 } from 'kibana/public'; import { CoreStart } from 'kibana/public'; import { CoreStart as CoreStart_2 } from 'src/core/public'; +import * as CSS from 'csstype'; import { Datatable as Datatable_2 } from 'src/plugins/expressions'; import { Datatable as Datatable_3 } from 'src/plugins/expressions/common'; import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions'; @@ -66,11 +67,12 @@ import { Plugin as Plugin_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_3 } from 'kibana/public'; import { PopoverAnchorPosition } from '@elastic/eui'; +import * as PropTypes from 'prop-types'; import { PublicContract } from '@kbn/utility-types'; import { PublicMethodsOf } from '@kbn/utility-types'; import { PublicUiSettingsParams } from 'src/core/server/types'; import React from 'react'; -import * as React_2 from 'react'; +import * as React_3 from 'react'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Reporter } from '@kbn/analytics'; import { RequestAdapter } from 'src/plugins/inspector/common'; @@ -1888,7 +1890,7 @@ export class Plugin implements Plugin_2); // (undocumented) - setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; + setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection, inspector }: DataSetupDependencies): DataPublicPluginSetup; // (undocumented) start(core: CoreStart_2, { uiActions }: DataStartDependencies): DataPublicPluginStart; // (undocumented) @@ -2560,7 +2562,7 @@ export const UI_SETTINGS: { // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:64:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts // src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:128:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts -// src/plugins/data/common/search/aggs/types.ts:145:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts +// src/plugins/data/common/search/aggs/types.ts:150:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts // src/plugins/data/common/search/search_source/search_source.ts:197:7 - (ae-forgotten-export) The symbol "SearchFieldValue" needs to be exported by the entry point index.d.ts // src/plugins/data/public/field_formats/field_formats_service.ts:67:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts index de747d234b44..bc4992384b0c 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts @@ -88,11 +88,12 @@ describe('AggsService - public', () => { describe('start()', () => { test('exposes proper contract', () => { const start = service.start(startDeps); - expect(Object.keys(start).length).toBe(4); + expect(Object.keys(start).length).toBe(5); expect(start).toHaveProperty('calculateAutoTimeExpression'); expect(start).toHaveProperty('getDateMetaByDatatableColumn'); expect(start).toHaveProperty('createAggConfigs'); expect(start).toHaveProperty('types'); + expect(start).toHaveProperty('datatableUtilities'); }); test('types registry returns initialized agg types', () => { diff --git a/src/plugins/data/public/search/aggs/aggs_service.ts b/src/plugins/data/public/search/aggs/aggs_service.ts index 85e0f604bb8b..7b5edac0280d 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.ts @@ -102,6 +102,7 @@ export class AggsService { const { calculateAutoTimeExpression, getDateMetaByDatatableColumn, + datatableUtilities, types, } = this.aggsCommonService.start({ getConfig: this.getConfig!, @@ -148,7 +149,8 @@ export class AggsService { return { calculateAutoTimeExpression, getDateMetaByDatatableColumn, - createAggConfigs: (indexPattern, configStates = [], schemas) => { + datatableUtilities, + createAggConfigs: (indexPattern, configStates = []) => { return new AggConfigs(indexPattern, configStates, { typesRegistry }); }, types: typesRegistry, diff --git a/src/plugins/data/public/search/aggs/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts index abc930f00b59..bc02b48d67f7 100644 --- a/src/plugins/data/public/search/aggs/mocks.ts +++ b/src/plugins/data/public/search/aggs/mocks.ts @@ -68,6 +68,11 @@ export const searchAggsSetupMock = (): AggsSetup => ({ export const searchAggsStartMock = (): AggsStart => ({ calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), getDateMetaByDatatableColumn: jest.fn(), + datatableUtilities: { + isFilterable: jest.fn(), + getAggConfig: jest.fn(), + getIndexPattern: jest.fn(), + }, createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), diff --git a/src/plugins/data/public/search/expressions/esaggs.test.ts b/src/plugins/data/public/search/expressions/esaggs.test.ts index 10ed22c86118..abb95ed05b12 100644 --- a/src/plugins/data/public/search/expressions/esaggs.test.ts +++ b/src/plugins/data/public/search/expressions/esaggs.test.ts @@ -72,7 +72,6 @@ describe('esaggs expression function - public', () => { types: {}, }; startDependencies = { - addFilters: jest.fn(), aggs: ({ createAggConfigs: jest.fn().mockReturnValue({ foo: 'bar' }), } as unknown) as jest.Mocked, @@ -113,7 +112,6 @@ describe('esaggs expression function - public', () => { expect(handleEsaggsRequest).toHaveBeenCalledWith(null, args, { abortSignal: mockHandlers.abortSignal, - addFilters: startDependencies.addFilters, aggs: { foo: 'bar' }, deserializeFieldFormat: startDependencies.deserializeFieldFormat, filters: undefined, diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index 4a078bf9b2e5..d8d90ea464a7 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -49,7 +49,6 @@ export function getFunctionDefinition({ ...getEsaggsMeta(), async fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId }) { const { - addFilters, aggs, deserializeFieldFormat, indexPatterns, @@ -64,7 +63,6 @@ export function getFunctionDefinition({ return await handleEsaggsRequest(input, args, { abortSignal: (abortSignal as unknown) as AbortSignal, - addFilters, aggs: aggConfigs, deserializeFieldFormat, filters: get(input, 'filters', undefined), @@ -104,9 +102,8 @@ export function getEsaggs({ return getFunctionDefinition({ getStartDependencies: async () => { const [, , self] = await getStartServices(); - const { fieldFormats, indexPatterns, query, search } = self; + const { fieldFormats, indexPatterns, search } = self; return { - addFilters: query.filterManager.addFilters.bind(query.filterManager), aggs: search.aggs, deserializeFieldFormat: fieldFormats.deserialize.bind(fieldFormats), indexPatterns, diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 4082fbe55094..c7b66acfc6c7 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -31,6 +31,7 @@ import { QuerySetup, QueryStart } from './query'; import { IndexPatternsContract } from './index_patterns'; import { IndexPatternSelectProps, StatefulSearchBarProps } from './ui'; import { UsageCollectionSetup } from '../../usage_collection/public'; +import { Setup as InspectorSetup } from '../../inspector/public'; export interface DataPublicPluginEnhancements { search: SearchEnhancements; @@ -40,6 +41,7 @@ export interface DataSetupDependencies { bfetch: BfetchPublicSetup; expressions: ExpressionsSetup; uiActions: UiActionsSetup; + inspector: InspectorSetup; usageCollection?: UsageCollectionSetup; } diff --git a/src/plugins/inspector/public/views/data/_data_table.scss b/src/plugins/data/public/utils/table_inspector_view/_data_table.scss similarity index 100% rename from src/plugins/inspector/public/views/data/_data_table.scss rename to src/plugins/data/public/utils/table_inspector_view/_data_table.scss diff --git a/src/plugins/inspector/public/views/data/_index.scss b/src/plugins/data/public/utils/table_inspector_view/_index.scss similarity index 100% rename from src/plugins/inspector/public/views/data/_index.scss rename to src/plugins/data/public/utils/table_inspector_view/_index.scss diff --git a/src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap similarity index 68% rename from src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap rename to src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap index ec68b307734e..4320fc186783 100644 --- a/src/plugins/inspector/public/views/data/components/__snapshots__/data_view.test.tsx.snap +++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap @@ -1,17 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Inspector Data View component should render empty state 1`] = ` -

@@ -272,7 +159,7 @@ exports[`Inspector Data View component should render empty state 1`] = `

@@ -295,7 +182,7 @@ exports[`Inspector Data View component should render empty state 1`] = ` > No data available @@ -316,7 +203,7 @@ exports[`Inspector Data View component should render empty state 1`] = `

The element did not provide any data. @@ -329,7 +216,7 @@ exports[`Inspector Data View component should render empty state 1`] = ` - + `; exports[`Inspector Data View component should render loading state 1`] = ` @@ -442,6 +329,20 @@ exports[`Inspector Data View component should render loading state 1`] = ` } } > +

loading
diff --git a/src/plugins/inspector/public/views/data/components/data_table.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx similarity index 57% rename from src/plugins/inspector/public/views/data/components/data_table.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx index 69be069272f7..f4d1a8988da7 100644 --- a/src/plugins/inspector/public/views/data/components/data_table.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx @@ -35,8 +35,10 @@ import { i18n } from '@kbn/i18n'; import { DataDownloadOptions } from './download_options'; import { DataViewRow, DataViewColumn } from '../types'; -import { TabularData } from '../../../../common/adapters/data/types'; import { IUiSettingsClient } from '../../../../../../core/public'; +import { Datatable, DatatableColumn } from '../../../../../expressions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { UiActionsStart } from '../../../../../ui_actions/public'; interface DataTableFormatState { columns: DataViewColumn[]; @@ -44,10 +46,21 @@ interface DataTableFormatState { } interface DataTableFormatProps { - data: TabularData; + data: Datatable; exportTitle: string; uiSettings: IUiSettingsClient; - isFormatted?: boolean; + fieldFormats: FieldFormatsStart; + uiActions: UiActionsStart; + isFilterable: (column: DatatableColumn) => boolean; +} + +interface RenderCellArguments { + table: Datatable; + columnIndex: number; + rowIndex: number; + formattedValue: string; + uiActions: UiActionsStart; + isFilterable: boolean; } export class DataTableFormat extends Component { @@ -55,25 +68,35 @@ export class DataTableFormat extends Component - {isFormatted ? value.formatted : value} + {formattedValue} - {dataColumn.filter && ( + {isFilterable && ( } @@ -81,23 +104,29 @@ export class DataTableFormat extends Component dataColumn.filter(value)} + onClick={() => { + const value = table.rows[rowIndex][column.id]; + const eventData = { table, column: columnIndex, row: rowIndex, value }; + uiActions.executeTriggerActions('VALUE_CLICK_TRIGGER', { + data: { data: [eventData] }, + }); + }} /> )} - {dataColumn.filterOut && ( + {isFilterable && ( } @@ -105,12 +134,21 @@ export class DataTableFormat extends Component dataColumn.filterOut(value)} + onClick={() => { + const value = table.rows[rowIndex][column.id]; + const eventData = { table, column: columnIndex, row: rowIndex, value }; + uiActions.executeTriggerActions('VALUE_CLICK_TRIGGER', { + data: { data: [eventData], negate: true }, + }); + }} /> @@ -121,7 +159,12 @@ export class DataTableFormat extends Component ({ - name: dataColumn.name, - field: dataColumn.field, - sortable: isFormatted ? (row: DataViewRow) => row[dataColumn.field].raw : true, - render: (value: any) => DataTableFormat.renderCell(dataColumn, value, isFormatted), - })); + const columns = data.columns.map((dataColumn: any, index: number) => { + const formatParams = { id: 'string', ...dataColumn.meta.params }; + const fieldFormatter = fieldFormats.deserialize(formatParams); + const filterable = isFilterable(dataColumn); + return { + originalColumn: () => dataColumn, + name: dataColumn.name, + field: dataColumn.id, + sortable: true, + render: (value: any) => { + const formattedValue = fieldFormatter.convert(value); + const rowIndex = data.rows.findIndex((row) => row[dataColumn.id] === value) || 0; + + return DataTableFormat.renderCell({ + table: data, + columnIndex: index, + rowIndex, + formattedValue, + uiActions, + isFilterable: filterable, + }); + }, + }; + }); return { columns, rows: data.rows }; } @@ -152,12 +213,12 @@ export class DataTableFormat extends Component diff --git a/src/plugins/inspector/public/views/data/components/data_view.test.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx similarity index 77% rename from src/plugins/inspector/public/views/data/components/data_view.test.tsx rename to src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx index 82bec5ee3fe8..975a91548d79 100644 --- a/src/plugins/inspector/public/views/data/components/data_view.test.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx @@ -18,11 +18,11 @@ */ import React, { Suspense } from 'react'; -import { getDataViewDescription } from '../index'; -import { DataAdapter } from '../../../../common/adapters/data'; +import { getTableViewDescription } from '../index'; import { mountWithIntl } from '@kbn/test/jest'; +import { TablesAdapter } from '../../../../../expressions/common'; -jest.mock('../lib/export_csv', () => ({ +jest.mock('./export_csv', () => ({ exportAsCsv: jest.fn(), })); @@ -30,13 +30,18 @@ describe('Inspector Data View', () => { let DataView: any; beforeEach(() => { - DataView = getDataViewDescription(); + DataView = getTableViewDescription(() => ({ + uiActions: {} as any, + uiSettings: {} as any, + fieldFormats: {} as any, + isFilterable: jest.fn(), + })); }); it('should only show if data adapter is present', () => { - const adapter = new DataAdapter(); + const adapter = new TablesAdapter(); - expect(DataView.shouldShow({ data: adapter })).toBe(true); + expect(DataView.shouldShow({ tables: adapter })).toBe(true); expect(DataView.shouldShow({})).toBe(false); }); @@ -44,7 +49,7 @@ describe('Inspector Data View', () => { let adapters: any; beforeEach(() => { - adapters = { data: new DataAdapter() }; + adapters = { tables: new TablesAdapter() }; }); it('should render loading state', () => { @@ -60,9 +65,7 @@ describe('Inspector Data View', () => { it('should render empty state', async () => { const component = mountWithIntl(); // eslint-disable-line react/jsx-pascal-case - const tabularLoader = Promise.resolve(null); - adapters.data.setTabularLoader(() => tabularLoader); - await tabularLoader; + adapters.tables.logDatatable({ columns: [{ id: '1' }], rows: [{ '1': 123 }] }); // After the loader has resolved we'll still need one update, to "flush" the state changes component.update(); expect(component).toMatchSnapshot(); diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx new file mode 100644 index 000000000000..97dca45d742c --- /dev/null +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.tsx @@ -0,0 +1,137 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { DataTableFormat } from './data_table'; +import { IUiSettingsClient } from '../../../../../../core/public'; +import { InspectorViewProps, Adapters } from '../../../../../inspector/public'; +import { UiActionsStart } from '../../../../../ui_actions/public'; +import { FieldFormatsStart } from '../../../field_formats'; +import { TablesAdapter, Datatable, DatatableColumn } from '../../../../../expressions/public'; + +interface DataViewComponentState { + datatable: Datatable; + adapters: Adapters; +} + +interface DataViewComponentProps extends InspectorViewProps { + uiSettings: IUiSettingsClient; + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + isFilterable: (column: DatatableColumn) => boolean; +} + +class DataViewComponent extends Component { + static propTypes = { + adapters: PropTypes.object.isRequired, + title: PropTypes.string.isRequired, + uiSettings: PropTypes.object, + uiActions: PropTypes.object.isRequired, + fieldFormats: PropTypes.object.isRequired, + isFilterable: PropTypes.func.isRequired, + }; + + state = {} as DataViewComponentState; + + static getDerivedStateFromProps( + nextProps: Readonly, + state: DataViewComponentState + ) { + if (state && nextProps.adapters === state.adapters) { + return null; + } + + const { tables } = nextProps.adapters.tables; + const keys = Object.keys(tables); + const datatable = keys.length ? tables[keys[0]] : undefined; + + return { + adapters: nextProps.adapters, + datatable, + }; + } + + onUpdateData = (tables: TablesAdapter['tables']) => { + const keys = Object.keys(tables); + const datatable = keys.length ? tables[keys[0]] : undefined; + + if (datatable) { + this.setState({ + datatable, + }); + } + }; + + componentDidMount() { + this.props.adapters.tables!.on('change', this.onUpdateData); + } + + componentWillUnmount() { + this.props.adapters.tables!.removeListener('change', this.onUpdateData); + } + + static renderNoData() { + return ( + + +

- - + + - + - + {!isRumAgentName(agentName) && ( - + )} - + @@ -89,11 +103,15 @@ export function ServiceOverview({ - - + + - + + {item.type === 'service' ? ( @@ -190,9 +190,9 @@ export function ServiceOverviewDependenciesTable({ serviceName }: Props) { })); return ( - + - +

diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx index 91bcc76f2b02..a4c0e1ce005c 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_errors_table/index.tsx @@ -4,26 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ import { + EuiBasicTable, EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem, EuiTitle, - EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; -import styled from 'styled-components'; -import { EuiBasicTable } from '@elastic/eui'; import { asInteger } from '../../../../../common/utils/formatters'; -import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { callApmApi } from '../../../../services/rest/createCallApmApi'; -import { px, truncate, unit } from '../../../../style/variables'; +import { px, unit } from '../../../../style/variables'; import { SparkPlot } from '../../../shared/charts/spark_plot'; import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink'; import { ErrorOverviewLink } from '../../../shared/Links/apm/ErrorOverviewLink'; import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper'; import { TimestampTooltip } from '../../../shared/TimestampTooltip'; +import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; import { ServiceOverviewTableContainer } from '../service_overview_table_container'; import { TableLinkFlexItem } from '../table_link_flex_item'; @@ -50,18 +49,6 @@ const DEFAULT_SORT = { field: 'occurrences' as const, }; -const ErrorDetailLinkWrapper = styled.div` - width: 100%; - .euiToolTipAnchor { - width: 100% !important; - } -`; - -const StyledErrorDetailLink = styled(ErrorDetailLink)` - display: block; - ${truncate('100%')} -`; - export function ServiceOverviewErrorsTable({ serviceName }: Props) { const { urlParams: { start, end }, @@ -87,16 +74,17 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { }), render: (_, { name, group_id: errorGroupId }) => { return ( - - - {name} - - - + + } + /> ); }, }, @@ -202,9 +190,9 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) { } = data; return ( - + - +

diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx index c9b480188316..51a4ef649a3b 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx @@ -236,7 +236,7 @@ export function ServiceOverviewInstancesTable({ serviceName }: Props) { status === FETCH_STATUS.LOADING || status === FETCH_STATUS.PENDING; return ( - +

diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx index e5113cebd3dc..76db81a70550 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_table_container.tsx @@ -4,24 +4,33 @@ * you may not use this file except in compliance with the Elastic License. */ +import React, { ReactNode } from 'react'; import styled from 'styled-components'; +import { useShouldUseMobileLayout } from './use_should_use_mobile_layout'; /** * The height for a table on the overview page. Is the height of a 5-row basic * table. */ -const tableHeight = 298; +const tableHeight = 282; /** * A container for the table. Sets height and flex properties on the EUI Basic * Table contained within and the first child div of that. This makes it so the * pagination controls always stay fixed at the bottom in the same position. * + * Only do this when we're at a non-mobile breakpoint. + * * Hide the empty message when we don't yet have any items and are still loading. */ -export const ServiceOverviewTableContainer = styled.div<{ +const ServiceOverviewTableContainerDiv = styled.div<{ isEmptyAndLoading: boolean; + shouldUseMobileLayout: boolean; }>` + ${({ shouldUseMobileLayout }) => + shouldUseMobileLayout + ? '' + : ` height: ${tableHeight}px; display: flex; flex-direction: column; @@ -34,10 +43,29 @@ export const ServiceOverviewTableContainer = styled.div<{ > :first-child { flex-grow: 1; } - } + `} .euiTableRowCell { visibility: ${({ isEmptyAndLoading }) => isEmptyAndLoading ? 'hidden' : 'visible'}; } `; + +export function ServiceOverviewTableContainer({ + children, + isEmptyAndLoading, +}: { + children?: ReactNode; + isEmptyAndLoading: boolean; +}) { + const shouldUseMobileLayout = useShouldUseMobileLayout(); + + return ( + + {children} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx index e50af6f53c72..b464fd002644 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_transactions_table/index.tsx @@ -5,6 +5,7 @@ */ import { + EuiBasicTable, EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem, @@ -12,31 +13,29 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; -import styled from 'styled-components'; -import { EuiToolTip } from '@elastic/eui'; import { ValuesType } from 'utility-types'; -import { EuiBasicTable } from '@elastic/eui'; -import { useLatencyAggregationType } from '../../../../hooks/use_latency_Aggregation_type'; import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types'; import { asDuration, asPercent, asTransactionRate, } from '../../../../../common/utils/formatters'; -import { px, truncate, unit } from '../../../../style/variables'; -import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { useLatencyAggregationType } from '../../../../hooks/use_latency_Aggregation_type'; import { APIReturnType, callApmApi, } from '../../../../services/rest/createCallApmApi'; +import { px, unit } from '../../../../style/variables'; +import { SparkPlot } from '../../../shared/charts/spark_plot'; +import { ImpactBar } from '../../../shared/ImpactBar'; import { TransactionDetailLink } from '../../../shared/Links/apm/TransactionDetailLink'; import { TransactionOverviewLink } from '../../../shared/Links/apm/TransactionOverviewLink'; import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper'; -import { TableLinkFlexItem } from '../table_link_flex_item'; -import { SparkPlot } from '../../../shared/charts/spark_plot'; -import { ImpactBar } from '../../../shared/ImpactBar'; +import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip'; import { ServiceOverviewTableContainer } from '../service_overview_table_container'; +import { TableLinkFlexItem } from '../table_link_flex_item'; type ServiceTransactionGroupItem = ValuesType< APIReturnType<'GET /api/apm/services/{serviceName}/transactions/groups/overview'>['transactionGroups'] @@ -55,18 +54,6 @@ const DEFAULT_SORT = { field: 'impact' as const, }; -const TransactionGroupLinkWrapper = styled.div` - width: 100%; - .euiToolTipAnchor { - width: 100% !important; - } -`; - -const StyledTransactionDetailLink = styled(TransactionDetailLink)` - display: block; - ${truncate('100%')} -`; - function getLatencyAggregationTypeLabel( latencyAggregationType?: LatencyAggregationType ) { @@ -189,17 +176,18 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { ), render: (_, { name, transactionType }) => { return ( - - - {name} - - - + + } + /> ); }, }, @@ -274,9 +262,9 @@ export function ServiceOverviewTransactionsTable({ serviceName }: Props) { ]; return ( - + - +

diff --git a/x-pack/plugins/apm/public/components/app/service_overview/use_should_use_mobile_layout.ts b/x-pack/plugins/apm/public/components/app/service_overview/use_should_use_mobile_layout.ts new file mode 100644 index 000000000000..bd844a3f2e69 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/service_overview/use_should_use_mobile_layout.ts @@ -0,0 +1,27 @@ +/* + * 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 { isWithinMaxBreakpoint } from '@elastic/eui'; +import { useEffect, useState } from 'react'; + +export function useShouldUseMobileLayout() { + const [shouldUseMobileLayout, setShouldUseMobileLayout] = useState( + isWithinMaxBreakpoint(window.innerWidth, 'm') + ); + + useEffect(() => { + const resizeHandler = () => { + setShouldUseMobileLayout(isWithinMaxBreakpoint(window.innerWidth, 'm')); + }; + window.addEventListener('resize', resizeHandler); + + return () => { + window.removeEventListener('resize', resizeHandler); + }; + }); + + return shouldUseMobileLayout; +} diff --git a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/index.tsx index be7c6babe8e0..475877c0edad 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/index.tsx @@ -48,11 +48,11 @@ export function LatencyChart({ height }: Props) { const latencyFormatter = getDurationFormatter(latencyMaxY); return ( - + - +

diff --git a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx index e620acd56aad..7b5ff4fd56e9 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/spark_plot/index.tsx @@ -58,7 +58,7 @@ export function SparkPlot({ const colorValue = theme.eui[color]; return ( - + {!series || series.every((point) => point.y === null) ? ( From f0234cbb9e4fd35840b67d35f0b0b4c87cc09e8a Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 17 Dec 2020 10:22:48 -0500 Subject: [PATCH 36/38] [Fleet] Bug fixes to Policies list under Integrations section (#86183) * Fix table cell not having tooltips * Show loading message while data is being retrieved --- .../screens/detail/package_policies_panel.tsx | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx index 4061b86f1f74..4d8cb5a16034 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx @@ -13,7 +13,7 @@ import { EuiTableFieldDataColumnType, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedRelative } from '@kbn/i18n/react'; +import { FormattedRelative, FormattedMessage } from '@kbn/i18n/react'; import { useGetPackageInstallStatus } from '../../hooks'; import { InstallStatus } from '../../../../types'; import { useLink } from '../../../../hooks'; @@ -37,6 +37,7 @@ const IntegrationDetailsLink = memo<{ + {description} + + ); + }, }, { field: 'packagePolicy.policy_id', @@ -172,7 +180,7 @@ export const PackagePoliciesPanel = ({ name, version }: PackagePoliciesPanelProp truncateText: true, render(updatedAt: PackagePolicyAndAgentPolicy['packagePolicy']['updated_at']) { return ( - + ); @@ -182,6 +190,24 @@ export const PackagePoliciesPanel = ({ name, version }: PackagePoliciesPanelProp [] ); + const noItemsMessage = useMemo(() => { + return isLoading ? ( + + ) : undefined; + }, [isLoading]); + + const tablePagination = useMemo(() => { + return { + pageIndex: pagination.currentPage - 1, + pageSize: pagination.pageSize, + totalItemCount: data?.total ?? 0, + pageSizeOptions, + }; + }, [data?.total, pageSizeOptions, pagination.currentPage, pagination.pageSize]); + // if they arrive at this page and the package is not installed, send them to overview // this happens if they arrive with a direct url or they uninstall while on this tab if (packageInstallStatus.status !== InstallStatus.installed) { @@ -192,15 +218,11 @@ export const PackagePoliciesPanel = ({ name, version }: PackagePoliciesPanelProp ); }; From d18fca3b8265bc2276800aec9b322f378abfeadb Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 17 Dec 2020 09:33:21 -0600 Subject: [PATCH 37/38] skip 'dashboard title is case insensitive' #86226 --- test/functional/apps/dashboard/dashboard_listing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/apps/dashboard/dashboard_listing.js b/test/functional/apps/dashboard/dashboard_listing.js index 175605bfa825..45c4d2bffbfa 100644 --- a/test/functional/apps/dashboard/dashboard_listing.js +++ b/test/functional/apps/dashboard/dashboard_listing.js @@ -134,7 +134,7 @@ export default function ({ getService, getPageObjects }) { expect(onDashboardLandingPage).to.equal(false); }); - it('title match is case insensitive', async function () { + it.skip('title match is case insensitive', async function () { await PageObjects.dashboard.gotoDashboardLandingPage(); const currentUrl = await browser.getCurrentUrl(); const newUrl = currentUrl + '&title=two%20words'; From 52f54e604387e6413a9b538ca082cabb388ce2ce Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 17 Dec 2020 09:54:18 -0600 Subject: [PATCH 38/38] skip saved objects migrations clone already existed. #86068 --- .../migrationsv2/integration_tests/actions.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts index 8947a5ec2171..8b25c8f6d3fc 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/actions.test.ts @@ -226,7 +226,7 @@ describe('migration actions', () => { } `); }); - it('resolves right after waiting for index status to be green if clone target already existed', async () => { + it.skip('resolves right after waiting for index status to be green if clone target already existed', async () => { // Create a yellow index await client.indices.create({ index: 'yellow_then_green_index',